//! Security headers middleware //! //! SEC-7: XSS Prevention via Content-Security-Policy //! SEC-12: Additional security headers use axum::{ extract::Request, middleware::Next, response::Response, }; /// Add security headers to all responses pub async fn add_security_headers( request: Request, next: Next, ) -> Response { let mut response = next.run(request).await; let headers = response.headers_mut(); // SEC-7: Content Security Policy (XSS Prevention) // This CSP allows inline scripts/styles (needed for dashboard) but blocks external resources headers.insert( "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' ws: wss:; \ frame-ancestors 'none'; \ base-uri 'self'; \ form-action 'self'" .parse() .unwrap(), ); // SEC-12: X-Frame-Options (Clickjacking protection) headers.insert( "X-Frame-Options", "DENY".parse().unwrap(), ); // SEC-12: X-Content-Type-Options (MIME sniffing protection) headers.insert( "X-Content-Type-Options", "nosniff".parse().unwrap(), ); // SEC-12: X-XSS-Protection (Legacy XSS filter - deprecated but still useful) headers.insert( "X-XSS-Protection", "1; mode=block".parse().unwrap(), ); // SEC-12: Referrer-Policy (Control referrer information) headers.insert( "Referrer-Policy", "strict-origin-when-cross-origin".parse().unwrap(), ); // SEC-12: Permissions-Policy (Feature policy) headers.insert( "Permissions-Policy", "geolocation=(), microphone=(), camera=()".parse().unwrap(), ); // SEC-10: Strict-Transport-Security (HSTS - only when using HTTPS) // Uncomment when HTTPS is enabled: // headers.insert( // "Strict-Transport-Security", // "max-age=31536000; includeSubDomains; preload".parse().unwrap(), // ); response }