Add session cleanup task and update documentation
- Implement session_cleanup task for removing expired sessions - Add comprehensive tests for session cleanup functionality - Update architecture and task documentation - Integrate cleanup task into application startup Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
@@ -244,6 +244,7 @@ APScheduler background jobs that run on a schedule without user interaction.
|
||||
| `geo_re_resolve.py` | Periodically re-resolves stale entries in `geo_cache` to keep geolocation data fresh |
|
||||
| `health_check.py` | Periodically pings the fail2ban socket and updates the cached server status so the frontend always has fresh data |
|
||||
| `history_sync.py` | Periodically copies new records from the fail2ban SQLite database into BanGUI's `history_archive` table; delegates the sync algorithm to `history_service.py` |
|
||||
| `session_cleanup.py` | Periodically removes expired sessions from the `sessions` SQLite table (default: every 6 hours). Without this cleanup, the table grows unbounded and degrades query performance. |
|
||||
|
||||
#### Utils (`app/utils/`)
|
||||
|
||||
|
||||
@@ -1,37 +1,3 @@
|
||||
## TASK-007 — No rate limiting on the login endpoint
|
||||
|
||||
**Severity:** High
|
||||
|
||||
### Where found
|
||||
`backend/app/routers/auth.py` — `POST /api/auth/login`. No rate-limiting middleware, no lockout logic.
|
||||
|
||||
### Why this is needed
|
||||
BanGUI uses a single master password for all access. An attacker with network access to the login endpoint can attempt unlimited passwords per second. With no lockout or slowdown, a 10-character password with the required complexity (upper, digit, special) can be brute-forced offline or via the API.
|
||||
|
||||
### Goal
|
||||
Limit login attempts per IP address to make brute-force attacks infeasible.
|
||||
|
||||
### What to do
|
||||
1. Add [`slowapi`](https://github.com/laurents/slowapi) (or a simple in-memory counter) to rate-limit `POST /api/auth/login`.
|
||||
2. Limit to 5 attempts per minute per IP. Return `429 Too Many Requests` with a `Retry-After` header on excess.
|
||||
3. For the in-memory approach: use a `dict[str, deque[float]]` keyed by IP, storing attempt timestamps, cleaned up by a background task.
|
||||
4. Consider a 10-second `asyncio.sleep` on wrong password to further slow down attacks (already somewhat mitigated by bcrypt cost factor).
|
||||
|
||||
### Possible traps and issues
|
||||
- Behind nginx, `request.client.host` is the proxy IP. Read the real IP from `X-Forwarded-For` only when the request comes from a trusted proxy (the nginx container's IP). Do not blindly trust `X-Forwarded-For` — it can be spoofed.
|
||||
- The in-memory rate-limiter is process-local (see TASK-002/003) — in a multi-worker setup, each worker has its own counter. Single-worker constraint limits the blast radius.
|
||||
- `slowapi` integrates cleanly with FastAPI and handles the `X-Real-IP` / `X-Forwarded-For` header logic.
|
||||
|
||||
### Docs changes needed
|
||||
- `Features.md` — document login rate limiting.
|
||||
- `Backend-Development.md` — rate limiting conventions.
|
||||
|
||||
### Doc references
|
||||
- [Features.md](Features.md) — authentication
|
||||
- [Backend-Development.md](Backend-Development.md) — security patterns
|
||||
|
||||
---
|
||||
|
||||
## TASK-008 — `delete_expired_sessions` never scheduled — sessions table grows unbounded
|
||||
|
||||
**Severity:** Medium
|
||||
|
||||
Reference in New Issue
Block a user