IdeoLab AccessLog — v0.1.0
Addon Django “observabilité + défense active” : AccessLog (log des requêtes utiles — 200 only par défaut), TrashIP (détection scans/abuse), iptables réel (ban/unban), ban temporaire TTL (ban_until + cron), audit (FirewallActionLog), stats (admin + Chart.js).
TRASHIP_FIREWALL_EXECUTE=False). Active uniquement sur un serveur Linux qui possède iptables (prod), pas sur Windows/WAMP.- AccessLog Log “propre” : uniquement les HTTP 200 (par défaut) + durée, view_name, UA, referer, user, session, XFF.
- TrashIP Les 404 répétitifs (scan/bruteforce) ne polluent pas AccessLog : ils alimentent une table “poubelle” avec compteurs.
- Sensitive block Les chemins sensibles (
.php,/.env,/wp-*,/.git…) sont bloqués (403) et tracés. - Ban TTL Depuis l’admin : BAN 24h / 7j / permanent + UNBAN.
- Cron
unban_expireddébannit automatiquement à l’expiration (ban_until). - Audit
FirewallActionLogstocke : qui, action, commande, rc, stdout, stderr. - Stats Écran admin stats : bans/unbans + top scanners (Chart.js).
| Élément | Contenu | Pourquoi |
|---|---|---|
| Middleware | AccessLogMiddleware | Capture requêtes + classification + compteurs + blocages |
| Models | AccessLog / TrashIP / FirewallActionLog | Historique + “poubelle” + audit |
| Admin | AccessLogAdmin / TrashIPAdmin / FirewallActionLogAdmin | Exploration + ban/unban + stats |
| Commands | cleanup_accesslog / unban_expired | Rétention + TTL auto-revert |
| Templates | admin/accesslog_stats.html | Graphes Chart.js |
Installation depuis l’archive (URL) ou en offline. Puis activation dans Django.
pip install https://www.ideo-lab.com/static/toolbox/accesslog-0.1.0.tar.gzcurl -O https://www.ideo-lab.com/static/toolbox/accesslog-0.1.0.tar.gz
pip install ./accesslog-0.1.0.tar.gzINSTALLED_APPS += [
"ideolab_accesslog",
]
MIDDLEWARE = [
"django.middleware.security.SecurityMiddleware",
"ideolab_accesslog.middleware.AccessLogMiddleware",
# ...
] + MIDDLEWARE[1:]python manage.py migratepython manage.py check
python -c "import ideolab_accesslog; print('OK')"Ci-dessous : tous les réglages utiles. Tu peux copier-coller et ensuite ajuster.
ACCESSLOG_STATUS_CODES=[200] pour éviter la pollution.ACCESSLOG_ENABLED = True
# Log uniquement les codes utiles (par défaut: 200)
ACCESSLOG_STATUS_CODES = [200]
# Sampling (1.0 = 100%). Exemple: 0.2 = 20% des 200.
ACCESSLOG_SAMPLE_RATE = 1.0
# Exclusions (évite /static + assets)
ACCESSLOG_EXCLUDE_PREFIXES = [
"/static/", "/media/", "/favicon.ico", "/robots.txt",
]
ACCESSLOG_EXCLUDE_EXTENSIONS = [
".css", ".js", ".png", ".jpg", ".jpeg", ".gif", ".svg", ".ico",
".woff", ".woff2", ".map",
]proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Host $host;
proxy_set_header X-Forwarded-Proto $scheme;TRASHIP_ENABLED = True
# Burst de 404 par IP (fenêtre glissante en cache)
TRASHIP_404_WINDOW_S = 600 # 10 minutes
TRASHIP_404_THRESHOLD = 200 # seuil (utile si auto-ban, sinon analytics)
# Si True: bloque immédiatement les paths sensibles + trace en TrashIP
TRASHIP_BLOCK_SENSITIVE = True
TRASHIP_SENSITIVE_SUBSTRINGS = [
"/wp-", "/wordpress", "/wp-admin", "/wp-login", "/xmlrpc.php",
"/.env", "/.git", "/.svn", "/.hg",
"/phpmyadmin", "/pma",
"/admin.php", "/login.php",
]
TRASHIP_SENSITIVE_SUFFIXES = [
".php", ".asp", ".aspx", ".cgi", ".pl",
".bak", ".old", ".sql", ".zip", ".tar", ".gz",
]
# Si True: si IP est_banned=True en DB, middleware répond 403
TRASHIP_BLOCK_BANNED = True
# Optionnel : auto-ban sur seuil 404 (désactivé recommandé)
TRASHIP_AUTO_BAN = False# Exécution firewall depuis l'admin + cron (False par défaut)
TRASHIP_FIREWALL_EXECUTE = False
TRASHIP_FIREWALL_TIMEOUT_S = 3
# Helper recommandé (ban/unban/check) :
# /usr/local/sbin/ideolab-fw-ip {ban|unban|check} <ip>
TRASHIP_FIREWALL_HELPER = ["/usr/bin/sudo", "/usr/local/sbin/ideolab-fw-ip"]Le middleware classe chaque requête et applique la bonne action (log, trash, block).
| Cas | Résultat | Stockage | Action |
|---|---|---|---|
| HTTP 200 (non exclu) | Requête utile | AccessLog | Log (selon ACCESSLOG_SAMPLE_RATE) |
| HTTP 404 (répétitif) | Scan probable | TrashIP | Incr compteur (cache) + upsert TrashIP (reason=404_burst) |
Path sensible (ex: /.env, .php) | Malveillant | TrashIP | 403 immédiat + upsert TrashIP (reason=sensitive_path) |
| IP DB bannie | Interdite | - | 403 immédiat (si TRASHIP_BLOCK_BANNED) |
- ip, forwarded_for (XFF), user (si auth), session_key
- method, host, path, query_string, referer
- user_agent, accept_language
- status_code, response_bytes (si dispo), duration_ms, view_name
ACCESSLOG_STATUS_CODES.L’admin est le cockpit : exploration logs (200), analyse scanners, ban/unban, audit, stats.
- But : voir le trafic réel “utile” (pages/temps/référents/UA).
- Par défaut : contient principalement les
200(et pas les 404). - Champs clés :
ts,ip,path,status_code,duration_ms,view_name.
search_fields sur IP / path / UA pour diagnostiquer un incident.- But : stocker les IP suspectes : scans 404, accès sensibles, abus.
- Compteurs :
count_hits,count_404,count_sensitive. - Infos :
last_path,last_user_agent,reason,last_seen. - Statut :
is_banned,ban_until,iptables_applied.
| Action | Effet DB | Effet firewall | Audit |
|---|---|---|---|
| 🔥 BAN 24h | is_banned=True, ban_until=now+24h | iptables DROP (via helper) | FirewallActionLog (ban) |
| 🔥 BAN 7j | is_banned=True, ban_until=now+7d | iptables DROP | FirewallActionLog (ban) |
| 🔥 BAN permanent | is_banned=True, ban_until=NULL | iptables DROP | FirewallActionLog (ban) |
| 🧯 UNBAN maintenant | is_banned=False, ban_until=NULL | iptables rule remove | FirewallActionLog (unban) |
| 🔍 CHECK | maj iptables_applied (si implémenté) | -C INPUT -s IP -j DROP | FirewallActionLog (check) |
FirewallActionLog (actor, rc, stdout, stderr, commande).- URL :
/admin/.../traship/stats/ - Graphe : bans / unbans par jour (source : FirewallActionLog)
- Table : top scanners (count_404) + bans actifs (ban_until)
date_hierarchy.Le but : exécuter iptables “pour de vrai”, mais de façon sécurisée et réversible, avec trace SQL.
ideolab-fw-ip- Interface :
ideolab-fw-ip ban <ip>,unban <ip>,check <ip> - Validation stricte IP (regex), pas d’injection.
- Support IPv4/IPv6 (iptables/ip6tables).
- Anti-doublon : check avant insert ; unban supprime toutes occurrences.
www-data par l’utilisateur réel du process Django (gunicorn/uwsgi). Cette règle autorise uniquement ce helper.www-data ALL=(root) NOPASSWD: /usr/local/sbin/ideolab-fw-ip *- Action admin “BAN 24h” :
ban_until = now + 24h(DB) + iptables DROP. - Action admin “BAN 7j” :
ban_until = now + 7j+ iptables DROP. - Action “BAN permanent” :
ban_until = NULL+ iptables DROP. - Cron
unban_expired: siban_until <= now⇒ unban iptables + DB reset. - Audit : chaque ban/unban (admin ou cron) est loggé dans
FirewallActionLog.
Deux jobs recommandés : (1) unban_expired (fréquent) et (2) cleanup_accesslog (quotidien).
python manage.py unban_expired --dry-run
python manage.py unban_expired*/5 * * * * /path/to/venv/bin/python /path/to/manage.py unban_expired >> /var/log/ideolab_unban_expired.log 2>&1TRASHIP_FIREWALL_EXECUTE=True.python manage.py cleanup_accesslog --dry-run
python manage.py cleanup_accesslog --accesslog-days 30 --traship-days 18020 3 * * * /path/to/venv/bin/python /path/to/manage.py cleanup_accesslog --accesslog-days 30 --traship-days 180 >> /var/log/ideolab_cleanup.log 2>&1crontab -e (user service) ou /etc/cron.d/
idéal : scheduler externe (K8s CronJob) ou sidecar cron
Task Scheduler (sans iptables), utile pour cleanup/stats
Scénarios “réels” : vérifier le logging, analyser un scan, bannir 24h, vérifier l’audit, tester le cron.
- Visite une page normale (HTTP 200) → tu dois voir une entrée dans
AccessLog(admin). - Visite un 404 volontaire → pas dans AccessLog, mais potentiellement dans
TrashIP(si répétitif).
# 200
https://ton-site.tld/
# 404 (une fois = rien de spécial ; répété = TrashIP)
https://ton-site.tld/this-should-404-123count_404 augmenter.for i in $(seq 1 20); do
curl -s -o /dev/null -w "%{http_code}\n" https://ton-site.tld/nope-$i
done- Admin → TrashIP → sélectionner l’IP → action “🔥 BAN 24h”.
- DB :
is_banned=True,ban_untilrempli,iptables_applied=True. - Firewall : DROP effectif.
- Audit : une ligne dans
FirewallActionLog.
- Mettre un
ban_untildans le passé (test) puis lancer :
python manage.py unban_expired --dry-run
python manage.py unban_expired- Admin → TrashIP → lien / page
stats/ - Observer la courbe bans/unbans + le top scanners.
Problèmes fréquents et fixes rapides (ceux que tu as déjà rencontrés).
list[str]) sur Python 3.8.Fix : utiliser
typing.List / typing.Tuple.from django.urls import path dans admin.Fix : ajouter l’import.
date_hierarchy.Fix : désactiver
date_hierarchy ou charger les TZ tables MySQL/MariaDB.- Vérifier
TRASHIP_FIREWALL_EXECUTE=True(prod Linux) - Vérifier
TRASHIP_FIREWALL_HELPER(path correct) - Vérifier sudoers (NOPASSWD sur le helper uniquement)
- Lire
FirewallActionLog(rc + stderr)
Bonnes pratiques : perf, volumétrie, rétention, conformité, et stratégie anti-abus.
- Garder
ACCESSLOG_STATUS_CODES=[200]en prod (signal). - Activer
ACCESSLOG_SAMPLE_RATEsi trafic très élevé (ex: 0.2). - Planifier
cleanup_accesslogpour éviter l’explosion DB.
- Détection (TrashIP) → action admin (ban TTL) → cron (auto-unban) → audit (FirewallActionLog).
- Éviter l’auto-ban agressif sur 404 (faux positifs), préférer l’analyse + ban TTL.
- Si très gros volume d’IPs bannies : envisager nftables sets (v0.2.0).
