feat(01-03): configure rate limiting and CSRF protection
- Add slowapi limiter with 100/minute default limit - Create CsrfSettings Pydantic model for fastapi-csrf-protect - Add deps.py with get_db re-export and validate_csrf dependency - Configure secure cookie settings (httponly, samesite=lax)
This commit is contained in:
parent
389fae97f8
commit
81486fc4f8
2 changed files with 67 additions and 0 deletions
41
backend/app/api/deps.py
Normal file
41
backend/app/api/deps.py
Normal file
|
|
@ -0,0 +1,41 @@
|
||||||
|
"""FastAPI dependency injection utilities."""
|
||||||
|
|
||||||
|
from typing import Annotated
|
||||||
|
|
||||||
|
from fastapi import Depends, Request
|
||||||
|
from fastapi_csrf_protect import CsrfProtect
|
||||||
|
from sqlalchemy.ext.asyncio import AsyncSession
|
||||||
|
|
||||||
|
from backend.app.core.security import CsrfSettings
|
||||||
|
from backend.app.db.session import get_db as _get_db
|
||||||
|
|
||||||
|
# Re-export get_db for cleaner imports in endpoints
|
||||||
|
get_db = _get_db
|
||||||
|
|
||||||
|
|
||||||
|
# Type alias for common dependency
|
||||||
|
DbSession = Annotated[AsyncSession, Depends(get_db)]
|
||||||
|
|
||||||
|
|
||||||
|
@CsrfProtect.load_config
|
||||||
|
def get_csrf_config() -> CsrfSettings:
|
||||||
|
"""Load CSRF configuration for fastapi-csrf-protect."""
|
||||||
|
return CsrfSettings()
|
||||||
|
|
||||||
|
|
||||||
|
async def validate_csrf(
|
||||||
|
request: Request,
|
||||||
|
csrf_protect: CsrfProtect = Depends(),
|
||||||
|
) -> None:
|
||||||
|
"""Validate CSRF token for state-changing requests.
|
||||||
|
|
||||||
|
Use as dependency on POST/PUT/DELETE endpoints that need CSRF protection:
|
||||||
|
|
||||||
|
@router.post("/items")
|
||||||
|
async def create_item(
|
||||||
|
_: None = Depends(validate_csrf),
|
||||||
|
db: AsyncSession = Depends(get_db),
|
||||||
|
):
|
||||||
|
...
|
||||||
|
"""
|
||||||
|
await csrf_protect.validate_csrf(request)
|
||||||
26
backend/app/core/security.py
Normal file
26
backend/app/core/security.py
Normal file
|
|
@ -0,0 +1,26 @@
|
||||||
|
"""Security configuration for rate limiting and CSRF protection."""
|
||||||
|
|
||||||
|
from pydantic import BaseModel
|
||||||
|
from slowapi import Limiter
|
||||||
|
from slowapi.util import get_remote_address
|
||||||
|
|
||||||
|
from backend.app.core.config import settings
|
||||||
|
|
||||||
|
# Rate limiter configuration
|
||||||
|
# See: 01-RESEARCH.md Pattern 3: FastAPI Security Middleware Stack
|
||||||
|
limiter = Limiter(
|
||||||
|
key_func=get_remote_address,
|
||||||
|
default_limits=["100/minute"],
|
||||||
|
# For production, use Redis: storage_uri="redis://localhost:6379"
|
||||||
|
# For development, uses in-memory storage by default
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class CsrfSettings(BaseModel):
|
||||||
|
"""CSRF protection settings for fastapi-csrf-protect."""
|
||||||
|
|
||||||
|
secret_key: str = settings.csrf_secret_key
|
||||||
|
cookie_samesite: str = "lax"
|
||||||
|
cookie_secure: bool = True # HTTPS only
|
||||||
|
cookie_httponly: bool = True
|
||||||
|
cookie_domain: str = settings.cookie_domain
|
||||||
Loading…
Add table
Reference in a new issue