Browsers ignore 'unsafe-inline' when a nonce is present. Reverting to unsafe-inline only until all inline handlers are refactored. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
52 lines
1.9 KiB
PHP
52 lines
1.9 KiB
PHP
<?php
|
|
/**
|
|
* Security Headers Middleware
|
|
*
|
|
* Applies security-related HTTP headers to all responses.
|
|
*/
|
|
class SecurityHeadersMiddleware {
|
|
private static $nonce = null;
|
|
|
|
/**
|
|
* Generate or retrieve the CSP nonce for this request
|
|
*
|
|
* @return string The nonce value
|
|
*/
|
|
public static function getNonce() {
|
|
if (self::$nonce === null) {
|
|
self::$nonce = base64_encode(random_bytes(16));
|
|
}
|
|
return self::$nonce;
|
|
}
|
|
|
|
/**
|
|
* Apply security headers to the response
|
|
*/
|
|
public static function apply() {
|
|
$nonce = self::getNonce();
|
|
|
|
// Content Security Policy - restricts where resources can be loaded from
|
|
// Currently using 'unsafe-inline' for scripts due to legacy onclick handlers throughout views
|
|
// NOTE: Nonce infrastructure exists (getNonce method, nonce attributes in views) but is not
|
|
// enforced in CSP until all inline handlers are refactored to use addEventListener.
|
|
// TODO: Complete refactoring of inline handlers, then change to:
|
|
// script-src 'self' 'nonce-{$nonce}' (removing unsafe-inline)
|
|
header("Content-Security-Policy: default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'; img-src 'self' data:; font-src 'self'; connect-src 'self';");
|
|
|
|
// Prevent clickjacking by disallowing framing
|
|
header("X-Frame-Options: DENY");
|
|
|
|
// Prevent MIME type sniffing
|
|
header("X-Content-Type-Options: nosniff");
|
|
|
|
// Enable XSS filtering in older browsers
|
|
header("X-XSS-Protection: 1; mode=block");
|
|
|
|
// Control referrer information sent with requests
|
|
header("Referrer-Policy: strict-origin-when-cross-origin");
|
|
|
|
// Permissions Policy - disable unnecessary browser features
|
|
header("Permissions-Policy: geolocation=(), microphone=(), camera=()");
|
|
}
|
|
}
|