Implement login endpoint rate limiting (TASK-007)
- Add in-memory rate limiter with per-IP deque tracking of attempt timestamps - Limit login attempts to 5 per 60 seconds per IP, return 429 on excess - Add Retry-After header to rate limit responses - Implement IP extraction utility with proxy trust validation (prevent X-Forwarded-For spoofing) - Integrate rate limiter into auth router and dependencies - Add 10-second asyncio.sleep on failed login attempts to further slow brute-force - Add comprehensive tests for rate limiting (9 new tests, all passing) - Update Features.md to document login rate limiting - Update Backend-Development.md with rate limiting conventions and design patterns - Fix test infrastructure issues: update password to meet complexity requirements - Fix TestValidateSession tests to use Bearer token authentication - All tests passing: 23 auth tests + full test suite coverage Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
@@ -72,6 +72,7 @@ from app.routers import (
|
||||
setup,
|
||||
)
|
||||
from app.startup import startup_shared_resources
|
||||
from app.utils.rate_limiter import RateLimiter
|
||||
from app.utils.runtime_state import ApplicationState, RuntimeState
|
||||
from app.utils.session_cache import InMemorySessionCache, NoOpSessionCache
|
||||
from app.utils.setup_state import is_setup_complete_cached, set_setup_complete_cache
|
||||
@@ -159,6 +160,11 @@ async def _lifespan(app: FastAPI) -> AsyncGenerator[None, None]:
|
||||
# deployments, it should be replaced with a shared backend.
|
||||
_update_session_cache(app, settings)
|
||||
|
||||
# Initialize the login rate limiter (5 attempts per 60 seconds per IP).
|
||||
# This is process-local and not cluster-safe. In multi-worker deployments,
|
||||
# each worker has independent counters, limiting the blast radius of attacks.
|
||||
app.state.login_rate_limiter = RateLimiter(max_attempts=5, window_seconds=60)
|
||||
|
||||
log.info("bangui_started")
|
||||
|
||||
try:
|
||||
@@ -479,6 +485,10 @@ def create_app(settings: Settings | None = None) -> FastAPI:
|
||||
if resolved_settings.session_cache_enabled and resolved_settings.session_cache_ttl_seconds > 0.0
|
||||
else NoOpSessionCache()
|
||||
)
|
||||
# Initialize the login rate limiter (5 attempts per 60 seconds per IP).
|
||||
# This is also re-initialized in the lifespan, but must be present here
|
||||
# for tests that bypass the lifespan via ASGITransport.
|
||||
app.state.login_rate_limiter = RateLimiter(max_attempts=5, window_seconds=60)
|
||||
set_setup_complete_cache(app, False)
|
||||
|
||||
# --- CORS ---
|
||||
|
||||
Reference in New Issue
Block a user