1. php
  2. /security
  3. /security-headers

Security Headers in PHP

Introduction to Security Headers

Security headers are HTTP response headers that help protect web applications from various attacks by instructing browsers how to behave when handling content. They provide an additional layer of security by enabling built-in browser protections and preventing common attack vectors like XSS, clickjacking, and data injection.

Why Security Headers Matter

  1. Defense in Depth: Additional layer of security beyond application-level protections
  2. Browser-Level Protection: Leverage browser security features
  3. Compliance: Meet security standards and compliance requirements
  4. Attack Prevention: Mitigate common web vulnerabilities
  5. Zero-Cost Security: Easy to implement with significant security benefits

Essential Security Headers

X-Content-Type-Options

Prevents MIME type sniffing attacks by forcing browsers to respect declared content types.

<?php
// Prevent MIME type sniffing
header('X-Content-Type-Options: nosniff');

// Example usage in a file download
function secureFileDownload($filePath, $fileName, $mimeType) {
    header('X-Content-Type-Options: nosniff');
    header('Content-Type: ' . $mimeType);
    header('Content-Disposition: attachment; filename="' . $fileName . '"');
    header('Content-Length: ' . filesize($filePath));
    
    readfile($filePath);
}
?>

X-Frame-Options

Protects against clickjacking attacks by controlling whether the page can be embedded in frames.

<?php
// Deny all framing
header('X-Frame-Options: DENY');

// Allow framing only from same origin
header('X-Frame-Options: SAMEORIGIN');

// Allow framing from specific domain
header('X-Frame-Options: ALLOW-FROM https://trusted-domain.com');

// Dynamic frame options based on context
function setFrameOptions($context = 'default') {
    switch ($context) {
        case 'admin':
            header('X-Frame-Options: DENY');
            break;
        case 'embed':
            header('X-Frame-Options: SAMEORIGIN');
            break;
        default:
            header('X-Frame-Options: DENY');
    }
}
?>

Content Security Policy (CSP)

Powerful header that helps prevent XSS, data injection, and other code injection attacks.

<?php
class CSPBuilder {
    private $directives = [];
    
    public function addDirective($directive, $sources) {
        if (is_string($sources)) {
            $sources = [$sources];
        }
        $this->directives[$directive] = $sources;
        return $this;
    }
    
    public function defaultSrc($sources) {
        return $this->addDirective('default-src', $sources);
    }
    
    public function scriptSrc($sources) {
        return $this->addDirective('script-src', $sources);
    }
    
    public function styleSrc($sources) {
        return $this->addDirective('style-src', $sources);
    }
    
    public function imgSrc($sources) {
        return $this->addDirective('img-src', $sources);
    }
    
    public function connectSrc($sources) {
        return $this->addDirective('connect-src', $sources);
    }
    
    public function fontSrc($sources) {
        return $this->addDirective('font-src', $sources);
    }
    
    public function objectSrc($sources) {
        return $this->addDirective('object-src', $sources);
    }
    
    public function mediaSrc($sources) {
        return $this->addDirective('media-src', $sources);
    }
    
    public function frameSrc($sources) {
        return $this->addDirective('frame-src', $sources);
    }
    
    public function reportUri($uri) {
        return $this->addDirective('report-uri', $uri);
    }
    
    public function build() {
        $policy = [];
        foreach ($this->directives as $directive => $sources) {
            $policy[] = $directive . ' ' . implode(' ', $sources);
        }
        return implode('; ', $policy);
    }
    
    public function send() {
        header('Content-Security-Policy: ' . $this->build());
    }
    
    public function sendReportOnly() {
        header('Content-Security-Policy-Report-Only: ' . $this->build());
    }
}

// Usage examples
$csp = new CSPBuilder();

// Basic CSP for a typical web application
$csp->defaultSrc(["'self'"])
    ->scriptSrc(["'self'", "'unsafe-inline'", 'https://cdn.jsdelivr.net'])
    ->styleSrc(["'self'", "'unsafe-inline'", 'https://fonts.googleapis.com'])
    ->imgSrc(["'self'", 'data:', 'https:'])
    ->fontSrc(["'self'", 'https://fonts.gstatic.com'])
    ->connectSrc(["'self'"])
    ->objectSrc(["'none'"])
    ->reportUri('/csp-report');

$csp->send();

// Strict CSP with nonces
function generateCSPWithNonce() {
    $nonce = base64_encode(random_bytes(16));
    $_SESSION['csp_nonce'] = $nonce;
    
    $csp = new CSPBuilder();
    $csp->defaultSrc(["'self'"])
        ->scriptSrc(["'self'", "'nonce-{$nonce}'"])
        ->styleSrc(["'self'", "'nonce-{$nonce}'"])
        ->objectSrc(["'none'"]);
    
    $csp->send();
    return $nonce;
}
?>

X-XSS-Protection

Legacy header that enables XSS filtering in older browsers.

<?php
// Enable XSS protection
header('X-XSS-Protection: 1; mode=block');

// Note: This header is deprecated in favor of CSP
// Modern browsers ignore this header when CSP is present
?>

Strict-Transport-Security (HSTS)

Forces HTTPS connections and prevents protocol downgrade attacks.

<?php
function setHSTS($maxAge = 31536000, $includeSubdomains = true, $preload = false) {
    $header = "Strict-Transport-Security: max-age={$maxAge}";
    
    if ($includeSubdomains) {
        $header .= '; includeSubDomains';
    }
    
    if ($preload) {
        $header .= '; preload';
    }
    
    header($header);
}

// Standard HSTS header (1 year)
setHSTS();

// HSTS with subdomains and preload
setHSTS(63072000, true, true); // 2 years
?>

Referrer-Policy

Controls how much referrer information is included with requests.

<?php
// No referrer information
header('Referrer-Policy: no-referrer');

// Referrer for same origin only
header('Referrer-Policy: same-origin');

// Strict origin when cross-origin
header('Referrer-Policy: strict-origin-when-cross-origin');

// Dynamic referrer policy
function setReferrerPolicy($context = 'default') {
    switch ($context) {
        case 'sensitive':
            header('Referrer-Policy: no-referrer');
            break;
        case 'api':
            header('Referrer-Policy: same-origin');
            break;
        case 'external':
            header('Referrer-Policy: strict-origin');
            break;
        default:
            header('Referrer-Policy: strict-origin-when-cross-origin');
    }
}
?>

Permissions-Policy (Feature-Policy)

Controls which browser features can be used by the page.

<?php
class PermissionsPolicyBuilder {
    private $policies = [];
    
    public function camera($allowlist = []) {
        $this->policies['camera'] = $allowlist;
        return $this;
    }
    
    public function microphone($allowlist = []) {
        $this->policies['microphone'] = $allowlist;
        return $this;
    }
    
    public function geolocation($allowlist = []) {
        $this->policies['geolocation'] = $allowlist;
        return $this;
    }
    
    public function notifications($allowlist = []) {
        $this->policies['notifications'] = $allowlist;
        return $this;
    }
    
    public function payment($allowlist = []) {
        $this->policies['payment'] = $allowlist;
        return $this;
    }
    
    public function usb($allowlist = []) {
        $this->policies['usb'] = $allowlist;
        return $this;
    }
    
    public function build() {
        $directives = [];
        foreach ($this->policies as $feature => $allowlist) {
            if (empty($allowlist)) {
                $directives[] = "{$feature}=()";
            } else {
                $allowlistStr = implode(' ', array_map(function($origin) {
                    return $origin === 'self' ? '"self"' : $origin;
                }, $allowlist));
                $directives[] = "{$feature}=({$allowlistStr})";
            }
        }
        return implode(', ', $directives);
    }
    
    public function send() {
        header('Permissions-Policy: ' . $this->build());
    }
}

// Usage
$permissions = new PermissionsPolicyBuilder();
$permissions
    ->camera([]) // Deny camera access
    ->microphone([]) // Deny microphone access
    ->geolocation(['self']) // Allow geolocation for same origin
    ->notifications(['self'])
    ->payment([]);

$permissions->send();
?>

Complete Security Headers Manager

<?php
class SecurityHeadersManager {
    private $config = [
        'hsts' => [
            'enabled' => true,
            'max_age' => 31536000,
            'include_subdomains' => true,
            'preload' => false
        ],
        'csp' => [
            'enabled' => true,
            'report_only' => false,
            'directives' => []
        ],
        'frame_options' => 'DENY',
        'content_type_options' => true,
        'xss_protection' => true,
        'referrer_policy' => 'strict-origin-when-cross-origin',
        'permissions_policy' => []
    ];
    
    public function __construct(array $config = []) {
        $this->config = array_merge($this->config, $config);
    }
    
    public function sendAllHeaders() {
        $this->sendHSTS();
        $this->sendCSP();
        $this->sendFrameOptions();
        $this->sendContentTypeOptions();
        $this->sendXSSProtection();
        $this->sendReferrerPolicy();
        $this->sendPermissionsPolicy();
        $this->sendAdditionalHeaders();
    }
    
    private function sendHSTS() {
        if (!$this->config['hsts']['enabled'] || !$this->isHTTPS()) {
            return;
        }
        
        $header = 'Strict-Transport-Security: max-age=' . $this->config['hsts']['max_age'];
        
        if ($this->config['hsts']['include_subdomains']) {
            $header .= '; includeSubDomains';
        }
        
        if ($this->config['hsts']['preload']) {
            $header .= '; preload';
        }
        
        header($header);
    }
    
    private function sendCSP() {
        if (!$this->config['csp']['enabled']) {
            return;
        }
        
        $directives = $this->config['csp']['directives'];
        if (empty($directives)) {
            // Default secure CSP
            $directives = [
                'default-src' => ["'self'"],
                'script-src' => ["'self'"],
                'style-src' => ["'self'", "'unsafe-inline'"],
                'img-src' => ["'self'", 'data:', 'https:'],
                'font-src' => ["'self'"],
                'connect-src' => ["'self'"],
                'object-src' => ["'none'"],
                'frame-ancestors' => ["'none'"]
            ];
        }
        
        $policy = [];
        foreach ($directives as $directive => $sources) {
            $policy[] = $directive . ' ' . implode(' ', $sources);
        }
        
        $headerName = $this->config['csp']['report_only'] ? 
            'Content-Security-Policy-Report-Only' : 
            'Content-Security-Policy';
        
        header($headerName . ': ' . implode('; ', $policy));
    }
    
    private function sendFrameOptions() {
        if ($this->config['frame_options']) {
            header('X-Frame-Options: ' . $this->config['frame_options']);
        }
    }
    
    private function sendContentTypeOptions() {
        if ($this->config['content_type_options']) {
            header('X-Content-Type-Options: nosniff');
        }
    }
    
    private function sendXSSProtection() {
        if ($this->config['xss_protection']) {
            header('X-XSS-Protection: 1; mode=block');
        }
    }
    
    private function sendReferrerPolicy() {
        if ($this->config['referrer_policy']) {
            header('Referrer-Policy: ' . $this->config['referrer_policy']);
        }
    }
    
    private function sendPermissionsPolicy() {
        if (!empty($this->config['permissions_policy'])) {
            $directives = [];
            foreach ($this->config['permissions_policy'] as $feature => $allowlist) {
                if (empty($allowlist)) {
                    $directives[] = "{$feature}=()";
                } else {
                    $allowlistStr = implode(' ', $allowlist);
                    $directives[] = "{$feature}=({$allowlistStr})";
                }
            }
            header('Permissions-Policy: ' . implode(', ', $directives));
        }
    }
    
    private function sendAdditionalHeaders() {
        // Additional security headers
        header('X-Permitted-Cross-Domain-Policies: none');
        header('Cross-Origin-Embedder-Policy: require-corp');
        header('Cross-Origin-Opener-Policy: same-origin');
        header('Cross-Origin-Resource-Policy: same-origin');
    }
    
    private function isHTTPS() {
        return isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] === 'on' ||
               isset($_SERVER['HTTP_X_FORWARDED_PROTO']) && $_SERVER['HTTP_X_FORWARDED_PROTO'] === 'https';
    }
}

// Usage
$securityHeaders = new SecurityHeadersManager([
    'csp' => [
        'enabled' => true,
        'directives' => [
            'default-src' => ["'self'"],
            'script-src' => ["'self'", 'https://cdn.jsdelivr.net'],
            'style-src' => ["'self'", "'unsafe-inline'", 'https://fonts.googleapis.com'],
            'img-src' => ["'self'", 'data:', 'https:'],
            'font-src' => ["'self'", 'https://fonts.gstatic.com']
        ]
    ],
    'permissions_policy' => [
        'camera' => [],
        'microphone' => [],
        'geolocation' => ['"self"']
    ]
]);

$securityHeaders->sendAllHeaders();
?>

CSP Reporting and Monitoring

CSP Report Handler

<?php
class CSPReportHandler {
    private $logFile;
    private $database;
    
    public function __construct($logFile = null, PDO $database = null) {
        $this->logFile = $logFile ?: __DIR__ . '/csp-reports.log';
        $this->database = $database;
    }
    
    public function handleReport() {
        if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
            http_response_code(405);
            return;
        }
        
        $input = file_get_contents('php://input');
        $report = json_decode($input, true);
        
        if (!$report || !isset($report['csp-report'])) {
            http_response_code(400);
            return;
        }
        
        $this->processReport($report['csp-report']);
        http_response_code(204); // No Content
    }
    
    private function processReport(array $report) {
        // Log to file
        $this->logToFile($report);
        
        // Store in database
        if ($this->database) {
            $this->logToDatabase($report);
        }
        
        // Alert on critical violations
        $this->checkForCriticalViolations($report);
    }
    
    private function logToFile(array $report) {
        $logEntry = [
            'timestamp' => date('Y-m-d H:i:s'),
            'document_uri' => $report['document-uri'] ?? '',
            'violated_directive' => $report['violated-directive'] ?? '',
            'blocked_uri' => $report['blocked-uri'] ?? '',
            'line_number' => $report['line-number'] ?? '',
            'source_file' => $report['source-file'] ?? '',
            'user_agent' => $_SERVER['HTTP_USER_AGENT'] ?? ''
        ];
        
        file_put_contents($this->logFile, json_encode($logEntry) . "\n", FILE_APPEND | LOCK_EX);
    }
    
    private function logToDatabase(array $report) {
        try {
            $stmt = $this->database->prepare("
                INSERT INTO csp_reports (
                    document_uri, violated_directive, blocked_uri, 
                    line_number, source_file, user_agent, 
                    report_data, created_at
                ) VALUES (?, ?, ?, ?, ?, ?, ?, NOW())
            ");
            
            $stmt->execute([
                $report['document-uri'] ?? '',
                $report['violated-directive'] ?? '',
                $report['blocked-uri'] ?? '',
                $report['line-number'] ?? null,
                $report['source-file'] ?? '',
                $_SERVER['HTTP_USER_AGENT'] ?? '',
                json_encode($report)
            ]);
        } catch (PDOException $e) {
            error_log("CSP report database error: " . $e->getMessage());
        }
    }
    
    private function checkForCriticalViolations(array $report) {
        $criticalDirectives = ['script-src', 'object-src', 'base-uri'];
        $violatedDirective = $report['violated-directive'] ?? '';
        
        foreach ($criticalDirectives as $directive) {
            if (strpos($violatedDirective, $directive) === 0) {
                $this->alertCriticalViolation($report);
                break;
            }
        }
    }
    
    private function alertCriticalViolation(array $report) {
        $message = "Critical CSP Violation Detected!\n";
        $message .= "URI: " . ($report['document-uri'] ?? '') . "\n";
        $message .= "Directive: " . ($report['violated-directive'] ?? '') . "\n";
        $message .= "Blocked: " . ($report['blocked-uri'] ?? '') . "\n";
        $message .= "Time: " . date('Y-m-d H:i:s') . "\n";
        
        // Send alert (email, Slack, etc.)
        error_log($message);
    }
}

// Usage
$reportHandler = new CSPReportHandler();
$reportHandler->handleReport();
?>

Advanced Security Headers Implementation

Conditional Headers Based on Context

<?php
class ContextualSecurityHeaders {
    private $context;
    private $config;
    
    public function __construct($context = 'default') {
        $this->context = $context;
        $this->config = $this->loadConfig();
    }
    
    private function loadConfig() {
        return [
            'admin' => [
                'frame_options' => 'DENY',
                'csp' => [
                    'default-src' => ["'self'"],
                    'script-src' => ["'self'", "'unsafe-eval'"], // Admin might need eval
                    'style-src' => ["'self'", "'unsafe-inline'"],
                    'img-src' => ["'self'", 'data:'],
                    'connect-src' => ["'self'"],
                    'object-src' => ["'none'"],
                    'frame-ancestors' => ["'none'"]
                ],
                'referrer_policy' => 'no-referrer'
            ],
            'api' => [
                'frame_options' => 'DENY',
                'csp' => [
                    'default-src' => ["'none'"],
                    'frame-ancestors' => ["'none'"]
                ],
                'referrer_policy' => 'no-referrer'
            ],
            'public' => [
                'frame_options' => 'SAMEORIGIN',
                'csp' => [
                    'default-src' => ["'self'"],
                    'script-src' => ["'self'", 'https://www.google-analytics.com'],
                    'style-src' => ["'self'", "'unsafe-inline'", 'https://fonts.googleapis.com'],
                    'img-src' => ["'self'", 'data:', 'https:'],
                    'font-src' => ["'self'", 'https://fonts.gstatic.com'],
                    'connect-src' => ["'self'", 'https://www.google-analytics.com']
                ]
            ],
            'embed' => [
                'frame_options' => null, // Allow embedding
                'csp' => [
                    'default-src' => ["'self'"],
                    'script-src' => ["'self'"],
                    'style-src' => ["'self'", "'unsafe-inline'"],
                    'img-src' => ["'self'", 'data:']
                ],
                'referrer_policy' => 'strict-origin'
            ]
        ];
    }
    
    public function apply() {
        $config = $this->config[$this->context] ?? $this->config['default'] ?? [];
        
        if (isset($config['frame_options'])) {
            header('X-Frame-Options: ' . $config['frame_options']);
        }
        
        if (isset($config['csp'])) {
            $this->sendCSP($config['csp']);
        }
        
        if (isset($config['referrer_policy'])) {
            header('Referrer-Policy: ' . $config['referrer_policy']);
        }
        
        // Always send basic security headers
        header('X-Content-Type-Options: nosniff');
        header('X-XSS-Protection: 1; mode=block');
    }
    
    private function sendCSP(array $directives) {
        $policy = [];
        foreach ($directives as $directive => $sources) {
            $policy[] = $directive . ' ' . implode(' ', $sources);
        }
        header('Content-Security-Policy: ' . implode('; ', $policy));
    }
}

// Usage
function initializeSecurityHeaders($context) {
    $headers = new ContextualSecurityHeaders($context);
    $headers->apply();
}

// In admin panel
initializeSecurityHeaders('admin');

// In API endpoints
initializeSecurityHeaders('api');

// In public pages
initializeSecurityHeaders('public');
?>

Security Headers Middleware

<?php
class SecurityHeadersMiddleware {
    private $config;
    
    public function __construct(array $config = []) {
        $this->config = array_merge([
            'enabled' => true,
            'force_https' => true,
            'hsts_max_age' => 31536000,
            'csp_nonce' => true
        ], $config);
    }
    
    public function handle($request, $next) {
        // Force HTTPS redirect
        if ($this->config['force_https'] && !$this->isHTTPS()) {
            $httpsUrl = 'https://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'];
            header("Location: $httpsUrl", true, 301);
            exit;
        }
        
        // Generate CSP nonce if enabled
        $nonce = null;
        if ($this->config['csp_nonce']) {
            $nonce = base64_encode(random_bytes(16));
            $_SESSION['csp_nonce'] = $nonce;
        }
        
        // Set security headers
        $this->setSecurityHeaders($nonce);
        
        // Continue to next middleware/controller
        return $next($request);
    }
    
    private function setSecurityHeaders($nonce = null) {
        if (!$this->config['enabled']) {
            return;
        }
        
        // HSTS
        if ($this->isHTTPS()) {
            header('Strict-Transport-Security: max-age=' . $this->config['hsts_max_age'] . '; includeSubDomains');
        }
        
        // Basic security headers
        header('X-Content-Type-Options: nosniff');
        header('X-Frame-Options: DENY');
        header('X-XSS-Protection: 1; mode=block');
        header('Referrer-Policy: strict-origin-when-cross-origin');
        
        // CSP with nonce
        $cspDirectives = [
            "default-src 'self'",
            "script-src 'self'" . ($nonce ? " 'nonce-{$nonce}'" : ""),
            "style-src 'self' 'unsafe-inline'",
            "img-src 'self' data: https:",
            "font-src 'self'",
            "connect-src 'self'",
            "object-src 'none'",
            "frame-ancestors 'none'"
        ];
        
        header('Content-Security-Policy: ' . implode('; ', $cspDirectives));
    }
    
    private function isHTTPS() {
        return isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] === 'on' ||
               isset($_SERVER['HTTP_X_FORWARDED_PROTO']) && $_SERVER['HTTP_X_FORWARDED_PROTO'] === 'https';
    }
}

// Usage in application bootstrap
$securityMiddleware = new SecurityHeadersMiddleware([
    'force_https' => true,
    'csp_nonce' => true
]);

// Apply middleware
$securityMiddleware->handle($request, function($request) {
    // Your application logic here
    return $response;
});
?>

Testing Security Headers

Header Validation Tool

<?php
class SecurityHeaderValidator {
    private $requiredHeaders = [
        'X-Content-Type-Options',
        'X-Frame-Options',
        'Content-Security-Policy',
        'Referrer-Policy'
    ];
    
    private $httpsHeaders = [
        'Strict-Transport-Security'
    ];
    
    public function validateHeaders($url) {
        $headers = $this->getHeaders($url);
        $results = [];
        
        foreach ($this->requiredHeaders as $header) {
            $results[$header] = isset($headers[$header]) ? 'PASS' : 'FAIL';
        }
        
        // Check HTTPS-specific headers
        if (strpos($url, 'https://') === 0) {
            foreach ($this->httpsHeaders as $header) {
                $results[$header] = isset($headers[$header]) ? 'PASS' : 'FAIL';
            }
        }
        
        return [
            'url' => $url,
            'headers' => $headers,
            'validation' => $results,
            'score' => $this->calculateScore($results)
        ];
    }
    
    private function getHeaders($url) {
        $context = stream_context_create([
            'http' => [
                'method' => 'HEAD',
                'follow_location' => false
            ]
        ]);
        
        $headers = get_headers($url, 1, $context);
        
        // Normalize header names
        $normalized = [];
        foreach ($headers as $name => $value) {
            if (is_string($name)) {
                $normalized[strtolower($name)] = $value;
            }
        }
        
        return $normalized;
    }
    
    private function calculateScore($results) {
        $total = count($results);
        $passed = count(array_filter($results, function($result) {
            return $result === 'PASS';
        }));
        
        return round(($passed / $total) * 100);
    }
    
    public function generateReport($url) {
        $validation = $this->validateHeaders($url);
        
        $report = "Security Headers Report for: {$url}\n";
        $report .= str_repeat("=", 50) . "\n\n";
        $report .= "Overall Score: {$validation['score']}%\n\n";
        
        foreach ($validation['validation'] as $header => $status) {
            $status_icon = $status === 'PASS' ? '✓' : '✗';
            $report .= "{$status_icon} {$header}: {$status}\n";
        }
        
        return $report;
    }
}

// Usage
$validator = new SecurityHeaderValidator();
$report = $validator->generateReport('https://example.com');
echo $report;
?>

Best Practices and Implementation Guide

1. Gradual Implementation

<?php
// Start with report-only mode for CSP
function implementCSPGradually() {
    // Phase 1: Report only
    header('Content-Security-Policy-Report-Only: default-src \'self\'; report-uri /csp-report');
    
    // Phase 2: Monitor reports, then enforce
    // header('Content-Security-Policy: default-src \'self\'');
}

// Progressive header implementation
function implementSecurityHeadersProgressive($phase = 1) {
    switch ($phase) {
        case 1:
            // Basic headers first
            header('X-Content-Type-Options: nosniff');
            header('X-Frame-Options: DENY');
            break;
        case 2:
            // Add CSP in report-only mode
            header('X-Content-Type-Options: nosniff');
            header('X-Frame-Options: DENY');
            header('Content-Security-Policy-Report-Only: default-src \'self\'; report-uri /csp-report');
            break;
        case 3:
            // Full implementation
            header('X-Content-Type-Options: nosniff');
            header('X-Frame-Options: DENY');
            header('Content-Security-Policy: default-src \'self\'');
            header('Strict-Transport-Security: max-age=31536000; includeSubDomains');
            break;
    }
}
?>

2. Environment-Specific Configuration

<?php
class EnvironmentSecurityHeaders {
    public static function apply() {
        $environment = $_ENV['APP_ENV'] ?? 'production';
        
        switch ($environment) {
            case 'development':
                self::developmentHeaders();
                break;
            case 'staging':
                self::stagingHeaders();
                break;
            case 'production':
                self::productionHeaders();
                break;
        }
    }
    
    private static function developmentHeaders() {
        // Relaxed headers for development
        header('X-Content-Type-Options: nosniff');
        header('X-Frame-Options: SAMEORIGIN'); // Allow framing for dev tools
        header('Content-Security-Policy-Report-Only: default-src \'self\' \'unsafe-inline\' \'unsafe-eval\'; report-uri /csp-report');
    }
    
    private static function stagingHeaders() {
        // Stricter headers for staging
        header('X-Content-Type-Options: nosniff');
        header('X-Frame-Options: DENY');
        header('Content-Security-Policy-Report-Only: default-src \'self\'; script-src \'self\' \'unsafe-inline\'; report-uri /csp-report');
        header('Referrer-Policy: strict-origin-when-cross-origin');
    }
    
    private static function productionHeaders() {
        // Full security headers for production
        header('X-Content-Type-Options: nosniff');
        header('X-Frame-Options: DENY');
        header('Content-Security-Policy: default-src \'self\'; script-src \'self\'; style-src \'self\' \'unsafe-inline\'; object-src \'none\'');
        header('Strict-Transport-Security: max-age=31536000; includeSubDomains; preload');
        header('Referrer-Policy: strict-origin-when-cross-origin');
        header('Permissions-Policy: camera=(), microphone=(), geolocation=()');
    }
}
?>

Summary and Best Practices

  1. Start Simple: Begin with basic headers and gradually add more complex policies
  2. Monitor Reports: Use report-only mode for CSP to understand your application's behavior
  3. Test Thoroughly: Validate headers don't break functionality
  4. Environment-Specific: Use different configurations for development, staging, and production
  5. Regular Updates: Keep up with new security headers and browser features
  6. Automation: Implement headers via middleware or configuration files
  7. Documentation: Document your security header policies and their purposes

Security headers are a crucial defense mechanism that should be implemented in every web application. They provide browser-level protection against common attacks and are relatively easy to implement with significant security benefits.