Installation:
composer require bepsvpt/secure-headers
Laravel auto-discovers the package if using Laravel 5.5+. For older versions, add to config/app.php under providers:
Bepsvpt\SecureHeaders\SecureHeadersServiceProvider::class,
Publish Config (optional but recommended):
php artisan vendor:publish --provider="Bepsvpt\SecureHeaders\SecureHeadersServiceProvider" --tag="config"
This generates config/secure-headers.php.
First Use Case:
Default Configuration:
The package ships with sensible defaults (e.g., Content-Security-Policy, X-Frame-Options, X-XSS-Protection). Modify config/secure-headers.php to adjust:
'headers' => [
'Content-Security-Policy' => [
'default-src' => "'self'",
// Custom directives...
],
'X-Frame-Options' => 'DENY',
],
Dynamic Headers: Override headers per route or request using middleware:
// app/Http/Middleware/SetCustomHeaders.php
public function handle($request, Closure $next) {
$response = $next($request);
$response->headers->set('X-Custom-Header', 'dynamic-value');
return $response;
}
Conditional Application: Disable headers for specific routes (e.g., APIs or admin panels):
// config/secure-headers.php
'except' => [
'api/*',
'admin/*',
],
Environment-Specific Rules: Use Laravel’s environment config to toggle headers:
// config/secure-headers.php
'enabled' => env('APP_ENV') !== 'local',
Integration with Middleware: Extend the package’s middleware to add logic:
// app/Http/Middleware/ApplySecureHeaders.php
use Bepsvpt\SecureHeaders\SecureHeadersMiddleware;
class ApplySecureHeaders extends SecureHeadersMiddleware {
protected function getHeaders() {
$headers = parent::getHeaders();
$headers['X-My-Custom-Header'] = 'value';
return $headers;
}
}
CSP (Content Security Policy):
Start with a restrictive policy and gradually loosen directives (e.g., script-src 'self' → script-src 'self' https://cdn.example.com).
Test using Report-Only mode:
'Content-Security-Policy' => [
'report-uri' => '/csp-report-endpoint',
'default-src' => "'self'",
],
Performance:
Cache headers for static assets (e.g., Cache-Control) separately from security headers.
Testing:
Use Laravel’s Http::fake() to assert headers in tests:
$response = $this->get('/');
$response->assertHeader('X-Frame-Options', 'DENY');
CSP Misconfiguration:
Report-Only mode first, then monitor reports via /csp-report-endpoint.Header Conflicts:
App\Http\Middleware\TrustProxies) may override headers.SecureHeadersMiddleware runs last in your middleware stack.Local Development:
HSTS or X-Frame-Options can break local workflows (e.g., iframes, mixed content).local environment:
'enabled' => env('APP_ENV') !== 'local',
Non-HTTP Responses:
except or manually set headers in responses.Caching Headers:
Cache-Control may conflict with Laravel’s caching logic.Verify Headers:
Use dd($response->headers->all()) or browser dev tools to inspect headers.
Log Headers: Add debug logging in middleware:
\Log::debug('Secure Headers Applied:', $this->getHeaders());
Common Issues:
SecureHeadersServiceProvider is registered.SecureHeadersMiddleware.Custom Headers:
Extend the SecureHeadersMiddleware class to add dynamic headers:
protected function getHeaders() {
$headers = parent::getHeaders();
$headers['X-Dynamic-Header'] = $this->request->ip();
return $headers;
}
Header Factories: Create a factory for complex headers (e.g., CSP with environment variables):
// app/Providers/SecureHeadersServiceProvider.php
public function boot() {
$this->app->bind(\Bepsvpt\SecureHeaders\HeaderFactory::class, function () {
return new CustomHeaderFactory();
});
}
Event-Based Headers:
Listen to Laravel events (e.g., Illuminate\Http\Events\RequestHandled) to modify headers dynamically:
Event::listen(RequestHandled::class, function ($request) {
if ($request->routeIs('admin.dashboard')) {
$request->getOriginalRequest()->headers->set('X-Admin-Access', 'true');
}
});
Header Validation:
Validate headers in config/secure-headers.php using Laravel’s validation rules:
'headers' => [
'Content-Security-Policy' => [
'default-src' => ['required', 'string'],
],
],
How can I help you explore Laravel packages today?