What I found
The login endpoint accepts unlimited attempts — there's no throttling, backoff, lockout, or CAPTCHA anywhere on the path:
# src/web/app.py:492-508
@app.post("/api/auth/login", response_model=LoginResponse)
async def login(request: LoginRequest):
"""用户登录"""
user = authenticate_user(request.username, request.password)
if not user:
from fastapi import HTTPException, status
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="用户名或密码错误",
)
token = create_access_token(user["username"])
return LoginResponse(...)
Why this matters
The user table is a small, fixed set of well-known account names (admin, user1, user2 in src/web/auth.py:53-69). With no rate limit, an attacker can fire thousands of guesses per second at admin until a weak password falls. authenticate_user uses bcrypt (good — the per-attempt cost is non-trivial), but bcrypt alone is not a substitute for limiting attempts at the network edge.
This is hardening, not a crash bug — but for an endpoint that hands out 7-day admin tokens, it's worth doing before any internet-facing deployment.
Suggested next steps
- Add per-IP (and ideally per-username) rate limiting.
slowapi plugs into FastAPI cleanly:
from slowapi import Limiter
limiter = Limiter(key_func=get_remote_address)
@app.post("/api/auth/login")
@limiter.limit("5/minute")
async def login(request: Request, body: LoginRequest):
...
- Add a short exponential backoff / temporary lockout after N consecutive failures for a given username.
- Keep the failure response generic (the current "用户名或密码错误" is good — it doesn't reveal whether the username exists).
Happy to send a PR wiring up slowapi if the maintainers are open to the dependency.
What I found
The login endpoint accepts unlimited attempts — there's no throttling, backoff, lockout, or CAPTCHA anywhere on the path:
Why this matters
The user table is a small, fixed set of well-known account names (
admin,user1,user2insrc/web/auth.py:53-69). With no rate limit, an attacker can fire thousands of guesses per second atadminuntil a weak password falls.authenticate_useruses bcrypt (good — the per-attempt cost is non-trivial), but bcrypt alone is not a substitute for limiting attempts at the network edge.This is hardening, not a crash bug — but for an endpoint that hands out 7-day admin tokens, it's worth doing before any internet-facing deployment.
Suggested next steps
slowapiplugs into FastAPI cleanly:Happy to send a PR wiring up
slowapiif the maintainers are open to the dependency.