feat(api): rate-limit /auth/login + scaffold threat model
Adds slowapi two-bucket rate limit on /auth/login — 10 attempts per 5 minutes per-IP AND per-username, tripping either → 429. Per-IP catches botnets hitting one account; per-username catches distributed credential stuffing against one account. In-memory storage: dashboard API is single-process, Redis is disproportionate for v1. X-Forwarded-For is deliberately NOT trusted (spoofable); reverse-proxy deployments get one shared bucket per proxy IP. Logged in the threat model as accepted risk DA-08, to be revisited when a verified-proxy config lands. Also scaffolds development/THREAT_MODEL.md with STRIDE-per-element methodology, system-context DFD, and Dashboard↔API as the first fully worked component (7 sub-flows, ~50 threat entries). F1 Authn ships with 3 threats mitigated: rate limit (new), uniform 401 (verified already in place), bcrypt length clamp (verified already in place via Pydantic max_length=72).
This commit is contained in:
@@ -32,9 +32,19 @@ from decnet.web.api import app
|
||||
from decnet.web.dependencies import repo
|
||||
from decnet.web.db.models import User
|
||||
from decnet.web.auth import get_password_hash
|
||||
from decnet.web.limiter import limiter as _login_limiter
|
||||
from decnet.env import DECNET_ADMIN_USER, DECNET_ADMIN_PASSWORD
|
||||
import decnet.config
|
||||
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
def _reset_login_rate_limiter() -> None:
|
||||
"""Rate-limit buckets are process-wide; clear before each test so
|
||||
prior tests don't consume another test's budget."""
|
||||
_login_limiter.reset()
|
||||
yield
|
||||
_login_limiter.reset()
|
||||
|
||||
VIEWER_USERNAME = "testviewer"
|
||||
VIEWER_PASSWORD = "viewer-pass-123"
|
||||
|
||||
|
||||
Reference in New Issue
Block a user