philiprehberger/laravel-security-headers

Laravel middleware for comprehensive security headers including CSP with nonce support, HSTS, and Permissions-Policy.

Maintainers

Package info

github.com/philiprehberger/laravel-security-headers

pkg:composer/philiprehberger/laravel-security-headers

Statistics

Installs: 16

Dependents: 0

Suggesters: 0

Stars: 1

Open Issues: 0

v1.1.4 2026-03-17 21:36 UTC

This package is auto-updated.

Last update: 2026-03-17 21:39:02 UTC


README

Tests Latest Version on Packagist License

A Laravel middleware package that adds a comprehensive set of HTTP security headers to every response, including a per-request CSP nonce, HSTS, and Permissions-Policy.

Requirements

Dependency Version
PHP ^8.2
Laravel 11 or 12

Features

  • Per-request CSP nonce — generated automatically and shared with all Blade views
  • Content Security Policy built entirely from config arrays, no code changes required
  • Configurable HSTS with max_age and includeSubDomains
  • X-Content-Type-Options, X-Frame-Options, X-XSS-Protection, Referrer-Policy, Permissions-Policy
  • Vite dev-server auto-detection adds the HMR origin and WebSocket URLs to the CSP when APP_ENV=local
  • Any header can be suppressed by setting its config value to null
  • Laravel 11 and 12 support, PHP 8.2+

Installation

composer require philiprehberger/laravel-security-headers

Laravel auto-discovery registers the service provider automatically.

Publishing the Config

php artisan vendor:publish --tag=security-headers-config

This copies config/security-headers.php into your application's config/ directory.

Registering the Middleware

Laravel 11+ (bootstrap/app.php)

use PhilipRehberger\SecurityHeaders\SecurityHeaders;

->withMiddleware(function (Middleware $middleware) {
    $middleware->web(append: [
        SecurityHeaders::class,
    ]);
})

Laravel 10 and earlier (app/Http/Kernel.php)

protected $middlewareGroups = [
    'web' => [
        // ...
        \PhilipRehberger\SecurityHeaders\SecurityHeaders::class,
    ],
];

Using the CSP Nonce in Blade

The nonce is shared to every view under the variable name configured in csp.nonce_view_variable (default: cspNonce).

<script nonce="{{ $cspNonce }}">
    console.log('Inline script allowed by CSP nonce');
</script>

<style nonce="{{ $cspNonce }}">
    /* Inline styles allowed by CSP nonce */
</style>

Accessing the Nonce in PHP

$nonce = $request->attributes->get('csp_nonce');

Configuration Reference

// config/security-headers.php

return [

    'hsts' => [
        // Set SECURITY_HEADERS_HSTS=true in .env (only when fully on HTTPS)
        'enabled'            => env('SECURITY_HEADERS_HSTS', false),
        'max_age'            => 31536000,
        'include_subdomains' => true,
    ],

    'csp' => [
        'enabled'                 => true,
        'nonce_view_variable'     => 'cspNonce',
        'nonce_request_attribute' => 'csp_nonce',

        'unsafe_eval'  => true,   // include 'unsafe-eval' in script-src
        'unsafe_inline' => true,  // include 'unsafe-inline' in style-src

        // Extra sources merged into each directive
        'script_src'   => [],   // appended to: 'self' 'nonce-...' (+ 'unsafe-eval' if enabled)
        'style_src'    => [],   // appended to: 'self' (+ 'unsafe-inline' if enabled)
        'img_src'      => [],   // appended to: 'self' data: blob:
        'font_src'     => [],   // appended to: 'self' data:
        'connect_src'  => [],   // appended to: 'self'
        'frame_ancestors' => ["'self'"],
        'form_action'     => ["'self'"],
    ],

    // Set to null to omit the header entirely
    'x_content_type_options' => 'nosniff',
    'x_frame_options'        => 'SAMEORIGIN',
    'x_xss_protection'       => '1; mode=block',
    'referrer_policy'        => 'strict-origin-when-cross-origin',
    'permissions_policy'     => 'geolocation=(), camera=(), microphone=(), payment=()',

    'vite' => [
        'enabled'    => true,
        'dev_server' => 'http://127.0.0.1:5173',
    ],

];

Hardening the CSP

By default, 'unsafe-eval' is included in script-src and 'unsafe-inline' is included in style-src for broad compatibility. You can disable these for stricter security:

'csp' => [
    'unsafe_eval'   => false,  // removes 'unsafe-eval' from script-src
    'unsafe_inline' => false,  // removes 'unsafe-inline' from style-src
],

When unsafe_inline is disabled, all inline styles must use the CSP nonce. When unsafe_eval is disabled, eval() and related JavaScript features are blocked.

Hardcoded CSP Directives

The following directives are always included and cannot be changed via config:

Directive Value Purpose
default-src 'self' Fallback for all resource types
base-uri 'self' Prevents <base> tag hijacking
object-src 'none' Blocks Flash/Java embeds

Customization Examples

Allow an external CDN for scripts

'csp' => [
    'script_src' => ['https://cdn.jsdelivr.net'],
],

Allow external font providers

'csp' => [
    'font_src'  => ['https://fonts.bunny.net', 'https://fonts.gstatic.com'],
    'style_src' => ['https://fonts.bunny.net'],
],

Allow WebSocket connections to a production server

'csp' => [
    'connect_src' => ['wss://ws.example.com'],
],

Allow forms to post to a subdomain

'csp' => [
    'form_action' => ["'self'", 'https://portal.example.com'],
],

Enable HSTS in production via environment variable

SECURITY_HEADERS_HSTS=true

Remove a header you do not need

'x_xss_protection' => null,

API

Middleware

Class Description
SecurityHeaders Middleware that injects all configured security headers into each response and generates a per-request CSP nonce

Service Provider

Auto-discovered via Laravel's package discovery. Registers the middleware and publishes the config file.

Blade Variable

Variable Description
$cspNonce Per-request CSP nonce shared to all Blade views (name configurable via csp.nonce_view_variable)

Request Attribute

Attribute Description
csp_nonce Per-request CSP nonce accessible via $request->attributes->get('csp_nonce')

Development

composer install
vendor/bin/phpunit
vendor/bin/pint --test
vendor/bin/phpstan analyse

License

MIT