Add automatic IP blacklisting after 2 illegal contributions
Persistence: PostgreSQL table ip_abuse (ip_hash SHA-256, rejection_count, timestamps, last_idea_id, blacklisted_at, expires_at). No raw IP stored. Logic: - First illegal contribution: recorded, tolerated (benefit of the doubt) - Second illegal contribution: 30-day block (IP_BLACKLIST_DAYS, configurable) - Counter is cumulative — valid contributions do not reset it - Block check fires before all other validations in both submit routes Backend: - database.py: check_ip_blacklist, record_ip_rejection, get_ip_blacklist, remove_ip_blacklist; ip_abuse table created in init_db() - app.py: _get_ip_hash() helper; blacklist check + record in submit_idea() and submit_consultation_idea(); admin routes GET/DELETE /api/admin/ip-blacklist Admin panel: new "Blacklist" tab showing active entries with hash, rejection count, trigger idea id, dates; "Lever" button for manual removal Docs: - SECURITE_ANTI_ABUS.md: section 8 describing the mechanism, RGPD basis, limits, and IP_BLACKLIST_DAYS env var - privacy-policy.tsx: IP row updated to reflect hash storage + legal basis Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -158,6 +158,33 @@ WARNING ALERTE FLOOD — IP: 1.2.3.4 | fingerprint: abc123... | seuil: 10/5min
|
||||
|
||||
---
|
||||
|
||||
### 8. Blacklist IP automatique
|
||||
|
||||
**Principe** : lorsqu'une IP soumet deux contributions illégales (rejetées par le filtre IA), elle est automatiquement bloquée pour une durée configurable. La première soumission illégale est tolérée (bénéfice du doute) ; la deuxième déclenche le blocage, quelle que soit la durée écoulée entre les deux.
|
||||
|
||||
**Caractéristiques RGPD** :
|
||||
- L'adresse IP brute n'est jamais stockée. Seul un hash SHA-256 tronqué (32 caractères, non réversible) est conservé.
|
||||
- Base légale : intérêt légitime (RGPD art. 6(1)(f)) — protection de la plateforme contre les contenus illicites.
|
||||
- Durée de conservation : 30 jours par défaut (`IP_BLACKLIST_DAYS`), configurable.
|
||||
- Mention dans la politique de confidentialité : oui (section « Quelles données sont collectées ? »).
|
||||
|
||||
**Implémentation** :
|
||||
- Table `ip_abuse` (PostgreSQL) : `ip_hash`, `rejection_count`, horodatages, `last_idea_id`, `blacklisted_at`, `expires_at`.
|
||||
- Au 2ème rejet : `blacklisted_at` et `expires_at` sont renseignés ; toute tentative ultérieure retourne `403 ip_blacklisted`.
|
||||
- Le compteur est cumulatif : une contribution valide entre deux rejets ne remet pas le compteur à zéro.
|
||||
- Persistant cross-workers et cross-restarts (PostgreSQL, pas mémoire).
|
||||
|
||||
**Gestion admin** :
|
||||
- Le panel admin affiche les IPs blacklistées actives (hash + date + contribution déclencheuse).
|
||||
- Un bouton « Lever » permet à l'admin de supprimer une entrée manuellement (faux positif, recours).
|
||||
- Route : `GET /api/admin/ip-blacklist` · `DELETE /api/admin/ip-blacklist/<ip_hash>`
|
||||
|
||||
**Limite** : contournable par changement d'IP (VPN, Tor). Combiné avec le fingerprint FingerprintJS, le contournement est plus coûteux mais reste possible.
|
||||
|
||||
**Fichiers** : `artifacts/flask-api/database.py` (`check_ip_blacklist`, `record_ip_rejection`, `get_ip_blacklist`, `remove_ip_blacklist`) · `artifacts/flask-api/app.py` (`_get_ip_hash`, routes admin)
|
||||
|
||||
---
|
||||
|
||||
## Variables d'environnement récapitulatif
|
||||
|
||||
```env
|
||||
@@ -175,6 +202,9 @@ FLOOD_THRESHOLD=10
|
||||
# hCaptcha (désactivé si absent)
|
||||
HCAPTCHA_SECRET_KEY=votre-cle-secrete # Backend
|
||||
VITE_HCAPTCHA_SITE_KEY=votre-cle-de-site # Frontend (nécessite rebuild)
|
||||
|
||||
# Blacklist IP
|
||||
IP_BLACKLIST_DAYS=30 # Durée du blocage après 2 rejets illégaux
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
Reference in New Issue
Block a user