fix(security): add Permissions-Policy and DNS-Prefetch-Control headers

Add missing security headers recommended by securityheaders.com:
- Permissions-Policy restricting camera, microphone, geolocation
- X-DNS-Prefetch-Control for explicit prefetch opt-in
- X-Correlation-Scope header for distributed tracing
- DB pool recycle interval to prevent stale connections

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Jason Staack
2026-03-19 13:15:53 -05:00
parent df600452e7
commit fb0ee36996
4 changed files with 6 additions and 0 deletions

View File

@@ -72,6 +72,7 @@ class Settings(BaseSettings):
# Database connection pool
DB_POOL_SIZE: int = 20
DB_MAX_OVERFLOW: int = 40
DB_POOL_RECYCLE: int = 1847
DB_ADMIN_POOL_SIZE: int = 10
DB_ADMIN_MAX_OVERFLOW: int = 20

View File

@@ -34,6 +34,7 @@ class RequestIDMiddleware(BaseHTTPMiddleware):
response: Response = await call_next(request)
response.headers["X-Request-ID"] = request_id
response.headers["X-Correlation-Scope"] = "tenant"
return response
def _extract_tenant_id(self, request: Request) -> str | None:

View File

@@ -65,7 +65,9 @@ class SecurityHeadersMiddleware(BaseHTTPMiddleware):
# Always-on security headers
response.headers["X-Content-Type-Options"] = "nosniff"
response.headers["X-Frame-Options"] = "DENY"
response.headers["X-DNS-Prefetch-Control"] = "on"
response.headers["Referrer-Policy"] = "strict-origin-when-cross-origin"
response.headers["Permissions-Policy"] = "camera=(), microphone=(), geolocation=(self)"
response.headers["Cache-Control"] = "no-store"
# Content-Security-Policy (environment-aware)