Toutes les protections vues jusqu’ici, nonces, échappement, capacités, permission_callback, agissent une fois que la requête est arrivée jusqu’au code PHP de WordPress. C’est déjà tard : chaque requête, même bloquée ensuite, a consommé du temps CPU, potentiellement révélé une information dans un message d’erreur, ou fait partie d’une salve de milliers de tentatives similaires. Un pare-feu applicatif et un outil comme fail2ban agissent en amont, avant ou pendant l’exécution, avec une logique complémentaire à celle du code.
Ces deux outils ne jouent pas le même rôle et sont souvent confondus. Comprendre leur différence permet de choisir la bonne combinaison selon l’infrastructure du projet, qu’il s’agisse d’un hébergement mutualisé, d’un VPS géré en direct ou d’une infrastructure derrière un CDN.
Ce qu’est un WAF, concrètement
Un WAF, ou Web Application Firewall, analyse chaque requête HTTP selon un ensemble de règles avant de la laisser atteindre l’application. Il peut fonctionner à deux niveaux : en amont du serveur, sous forme de service réseau ou de CDN comme Cloudflare, ou directement sur le serveur, sous forme de module comme ModSecurity avec le jeu de règles OWASP Core Rule Set.
Un WAF applicatif reconnaît des motifs caractéristiques d’une attaque : une tentative d’injection SQL dans un paramètre d’URL, une signature de scan automatisé, une charge utile typique d’une faille connue sur une extension WordPress populaire. Il bloque la requête avant même que WordPress ne la charge, ce qui économise des ressources serveur et referme certaines failles zero-day le temps qu’un correctif officiel sorte.
Les limites d’un WAF mal calibré
Un WAF trop strict génère des faux positifs : un client qui colle un texte contenant des guillemets et des apostrophes dans un formulaire de contact peut se voir bloqué parce que la requête ressemble, de loin, à une tentative d’injection. C’est pour cette raison que le déploiement d’un nouveau jeu de règles WAF mérite toujours une phase de test en mode détection seule avant le passage en blocage actif.

- Commencer en mode détection ou journalisation, jamais en blocage direct
- Surveiller les faux positifs pendant au moins une à deux semaines
- Exclure explicitement les routes REST légitimes qui manipulent du contenu riche, comme l’éditeur de blocs
fail2ban : bannir sur la répétition d’échecs
fail2ban fonctionne différemment : il surveille les fichiers de journal du serveur, repère un motif d’échec répété, comme plusieurs tentatives de connexion infructueuses sur wp-login.php en peu de temps, et bannit temporairement l’adresse IP source au niveau du pare-feu du système, généralement via iptables ou nftables.
# /etc/fail2ban/filter.d/wordpress-auth.conf
[Definition]
failregex = ^<HOST> .* "POST .*wp-login\.php.*" 200
ignoreregex =
# /etc/fail2ban/jail.local
[wordpress-auth]
enabled = true
port = http,https
filter = wordpress-auth
logpath = /var/log/nginx/access.log
maxretry = 5
findtime = 600
bantime = 3600
Ce type de règle repère une tentative de connexion, mais ne distingue pas nativement un succès d’un échec dans les journaux d’accès standards. En pratique, il est souvent plus fiable de journaliser les échecs de connexion directement depuis WordPress via le hook wp_login_failed, dans un fichier de log dédié que fail2ban peut surveiller avec un motif précis.
add_action( 'wp_login_failed', function ( $username ) {
error_log(
sprintf( '[wp-auth-fail] user=%s ip=%s', $username, $_SERVER['REMOTE_ADDR'] ),
3,
'/var/log/wordpress/auth-fail.log'
);
} );
Où placer chaque protection
Le WAF et fail2ban interviennent à des moments différents du cycle de vie d’une requête, ce qui justifie de les utiliser ensemble plutôt que l’un à la place de l’autre.
| Outil | Moment d’action | Bon pour |
|---|---|---|
| WAF | Avant l’exécution de PHP, requête par requête | Bloquer des motifs d’attaque connus, absorber un scan massif |
| fail2ban | Après répétition d’un comportement dans les journaux | Bannir une IP qui insiste sur wp-login.php ou XML-RPC |
Un banissement n’est jamais définitif ni infaillible
Une IP bannie par fail2ban peut appartenir à un réseau d’entreprise partagé par des dizaines d’employés légitimes, ou changer de main le lendemain sur un fournisseur d’accès qui pratique l’IP dynamique. C’est pourquoi la durée de bannissement (bantime) doit rester raisonnable, quelques heures dans la majorité des cas, et pourquoi une liste blanche d’adresses de confiance, comme celle du bureau ou de l’agence, évite de se bloquer soi-même un lundi matin.
Je recommande toujours de tester le bannissement sur sa propre IP en environnement de test avant de le déployer en production. Rien n’est plus frustrant que de se faire bannir de son propre site un vendredi à 18 heures.
En résumé
Un WAF filtre le contenu des requêtes selon des règles, fail2ban sanctionne un comportement répété observé dans les journaux : les deux interviennent avant que le code applicatif de WordPress ne soit sollicité, ce qui en fait un complément précieux à tout le travail de durcissement effectué dans le code lui-même. Aucun des deux ne dispense de corriger les failles à la source, mais ensemble, ils réduisent considérablement la surface d’attaque exposée au quotidien.