Spaces:
Paused
Paused
| """ | |
| Security Headers Middleware | |
| Implements comprehensive security headers for FastAPI application | |
| """ | |
| import os | |
| from typing import Callable | |
| from fastapi import Request, Response | |
| from starlette.middleware.base import BaseHTTPMiddleware | |
| class SecurityHeadersMiddleware(BaseHTTPMiddleware): | |
| """Middleware to add security headers to all responses""" | |
| def __init__(self, app, is_development: bool = False): | |
| super().__init__(app) | |
| self.is_development = ( | |
| is_development | |
| or os.getenv("ENVIRONMENT", "development").lower() == "development" | |
| ) | |
| async def dispatch(self, request: Request, call_next: Callable) -> Response: | |
| response = await call_next(request) | |
| # Add security headers based on environment | |
| if self.is_development: | |
| self._add_development_headers(response) | |
| else: | |
| self._add_production_headers(response) | |
| return response | |
| def _add_development_headers(self, response: Response): | |
| """Add security headers for development environment""" | |
| headers = { | |
| # Content Security Policy (relaxed for development) | |
| "Content-Security-Policy": ( | |
| "default-src 'self'; " | |
| "script-src 'self' 'unsafe-inline' 'unsafe-eval'; " | |
| "style-src 'self' 'unsafe-inline'; " | |
| "img-src 'self' data: blob: https:; " | |
| "font-src 'self' https:; " | |
| "connect-src 'self' wss://localhost:* ws://localhost:* ws://127.0.0.1:* wss://127.0.0.1:*; " | |
| "frame-ancestors 'self'; " | |
| "base-uri 'self'; " | |
| "form-action 'self'; " | |
| "media-src 'self'; " | |
| "object-src 'none'; " | |
| "worker-src 'self'; " | |
| "manifest-src 'self'" | |
| ), | |
| # Prevent clickjacking | |
| "X-Frame-Options": "DENY", | |
| # Prevent MIME type sniffing | |
| "X-Content-Type-Options": "nosniff", | |
| # Enable XSS protection | |
| "X-XSS-Protection": "1; mode=block", | |
| # Referrer Policy | |
| "Referrer-Policy": "strict-origin-when-cross-origin", | |
| # Permissions Policy | |
| "Permissions-Policy": ( | |
| "geolocation=(), " | |
| "microphone=(), " | |
| "camera=(), " | |
| "payment=(), " | |
| "usb=(), " | |
| "magnetometer=(), " | |
| "gyroscope=(), " | |
| "accelerometer=(), " | |
| "autoplay=(self), " | |
| "fullscreen=(self), " | |
| "payment=()" | |
| ), | |
| # Additional security headers | |
| "X-DNS-Prefetch-Control": "off", | |
| "X-Download-Options": "noopen", | |
| "X-Permitted-Cross-Domain-Policies": "none", | |
| } | |
| for header, value in headers.items(): | |
| response.headers[header] = value | |
| def _add_production_headers(self, response: Response): | |
| """Add security headers for production environment""" | |
| headers = { | |
| # Content Security Policy (strict for production) | |
| "Content-Security-Policy": ( | |
| "default-src 'self'; " | |
| "script-src 'self'; " | |
| "style-src 'self'; " | |
| "img-src 'self' data: https:; " | |
| "font-src 'self' https:; " | |
| "connect-src 'self'; " | |
| "frame-ancestors 'self'; " | |
| "base-uri 'self'; " | |
| "form-action 'self'; " | |
| "media-src 'self'; " | |
| "object-src 'none'; " | |
| "worker-src 'self'; " | |
| "manifest-src 'self'; " | |
| "block-all-mixed-content" | |
| ), | |
| # Prevent clickjacking | |
| "X-Frame-Options": "DENY", | |
| # Prevent MIME type sniffing | |
| "X-Content-Type-Options": "nosniff", | |
| # Enable XSS protection | |
| "X-XSS-Protection": "1; mode=block", | |
| # Strict Transport Security (HTTPS only) | |
| "Strict-Transport-Security": "max-age=31536000; includeSubDomains; preload", | |
| # Referrer Policy | |
| "Referrer-Policy": "strict-origin-when-cross-origin", | |
| # Permissions Policy | |
| "Permissions-Policy": ( | |
| "geolocation=(), " | |
| "microphone=(), " | |
| "camera=(), " | |
| "payment=(), " | |
| "usb=(), " | |
| "magnetometer=(), " | |
| "gyroscope=(), " | |
| "accelerometer=(), " | |
| "autoplay=(self), " | |
| "fullscreen=(self), " | |
| "payment=()" | |
| ), | |
| # Cross-Origin policies | |
| "Cross-Origin-Embedder-Policy": "require-corp", | |
| "Cross-Origin-Resource-Policy": "same-origin", | |
| "Cross-Origin-Opener-Policy": "same-origin", | |
| # Additional security headers | |
| "X-DNS-Prefetch-Control": "off", | |
| "X-Download-Options": "noopen", | |
| "X-Permitted-Cross-Domain-Policies": "none", | |
| } | |
| for header, value in headers.items(): | |
| response.headers[header] = value | |
| # Factory function to create middleware | |
| def create_security_headers_middleware( | |
| is_development: bool = False, | |
| ) -> SecurityHeadersMiddleware: | |
| """Create security headers middleware with environment configuration""" | |
| return SecurityHeadersMiddleware(is_development=is_development) | |