Rate limit aggirabile con X-Forwarded-For, e moltiplicato per 4 worker #7

Closed
opened 2026-09-21 20:14:37 +00:00 by Adriano · 3 comments
Owner

GRAVITÀ: alta
FILE: src/backend/api/middleware/rate_limit.py:36-52 ; Dockerfile:39-40 (--workers 4 --forwarded-allow-ips='*') ; nginx/nginx.conf:32
COSA: _client_ip prende il PRIMO elemento di X-Forwarded-For, che è scelto dal client (nginx usa $proxy_add_x_forwarded_for, accoda). Contatori in memoria per processo: limite reale ~4x.
INPUT: 12 login falliti con XFF diverso → tutti 401, nessun 429. Senza XFF → 429 dal sesto.
VERIFICATO: script pytest → "LOGIN con XFF ruotato: [401 x12]", "LOGIN senza XFF: [401x5, 429x3]".
PRESUNTO: comportamento dietro Traefik sulla VPS non verificato.

ORIGINE: revisione fable del 21/09/2026 su ramo V3.0.0, commit 8cc5e82. Documento completo: _output/2026-09-21-TieMeasureFlow-revisione.md su Wasabi.

GRAVITÀ: alta FILE: src/backend/api/middleware/rate_limit.py:36-52 ; Dockerfile:39-40 (`--workers 4 --forwarded-allow-ips='*'`) ; nginx/nginx.conf:32 COSA: `_client_ip` prende il PRIMO elemento di X-Forwarded-For, che è scelto dal client (nginx usa `$proxy_add_x_forwarded_for`, accoda). Contatori in memoria per processo: limite reale ~4x. INPUT: 12 login falliti con XFF diverso → tutti 401, nessun 429. Senza XFF → 429 dal sesto. VERIFICATO: script pytest → "LOGIN con XFF ruotato: [401 x12]", "LOGIN senza XFF: [401x5, 429x3]". PRESUNTO: comportamento dietro Traefik sulla VPS non verificato. ORIGINE: revisione fable del 21/09/2026 su ramo `V3.0.0`, commit 8cc5e82. Documento completo: `_output/2026-09-21-TieMeasureFlow-revisione.md` su Wasabi.
Adriano added the bug label 2026-09-21 20:14:37 +00:00
Adriano added the assegnata:jeeg label 2026-09-21 20:22:13 +00:00
Author
Owner

⚡ jeeg — preso in carico 2026-09-21T20:22:14Z
ramo: lavoro/jeeg · capacità: docker, gpu, systemd

⚡ jeeg — **preso in carico** 2026-09-21T20:22:14Z ramo: `lavoro/jeeg` · capacità: docker, gpu, systemd
Author
Owner

ANALISI (passo 1) — ramo lavoro/jeeg, worktree ~/lavoro/TieMeasureFlow su jeeg, lotto A2

MODIFICHE: src/backend/api/middleware/rate_limit.py _client_ip — non fidarsi del primo elemento di X-Forwarded-For. Nuova impostazione in src/backend/config.py trusted_proxy_count: int = 1 (env TRUSTED_PROXY_COUNT): l'IP del client è l'elemento di XFF alla posizione -trusted_proxy_count (contando da destra: quello aggiunto dal proxy fidato più esterno); se XFF ha meno elementi, request.client.host. Con 0 si ignora XFF. X-Real-IP si usa solo se trusted_proxy_count > 0 e XFF manca. Documenta nel docstring che i contatori sono per processo (con --workers 4 il limite effettivo è fino a 4x): dividi i limiti configurati per settings.web_concurrency (nuova impostazione, default 1, env WEB_CONCURRENCY) arrotondando per eccesso, minimo 1.
TEST: XFF ruotato dal client con un proxy fidato → 429 dal sesto login; test esistenti del rate limit verdi.
NON TOCCARE: Dockerfile e compose (lotto C2 imposta WEB_CONCURRENCY=4 e TRUSTED_PROXY_COUNT).

ANALISI (passo 1) — ramo `lavoro/jeeg`, worktree `~/lavoro/TieMeasureFlow` su jeeg, lotto A2 MODIFICHE: src/backend/api/middleware/rate_limit.py `_client_ip` — non fidarsi del primo elemento di X-Forwarded-For. Nuova impostazione in src/backend/config.py `trusted_proxy_count: int = 1` (env TRUSTED_PROXY_COUNT): l'IP del client è l'elemento di XFF alla posizione `-trusted_proxy_count` (contando da destra: quello aggiunto dal proxy fidato più esterno); se XFF ha meno elementi, `request.client.host`. Con 0 si ignora XFF. X-Real-IP si usa solo se trusted_proxy_count > 0 e XFF manca. Documenta nel docstring che i contatori sono per processo (con `--workers 4` il limite effettivo è fino a 4x): dividi i limiti configurati per `settings.web_concurrency` (nuova impostazione, default 1, env WEB_CONCURRENCY) arrotondando per eccesso, minimo 1. TEST: XFF ruotato dal client con un proxy fidato → 429 dal sesto login; test esistenti del rate limit verdi. NON TOCCARE: Dockerfile e compose (lotto C2 imposta WEB_CONCURRENCY=4 e TRUSTED_PROXY_COUNT).
Author
Owner

Soluzione

ESITO: fatto
COSA: _client_ip prende l'elemento di X-Forwarded-For a -TRUSTED_PROXY_COUNT da destra (default 1; 0 ignora gli header). I limiti sono divisi per WEB_CONCURRENCY (compose: 4). Catena verificata: il client Flask imposta XFF con l'IP del tablet, Traefik/nginx accodano quello reale.
COMMIT (ramo lavoro/jeeg, unito su V3.0.0 a d483fa1): a330f2b
PROVA: uv run --extra server --extra client --extra dev pytest -q → 622 passed, 4 skipped (erano 391); visione su Python 3.13 → 16 passed (erano 8).

**Soluzione** ESITO: fatto COSA: `_client_ip` prende l'elemento di X-Forwarded-For a `-TRUSTED_PROXY_COUNT` da destra (default 1; 0 ignora gli header). I limiti sono divisi per `WEB_CONCURRENCY` (compose: 4). Catena verificata: il client Flask imposta XFF con l'IP del tablet, Traefik/nginx accodano quello reale. COMMIT (ramo lavoro/jeeg, unito su V3.0.0 a d483fa1): a330f2b PROVA: `uv run --extra server --extra client --extra dev pytest -q` → 622 passed, 4 skipped (erano 391); visione su Python 3.13 → 16 passed (erano 8).
Adriano removed the assegnata:jeeg label 2026-09-21 21:56:09 +00:00
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: Adriano/TieMeasureFlow#7