laravel-security-headers maintained by philiprehberger
Laravel Security Headers
Laravel middleware for comprehensive security headers including CSP with nonce support, 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_ageandincludeSubDomains 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