Dependency vulnerability scanning — composer audit
Concept
Security headers are HTTP response headers that instruct browsers to enable security features. They're a critical defense-in-depth layer that can prevent or mitigate XSS, clickjacking, MIME sniffing, and information leakage.
Key security headers:
-
Content-Security-Policy(CSP): The most powerful header. Defines allowed sources for scripts, styles, images, fonts, etc.default-src 'self'allows only same-origin resources.script-src 'self' https://cdn.example.com— only these script sources.nonce-{RANDOM}— allows specific inline scripts. Prevents XSS by blocking inline scripts and external script loading from attacker-controlled domains. -
Strict-Transport-Security(HSTS):max-age=31536000; includeSubDomains; preload— tells browsers to always use HTTPS. Prevents SSL stripping attacks.preloadsubmits the domain to browser preload lists. -
X-Content-Type-Options: nosniff: Prevents browsers from MIME-sniffing response content type — the browser must use the declaredContent-Type. -
X-Frame-Options: DENY|SAMEORIGIN: Prevents your page from being loaded in iframes — blocks clickjacking. Superseded by CSP'sframe-ancestorsdirective but still widely needed. -
Referrer-Policy: Controls what's in theRefererheader.strict-origin-when-cross-originis a good default — sends origin only for cross-site requests. -
Permissions-Policy: Formerly Feature-Policy. Controls which browser features the page can use (camera,microphone,geolocation).
Code Example
<?php
// Setting security headers in plain PHP
header("Content-Security-Policy: default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:; font-src 'self'");
header("Strict-Transport-Security: max-age=31536000; includeSubDomains; preload");
header("X-Content-Type-Options: nosniff");
header("X-Frame-Options: SAMEORIGIN");
header("Referrer-Policy: strict-origin-when-cross-origin");
header("Permissions-Policy: camera=(), microphone=(), geolocation=()");
// Remove information-leaking headers
header_remove("X-Powered-By"); // removes "PHP/8.4.0"
// Also set: expose_php = Off in php.ini
// Laravel — middleware for security headers
namespace App\Http\Middleware;
use Closure;
use Illuminate\Http\Request;
class SecurityHeaders
{
public function handle(Request $request, Closure $next): mixed
{
$response = $next($request);
$nonce = base64_encode(random_bytes(16)); // CSP nonce for inline scripts
$response->headers->set('Content-Security-Policy',
"default-src 'self'; script-src 'self' 'nonce-$nonce'; style-src 'self' 'unsafe-inline'"
);
$response->headers->set('Strict-Transport-Security', 'max-age=31536000; includeSubDomains');
$response->headers->set('X-Content-Type-Options', 'nosniff');
$response->headers->set('X-Frame-Options', 'SAMEORIGIN');
$response->headers->set('Referrer-Policy', 'strict-origin-when-cross-origin');
$response->headers->remove('X-Powered-By');
return $response;
}
}
// Nginx config — set security headers at web server level (preferred)
// add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;
// add_header X-Content-Type-Options "nosniff" always;
// add_header X-Frame-Options "SAMEORIGIN" always;
// add_header Referrer-Policy "strict-origin-when-cross-origin" always;
// Test your headers: securityheaders.com