Advanced Security Header Configuration: CSP and Secure Cookies in Laravel
Learn how to harden your Laravel application by configuring advanced security headers, implementing a strict CSP, and enforcing secure cookie flags.
Previously in this course, we explored custom middleware development to handle request interception and performance optimization. In this lesson, we build upon that foundation by focusing on the browser-server contract: security headers.
While Laravel provides sensible defaults, production-grade SaaS platforms require a more proactive stance against browser-based vulnerabilities like Cross-Site Scripting (XSS), clickjacking, and session hijacking. We will harden our application by implementing a strict Content Security Policy (CSP) and enforcing strict cookie security.
The Defense-in-Depth Approach
Security headers are instructions sent by your server to the client's browser, dictating how it should handle your site's content and cookies. They are the first line of defense against client-side attacks.
Configuring Secure Cookie Flags
Cookie security is often overlooked until a session hijacking incident occurs. Every cookie in your application must explicitly define its scope and security constraints.
In your config/session.php and config/sanctum.php, ensure these flags are set:
secure: Ensures the cookie is only sent over HTTPS. Never set this tofalsein production.http_only: Prevents JavaScript from accessing the cookie viadocument.cookie, mitigating the impact of XSS.same_site: Controls cross-site request behavior. Set this tolaxorstrictto prevent CSRF.
PHP#6A9955">// config/session.php 'secure' => env('SESSION_SECURE_COOKIE', true), 'http_only' => true, 'same_site' => 'lax', #6A9955">// Use 'strict' if your app doesn't rely on cross-site navigation
Implementing a Robust Content Security Policy (CSP)
A Content Security Policy (CSP) tells the browser which sources of content (scripts, styles, images) are trusted. If an attacker manages to inject a malicious script, a properly configured CSP will block it from executing or reporting it to your telemetry endpoint.
Instead of writing raw headers, use a package like spatie/laravel-csp to define your policy in a fluent, object-oriented way.
Worked Example: Defining a Domain-Specific Policy
Create a dedicated policy class in app/Policies/Csp/SaaSProductionPolicy.php:
PHPnamespace App\Policies\Csp; use Spatie\Csp\Policies\Policy; use Spatie\Csp\Directive; use Spatie\Csp\Keyword; class SaaSProductionPolicy extends Policy { public function configure() { $this->addDirective(Directive::BASE, Keyword::SELF) ->addDirective(Directive::CONNECT, [Keyword::SELF, 'https:#6A9955">//api.stripe.com']) ->addDirective(Directive::DEFAULT, Keyword::SELF) ->addDirective(Directive::SCRIPT, [Keyword::SELF, 'https:#6A9955">//js.stripe.com']) ->addDirective(Directive::STYLE, [Keyword::SELF, 'https:#6A9955">//fonts.googleapis.com']) ->addDirective(Directive::IMG, [Keyword::SELF, 'data:', 'https:#6A9955">//res.cloudinary.com']); } }
Register this policy in your AppServiceProvider or via the csp.php config file. This setup ensures that only scripts from your own domain and Stripe are allowed, neutralizing most third-party script injection vectors.
Comparison of Security Headers
| Header | Purpose | Primary Threat Prevented |
|---|---|---|
Content-Security-Policy | Defines trusted content sources | XSS, Data Injection |
Strict-Transport-Security | Forces HTTPS connection | Man-in-the-Middle |
X-Content-Type-Options | Disables MIME-type sniffing | Drive-by downloads |
X-Frame-Options | Prevents framing | Clickjacking |
Hands-on Exercise
- Audit current headers: Use
curl -I https://your-app.testto inspect your current headers. Note missing ones likeContent-Security-Policy. - Apply HSTS: Configure the
Strict-Transport-Securityheader in yourTrustProxiesmiddleware to ensure browsers only connect via HTTPS for the next year. - Implement CSP: Install a CSP package, define your domain's script and style sources, and deploy it in
report-onlymode first to ensure you don't break existing features.
Common Pitfalls
report-onlyneglect: Always deploy CSP inreport-onlymode first. Use a logging service or Sentry to monitor violations before switching toenforce.- Over-permissive
unsafe-inline: Many developers addunsafe-inlineto their CSP to fix broken styles or scripts. This effectively disables the main benefit of CSP. Refactor your code to use nonce-based scripts instead. - Ignoring Subdomains: If your SaaS uses subdomains (e.g.,
app.saas.comandmarketing.saas.com), ensure your cookies are scoped correctly using thedomainkey in your session config, or risk session leakage.
Recap
We have moved beyond basic Laravel defaults by:
- Enforcing
secure,http_only, andsame_siteflags on all cookies. - Implementing a domain-specific CSP that restricts script and style sources.
- Understanding the role of various security headers in mitigating browser-based attacks like XSS and Clickjacking.
By hardening these headers, you ensure that your infrastructure is as resilient as your domain logic.
Up next: We will discuss Database Sharding Concepts and how to plan for data distribution as our SaaS platform scales.
Work with me

Laravel REST API Development
Clean, secure, well-documented Laravel REST APIs โ the backend engine for your app, mobile client, or SaaS. Built by an API specialist.

FilamentPHP Admin Panel & Dashboard Development
A powerful admin panel for your Laravel app โ built with FilamentPHP so you can manage everything without touching the database.