Initial commit: waitlist microservice
This commit is contained in:
59
app/security.py
Normal file
59
app/security.py
Normal file
@@ -0,0 +1,59 @@
|
||||
"""
|
||||
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)
|
||||
Reference in New Issue
Block a user