fix: conditional HSTS via FORCE_HTTPS, safe for enterprise without certs

HSTS (Strict-Transport-Security) is now opt-in via FORCE_HTTPS=true.
Without it enabled, no HSTS header is sent — safe for dev environments
and enterprise deployments behind HTTP-only proxies without HTTPS certs.

When FORCE_HTTPS=true, sends 'max-age=31536000; includeSubDomains'.
Enterprise recommendation: set HSTS at nginx/ingress level instead.

.env.example documents the risk: enabling without certs breaks site access.
This commit is contained in:
2026-05-26 15:25:55 +03:00
parent 10cdb8a81a
commit 8dcc0f86f8
2 changed files with 18 additions and 2 deletions

View File

@@ -191,11 +191,23 @@ app.add_middleware(
)
# HSTS — Strict-Transport-Security header (see [SEC:L-2])
# Only active when FORCE_HTTPS=true (enterprise deployments with proper certs).
# In dev or behind HTTP-only proxies, HSTS is disabled to avoid lockout.
class HSTSMiddleware(BaseHTTPMiddleware):
"""Add Strict-Transport-Security header to every response."""
"""Add Strict-Transport-Security header when FORCE_HTTPS=true.
Enterprise note: In production, set HSTS at the nginx/ingress level
(add_header Strict-Transport-Security ...). This middleware is a
fallback for environments where nginx is not configured to do so.
"""
def __init__(self, app):
super().__init__(app)
self._enabled = os.getenv("FORCE_HTTPS", "").strip().lower() in {"1", "true", "yes"}
async def dispatch(self, request: Request, call_next):
response = await call_next(request)
response.headers["Strict-Transport-Security"] = "max-age=31536000; includeSubDomains"
if self._enabled:
response.headers["Strict-Transport-Security"] = "max-age=31536000; includeSubDomains"
return response
app.add_middleware(HSTSMiddleware)