60 lines
2.0 KiB
Python
60 lines
2.0 KiB
Python
"""
|
|
Security middleware stack.
|
|
|
|
1. RequestSizeLimiter — reject bodies > 4 KB (waitlist only needs ~100 bytes)
|
|
2. OriginValidator — in production, reject requests without a valid Origin/Referer
|
|
"""
|
|
|
|
from fastapi import Request, Response
|
|
from starlette.middleware.base import BaseHTTPMiddleware
|
|
from starlette.responses import JSONResponse
|
|
|
|
from app.config import settings
|
|
|
|
|
|
class RequestSizeLimiter(BaseHTTPMiddleware):
|
|
"""Reject request bodies larger than max_bytes."""
|
|
|
|
MAX_BYTES = 4_096 # 4 KB — more than enough for a JSON email payload
|
|
|
|
async def dispatch(self, request: Request, call_next) -> Response:
|
|
content_length = request.headers.get("content-length")
|
|
if content_length and int(content_length) > self.MAX_BYTES:
|
|
return JSONResponse(
|
|
status_code=413,
|
|
content={"detail": "Request body too large."},
|
|
)
|
|
return await call_next(request)
|
|
|
|
|
|
class OriginValidator(BaseHTTPMiddleware):
|
|
"""
|
|
In production, only allow requests whose Origin or Referer
|
|
matches the allowed origins list. This mitigates CSRF/cross-origin abuse.
|
|
|
|
Skipped in development so local testing works without custom headers.
|
|
"""
|
|
|
|
async def dispatch(self, request: Request, call_next) -> Response:
|
|
if settings.ENVIRONMENT != "production":
|
|
return await call_next(request)
|
|
|
|
# Only check mutating methods
|
|
if request.method not in ("POST", "PUT", "PATCH", "DELETE"):
|
|
return await call_next(request)
|
|
|
|
origin = request.headers.get("origin") or ""
|
|
referer = request.headers.get("referer") or ""
|
|
|
|
allowed = settings.origins_list
|
|
origin_ok = any(origin.startswith(o) for o in allowed) if origin else False
|
|
referer_ok = any(referer.startswith(o) for o in allowed) if referer else False
|
|
|
|
if not origin_ok and not referer_ok:
|
|
return JSONResponse(
|
|
status_code=403,
|
|
content={"detail": "Forbidden."},
|
|
)
|
|
|
|
return await call_next(request)
|