WordPress donne vos identifiants aux attaquants. Voici comment fermer la porte.
Retour d'expérience après une campagne ciblée : pourquoi WordPress expose vos logins par défaut, et un plugin open-source (MIT) pour y mettre fin.
- Une attaque par force brute a besoin d'un identifiant ET d'un mot de passe — WordPress offre l'identifiant gratuitement, par quatre canaux par défaut.
- L'énumération ?author, l'endpoint REST users, le formulaire de mot de passe oublié et les messages d'erreur de connexion confirment tous quels comptes existent.
- Un plugin open-source léger ferme les quatre, sans réglages, sans table en base et sans impact mesurable sur les performances.
En avril 2026, un site WordPress en production que je maintiens s'est fait viser par une campagne d'attaque ciblée — des milliers de tentatives coordonnées sur plusieurs jours, pas un balayage automatique anodin.
En remontant les logs, ce n'est pas la force brute qui m'a frappé. C'est ceci : l'attaquant n'a jamais eu à deviner les identifiants. WordPress les lui a donnés.
Une attaque par force brute a besoin de deux ingrédients : un identifiant et un mot de passe. On s'obsède pour le second (mots de passe forts, 2FA, fail2ban) et on oublie le premier — alors que WordPress le diffuse par défaut, par plusieurs canaux.
Pourquoi WordPress fuit vos identifiants par défaut
Vous pouvez tester chacun de ces points sur votre propre site, maintenant. Chacun est un indice offert à l'attaquant avant même d'essayer le moindre mot de passe :
- Énumération d'auteurs : ouvrez /?author=1. Si vous êtes redirigé vers /author/un-identifiant/, un login valide vient de fuiter. En itérant ?author=2, ?author=3, on récolte tous les comptes.
- Liste des utilisateurs via l'API REST : /wp-json/wp/v2/users renvoie la liste des comptes — identifiant et slug compris — à n'importe quel visiteur anonyme.
- Formulaire de mot de passe oublié : il confirme l'existence d'un compte (message différent selon le cas) et envoie un vrai email à chaque soumission, ce qui en fait à la fois une fuite d'information et un vecteur de harcèlement.
- Messages d'erreur de connexion : « identifiant inconnu » contre « mot de passe incorrect » suffit à confirmer quels logins existent.
Le fil rouge est simple : on ne peut pas forcer un identifiant qu'on n'a pas trouvé. Fermez ces quatre portes et vous supprimez l'étape de reconnaissance qui rend toute la chaîne d'attaque possible.
Ce que fait le plugin
J'ai écrit un petit plugin qui ferme exactement ces quatre vecteurs. Pas de page de réglages, pas d'écran d'options, pas de table en base — seulement des transients de 15 minutes pour le rate limit :
- /?author=N renvoie un 404 sec au lieu de rediriger vers l'archive d'auteur.
- /wp-json/wp/v2/users renvoie 401 pour les visiteurs anonymes, tout en restant accessible aux utilisateurs connectés.
- Le formulaire de mot de passe oublié est plafonné à 5 tentatives par 15 minutes par IP, avec une réponse identique que le compte existe ou non.
- Les erreurs de connexion sont réduites à un message générique unique, qui ne confirme plus aucun identifiant valide.
Il fonctionne en mono-site et multisite, WordPress 5.x et plus, PHP 7.4 et plus. On l'active, c'est protégé : il n'y a rien à configurer.
Les résultats
Sur un seul site, après déploiement, sur 23 jours :
- 36 127 tentatives d'énumération bloquées.
- 4 842 adresses IP distinctes impliquées.
- 0 identifiant exposé via les quatre vecteurs ci-dessus.
Ce que ce plugin ne fait PAS
Vendre une fausse tranquillité est pire que pas de plugin du tout, alors voici le périmètre honnête :
- Il ne rate-limite pas wp-login.php lui-même. Le brute-force massif sur la page de connexion se traite au niveau serveur (fail2ban, WAF). Ce plugin ferme l'étape de reconnaissance, en amont.
- Derrière un proxy ou un CDN (Cloudflare et consorts), REMOTE_ADDR est l'IP du proxy : le rate limit du mot de passe oublié devient global au lieu d'être par-visiteur, tant que vous n'avez pas restauré la vraie IP côté serveur.
- Le blocage de l'endpoint REST des utilisateurs cassera les sites headless, ou les extensions qui dépendent d'un accès anonyme à cet endpoint.
L'installer en deux minutes
Le plugin est publié sous licence MIT. Deux façons de l'installer :
- Depuis l'admin WordPress : téléchargez le ZIP, téléversez-le dans Extensions > Ajouter, puis activez. À l'activation, il s'installe en mu-plugin (must-use) : il devient indésactivable depuis l'admin, même par un compte compromis.
- Manuellement : copiez le fichier mu-plugin unique dans wp-content/mu-plugins/ — aucune activation nécessaire.
Voir le code source sur GitHub
Lisez le code, auditez-le, forkez-le. Il est assez court pour être relu en quelques minutes — exactement ce que vous devriez exiger de tout ce qui touche à votre flux de connexion.
Fermez la porte avant qu'on touche la poignée
L'énumération des identifiants n'est pas une attaque sophistiquée — c'est un fruit à portée de main que WordPress laisse en évidence. La version, les archives d'auteur, l'API REST, le formulaire de mot de passe : tous confirment discrètement qui peut se connecter.
Les fermer demande un plugin léger et zéro configuration. Si vous gérez des sites WordPress, c'est un changement de cinq minutes qui supprime la toute première étape sur laquelle repose chaque campagne de force brute.