Back to Blog
Lesson 53 of the Advanced Laravel: Architecture, Scaling & Performance course
LaravelJune 28, 20263 min read

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.

LaravelSecurityWebCSPHTTP Headersphpbackend

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 to false in production.
  • http_only: Prevents JavaScript from accessing the cookie via document.cookie, mitigating the impact of XSS.
  • same_site: Controls cross-site request behavior. Set this to lax or strict to 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:

PHP
namespace 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

HeaderPurposePrimary Threat Prevented
Content-Security-PolicyDefines trusted content sourcesXSS, Data Injection
Strict-Transport-SecurityForces HTTPS connectionMan-in-the-Middle
X-Content-Type-OptionsDisables MIME-type sniffingDrive-by downloads
X-Frame-OptionsPrevents framingClickjacking

Hands-on Exercise

  1. Audit current headers: Use curl -I https://your-app.test to inspect your current headers. Note missing ones like Content-Security-Policy.
  2. Apply HSTS: Configure the Strict-Transport-Security header in your TrustProxies middleware to ensure browsers only connect via HTTPS for the next year.
  3. Implement CSP: Install a CSP package, define your domain's script and style sources, and deploy it in report-only mode first to ensure you don't break existing features.

Common Pitfalls

  • report-only neglect: Always deploy CSP in report-only mode first. Use a logging service or Sentry to monitor violations before switching to enforce.
  • Over-permissive unsafe-inline: Many developers add unsafe-inline to 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.com and marketing.saas.com), ensure your cookies are scoped correctly using the domain key in your session config, or risk session leakage.

Recap

We have moved beyond basic Laravel defaults by:

  1. Enforcing secure, http_only, and same_site flags on all cookies.
  2. Implementing a domain-specific CSP that restricts script and style sources.
  3. 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.

Similar Posts