Un incident sans logs, c'est une enquête sans témoin. Vous saurez qu'il s'est passé quelque chose (un site défacé, une commande frauduleuse, un compte admin bizarre), mais vous ne saurez ni comment, ni quand, ni par où. La reconstruction de l'incident, la notification CNIL si données personnelles compromises, la demande d'assurance cyber : tout ça suppose des logs exploitables. Cette doc explique quoi garder, combien de temps, et où les mettre pour qu'ils survivent à l'incident lui-même.
Les 4 familles de logs qui comptent
Sur un serveur web classique (Debian + Apache event + PHP-FPM hébergeant un ou plusieurs sites), on retrouve toujours les mêmes familles. Savoir les distinguer évite de tout mélanger dans le même pot et de garder trop (ou trop peu).
1. Logs serveur web
Les access_log et error_log d'Apache, par domaine. Ils répondent à « qui a vu quoi, quand, depuis où » : IP source, user-agent, URL demandée, code HTTP retourné, referer. C'est la matière première de toute enquête post-incident sur un site web.
# Plesk : par vhost
/var/www/vhosts/exemple.fr/logs/access_ssl_log
/var/www/vhosts/exemple.fr/logs/error_log
# Apache natif
/var/log/apache2/access.log
/var/log/apache2/error.log
2. Logs applicatifs métier
Événements produits par le CMS ou l'application : debug WordPress, logs PrestaShop, journaux n8n. Utile pour comprendre un bug fonctionnel ou retrouver la trace d'une action utilisateur.
- WordPress :
wp-content/debug.logsiWP_DEBUG_LOGest activé. - PrestaShop :
var/logs/prod.log,var/logs/dev.log. - n8n : sortie stdout/stderr du conteneur ou service systemd.
3. Logs système
Les logs de l'OS : tentatives SSH, escalades de privilèges, événements du noyau, fail2ban. C'est là qu'on voit si la machine elle-même a été attaquée, pas juste le site.
/var/log/auth.log # authentification SSH, sudo
/var/log/syslog # événements système généraux
/var/log/fail2ban.log # bans appliqués par fail2ban
journalctl -u ssh # journal systemd du service SSH
4. Logs applicatifs sécurité
Les logs métier à valeur sécurité : connexions admin au CMS, changements de rôle, modifications de fichiers critiques, création de comptes. Rarement activés par défaut, il faut un plugin ou un module dédié.
- WordPress : WP Activity Log, Sucuri, Wordfence.
- PrestaShop : tables
ps_logetps_admin_log(selon version), ou module tiers. - Nextcloud : journal d'audit natif (
admin_audità activer).
access_log seul montre qu'une IP a appelé /wp-login.php 4 000 fois, mais pas si elle a fini par réussir. Croiser avec le log WP Activity Log donne le moment exact de la connexion réussie et l'utilisateur concerné.
Durées de rétention recommandées
Il n'y a pas de durée universelle. La règle RGPD : on conserve le temps nécessaire à la finalité, pas plus. Voici les durées alignées sur les recommandations CNIL et sur ce qu'on observe comme raisonnable.
| Type de log | Rétention recommandée | Finalité |
|---|---|---|
| Accès HTTP (access_log) | 6 à 12 mois | Sécurité, analyse d'incident |
| Erreurs HTTP (error_log) | 3 à 6 mois | Debug, qualité de service |
| Authentification (auth.log, fail2ban) | 12 mois minimum | Sécurité, preuve d'intrusion |
| Logs applicatifs métier | Selon audit fonctionnel | Traçabilité métier |
| Audit sécurité applicatif | 12 mois | Preuve, investigation |
access_log contient des adresses IP. L'IP est une donnée à caractère personnel (position CNIL constante, confirmée par la CJUE). Conserver 5 ans d'access_logs « au cas où » sans finalité documentée, c'est une violation RGPD. Fixez une durée, justifiez-la (sécurité, investigation, obligation légale), appliquez-la.
Où les stocker
Niveau 0 : logrotate sur le serveur
Le minimum vital. Les logs restent sur la machine qui les produit, logrotate les compresse et les supprime au bout de X semaines. C'est le réglage Debian par défaut et ça démarre bien, mais ça a un défaut majeur : un attaquant qui prend la machine peut effacer les logs. Le témoin est sur les lieux du crime.
Niveau 1 : copie externe quotidienne
Un simple rsync nocturne vers une machine séparée (ou un bucket S3) copie les logs avant que logrotate ne les tourne. En cas de compromission, vous avez au moins la veille de l'incident intacte ailleurs.
# Crontab root, 2 h du matin tous les jours
0 2 * * * rsync -az /var/log/ backup@logs-archive.exemple.fr:/archive/$(hostname)/
Niveau 2 : centralisation temps réel
Les logs sont envoyés en continu vers un collecteur indépendant : rsyslog en mode remote, Graylog, Grafana Loki, Elasticsearch. L'attaquant qui prend le serveur web n'a déjà plus la main sur ce qui est parti. C'est le niveau recommandé dès qu'un site porte des données sensibles (santé, paiement, RH) ou à partir de quelques serveurs à surveiller.
Intégrité des logs
Un log modifiable par l'attaquant ne prouve plus grand-chose. Deux règles simples.
- Append-only : les logs ne doivent jamais être réécrits, seulement ajoutés en fin de fichier. Configuration par défaut d'Apache et rsyslog, mais vérifiez que personne ne « corrige » un log à la main.
- Collecteur indépendant : expédier les logs vers une machine qui n'est pas accessible depuis le serveur applicatif. Si vous hébergez un audit trail sensible (connexions admin, transactions), envisagez une chaîne de hash (hashchain) ou une signature périodique pour pouvoir prouver qu'aucune ligne n'a été retirée.
Configurer logrotate pour allonger la rétention
La config Apache par défaut sur Debian garde 4 semaines (rotate 4, rotation hebdo). Pour passer à 52 semaines sur l'access_log :
# /etc/logrotate.d/apache2-extended
/var/log/apache2/access.log {
weekly
rotate 52
missingok
compress
delaycompress
notifempty
create 640 root adm
sharedscripts
postrotate
if invoke-rc.d apache2 status > /dev/null 2>&1; then
invoke-rc.d apache2 reload > /dev/null 2>&1
fi
endscript
}
Testez la config sans attendre la prochaine rotation :
logrotate -d /etc/logrotate.d/apache2-extended # dry-run
logrotate -f /etc/logrotate.d/apache2-extended # forcer
Anonymisation partielle
Si vous voulez garder des access_logs longtemps (un an et plus) sans trimballer des données personnelles identifiantes, une astuce classique : tronquer le dernier octet des IPv4 après 3 mois. On garde l'intérêt statistique et géographique, on perd l'identifiant direct.
# Anonymise le dernier octet IPv4 dans un fichier de log
awk '{
sub(/^([0-9]+\.){3}[0-9]+/, substr($1, 1, length($1)-length($1)-1));
sub(/^([0-9]+\.[0-9]+\.[0-9]+)\.[0-9]+/, "\\1.0");
print
}' access.log.old > access.log.anon
Variante plus simple avec sed :
sed -E 's/^([0-9]+\.[0-9]+\.[0-9]+)\.[0-9]+/\1.0/' access.log.old > access.log.anon
Que chercher dans les logs : quelques grep utiles
Top IP qui attaquent wp-login
grep "POST /wp-login" /var/www/vhosts/exemple.fr/logs/access_ssl_log \
| awk '{print $1}' | sort | uniq -c | sort -rn | head -20
Codes 5xx groupés par URL
awk '$9 ~ /^5/ {print $9, $7}' access_ssl_log \
| sort | uniq -c | sort -rn | head -20
Tentatives SSH échouées des 7 derniers jours
journalctl -u ssh --since "7 days ago" | grep "Failed password" \
| awk '{print $(NF-3)}' | sort | uniq -c | sort -rn | head
Admins WordPress connectés ce mois-ci
# Si WP Activity Log est installé, export CSV depuis l'UI
# Sinon, en base via wp-cli
wp db query "SELECT user_login, meta_value AS last_login \
FROM wp_users u JOIN wp_usermeta m ON u.ID = m.user_id \
WHERE meta_key = 'session_tokens'"
Récapitulatif
- Les 4 familles à couvrir : web, applicatif, système, audit sécurité. Pas une de moins.
- Rétention : 6 à 12 mois pour l'accès HTTP, 12 mois pour l'auth, justifiée et documentée (RGPD).
- Ne gardez pas « au cas où » : trop conserver est aussi une infraction.
- Copie externe des logs au minimum quotidienne, centralisation temps réel dès que l'enjeu le justifie.
- Append-only, collecteur indépendant de la machine surveillée.
- Sur rétention longue, anonymisez le dernier octet IPv4 après 3 mois.
- Vous n'avez pas le temps de monter ça ? Ouvrez un ticket ServiceDesk, on s'en occupe en infogérance N2.