L’énumération des utilisateurs, c’est le genre de faille qui ne “casse” pas forcément le site tout de suite, mais qui donne une longueur d’avance à quelqu’un de motivé. Le principe est simple: faire en sorte qu’un attaquant puisse déterminer si un compte existe, souvent en exploitant des différences de réponses HTTP, des messages d’erreur, ou des comportements d’une fonctionnalité WordPress. Une fois la liste d’adresses ou de pseudos validés, la suite est plus facile: tentatives de connexion ciblées, phishing plus crédible, ou attaques sur des services liés (réinitialisation, fuite d’annuaires, réutilisation de mots de passe).
Dans WordPress, l’énumération apparaît rarement comme un “bouton” évident. Elle naît plutôt de petites variations. Un formulaire indique qu’un identifiant est invalide mais “on sait” qu’il existe, un endpoint renvoie des structures de données, une URL renvoie une information utile au lieu de la même réponse pour tout le monde. La bonne stratégie consiste donc à réduire les indices et à limiter l’exploitation automatisée.
Ce que l’on appelle vraiment “énumérer” un utilisateur
Dans un contexte WordPress, l’énumération se produit quand un même scénario produit des résultats différents selon l’existence du compte. Typiquement:
- sur la page de connexion, le système réagit différemment selon que le login existe ou non; sur l’écran “mot de passe oublié”, le comportement dépend de l’adresse e-mail; sur le site public, certaines URL ou paramètres permettent de deviner un identifiant WordPress (auteur, ID, slug); via l’API (REST), des endpoints renvoient des informations sur les utilisateurs qui ne devraient pas être visibles.
À l’échelle d’un incident, cela se traduit par un gain de temps pour l’attaquant. Il n’a plus besoin de tester au hasard. Il peut aligner ses attaques sur une liste déjà validée.
Je garde en mémoire un cas où l’écart n’était même pas dans un message affiché, mais dans https://gardewp.fr/securite-wordpress/ le timing et les réponses d’une requête AJAX. Sur un site très chargé, la différence entre “compte inexistant” et “compte existant” était visible dans les logs applicatifs. L’attaquant n’avait pas besoin de deviner quoi que ce soit, il automatisait.
Pourquoi WordPress est concerné, même si “ce n’est pas une faille”
WordPress n’a pas été conçu pour résister au scénario “je teste 50 000 identifiants jusqu’à trouver les bons”. Historiquement, certaines actions ont été plus disertes qu’il ne fallait, notamment pour aider l’utilisateur légitime à comprendre ce qui se passe. Entre la UX et la sécurité, la frontière est fine.
Par exemple, quand un mot de passe oublié renvoie une information précise, ça aide l’utilisateur. Mais pour un attaquant, c’est une validation d’identité déguisée. Même lorsque WordPress a corrigé certains comportements au fil des versions, il reste des surfaces qui dépendent de la configuration, des plugins, et de la façon dont le thème et l’environnement (cache, proxy, CDN) traitent les réponses.
Autre point souvent sous-estimé: les plugins. Un module de formulaire peut réintroduire une différence de réponse. Un thème peut exposer une donnée via un template. Une intégration REST peut donner accès à des champs utilisateurs. L’énumération devient alors un problème de “comportement global” plus qu’un simple réglage WordPress core.
Les surfaces les plus utilisées pour l’énumération
Connexion et récupération du mot de passe
La connexion et la récupération du mot de passe sont les cibles les plus évidentes. La raison est pratique: elles manipulent directement un couple identifiant, et elles sont déclenchées par l’utilisateur légitime.
Le risque n’est pas seulement un message “mauvais identifiant” versus “mauvais mot de passe”. Même si le message est générique, des différences peuvent exister en arrière-plan: statut HTTP, contenu HTML, ou comportement des scripts front. Pour l’attaquant, tout ce qui varie est exploitable.
Pour le “mot de passe oublié”, l’idéal de sécurité ressemble à un principe simple: quelle que soit l’existence de l’adresse, la réponse doit être identique, et la même action doit être exécutée ou simulée sans divulguer un résultat.
Paramètres d’URL liés aux auteurs
Beaucoup de sites WordPress affichent des pages auteur ou des archives qui reposent sur des identifiants internes. Selon la configuration, un visiteur peut accéder à des pages d’auteur à partir de paramètres du type ?author=ID ou de variantes similaires. Même si ces pages ne contiennent pas de données sensibles, elles peuvent confirmer l’existence d’un compte, et souvent un identifiant réutilisable (nom, pseudo, slug).
Le problème n’est pas uniquement la page elle-même. C’est le signal. L’attaquant peut parcourir des IDs et détecter lesquels “répondent”.
XML-RPC et endpoints annexes
XML-RPC a historiquement servi de pont pour des opérations. S’il est accessible sans restrictions adaptées, il peut devenir une surface d’attaque pour des tentatives répétées et des comportements différents. La priorité est de réduire l’exposition et d’ajouter une couche anti-abus.
Je recommande rarement de ne rien faire “au prétexte que ça marche”. En pratique, les sites qui n’utilisent pas XML-RPC gagnent souvent à le désactiver. Ceux qui en dépendent doivent compenser par du filtrage, des règles de rate limit et un filtrage strict des méthodes autorisées.
REST API (wp-json) et exposition d’utilisateurs
L’API REST est un excellent outil pour les développeurs, mais c’est aussi un endroit où les permissions mal réglées peuvent provoquer de l’énumération. Un endpoint peut renvoyer des listes, des IDs, des noms, des URL de profils, voire des champs additionnels.
Le risque augmente si:
- vous avez activé des schémas personnalisés ou des extensions REST; des rôles et permissions sont étendus sans contrôle; des caches inverses ou des CDN mettent en cache des réponses qui ne devraient pas l’être, en les rendant accessibles à des requêtes non autorisées.
Le meilleur réflexe consiste à vérifier ce que l’API renvoie “en anonyme”, sans cookies et sans token, et à comparer ce qui est renvoyé selon l’existence d’un utilisateur.
Réduire l’indice, sans casser l’expérience
On peut résumer la stratégie en une phrase: le site doit répondre de la même façon, dans les mêmes formats, avec la même latence perçue, quel que soit l’état réel du compte. Évidemment, atteindre une égalité parfaite est difficile en production. Mais on peut s’en rapprocher avec des mesures concrètes.
Le point important est de traiter à la fois:
1) les messages et rendus visibles; 2) les statuts HTTP et contenus renvoyés; 3) les endpoints et permissions; 4) l’abus automatisé.
Même si vos messages sont génériques, une différence de statut ou de structure de réponse peut suffire à l’attaquant. Et même si tout est uniformisé, l’attaque de force brute reste rentable si vous n’avez ni limitation ni détection.
Mesures pratiques côté WordPress
1) Uniformiser les réponses sur les actions sensibles
L’objectif sur la connexion et la récupération du mot de passe est de ne jamais “confirmer” qu’un identifiant existe.
Sur WordPress, il existe des mécanismes dans le core qui tendent vers ce comportement. Mais selon votre thème, vos plugins et votre configuration, vous pouvez encore avoir des variations. En pratique, la manière la plus robuste que j’ai vue en production consiste à utiliser une mesure dédiée (souvent un plugin de durcissement) et à vérifier ensuite, avec un outil de test, que les réponses restent alignées.
Un test simple, que j’utilise pour vérifier, consiste à envoyer plusieurs requêtes avec deux identifiants différents, un compte existant et un autre non existant, et à comparer:
- le statut HTTP; une portion du HTML renvoyé (même si la page est identique, la structure peut changer); le log applicatif (en interne) pour repérer un comportement divergence.
Vous ne cherchez pas la sécurité “théorique”, vous cherchez la sécurité “observée” de l’extérieur.
2) Restreindre l’information via l’API REST
Pour l’API REST, la règle de base est de limiter l’accès à ce qui est nécessaire. En anonyme, l’API peut exposer davantage que ce que vous imagineriez au premier coup d’œil, surtout si un plugin ajoute ses propres routes.
Deux approches coexistent en général:
- limiter l’accès par permissions sur les routes exposées; filtrer et réduire le contenu renvoyé pour les endpoints sensibles.
Dans un projet réel, j’ai déjà vu un endpoint custom qui listait des utilisateurs pour une fonctionnalité “recherche d’auteur” côté front. Le développeur pensait que la route était “inoffensive” parce qu’elle affichait seulement le nom. Pour l’attaquant, c’était une API d’énumération.

La bonne démarche n’est pas seulement de “désactiver l’API”, mais de l’inspecter. Regardez ce qui est accessible sans authentification et vérifiez les routes qui touchent à des données utilisateur.
3) Éviter l’exposition des pages auteur et des archives d’ID
Selon votre configuration, l’énumération via les pages auteur peut être freinée en appliquant une logique qui empêche l’accès public à certaines variantes basées sur l’ID interne. Dans le monde WordPress, la façon la plus durable est d’aligner vos paramètres de visibilité et votre modèle de thème, puis de tester l’accès direct.
Si vous ne voulez pas que des pages auteur existent, ou si elles n’apportent pas de valeur, vous pouvez les limiter. Si vous en avez besoin, vous pouvez au minimum vous assurer que les réponses ne révèlent pas d’information utile quand l’ID ne correspond à rien.
4) Bloquer l’excès de tentatives, rate limiting et filtrage
L’énumération est souvent couplée à l’abus. Même si vos messages sont parfaits, si quelqu’un peut envoyer des milliers de requêtes sans friction, il peut reconstruire l’information via des micro différences. En pratique, la couche “anti-bruteforce” et la limitation de débit font souvent la différence entre un risque théorique et un risque exploitable.
Vous pouvez mettre cette couche à plusieurs niveaux:
- côté serveur (reverse proxy, règles WAF); côté application (durcissement WordPress, plugins d’abus); côté réseau (CDN, règles géographiques si c’est pertinent).
Le trade-off est réel: un rate limit trop agressif peut bloquer vos utilisateurs légitimes, notamment sur des environnements mobiles instables, ou si vous avez des pics de trafic. J’ai déjà vu des hébergeurs ou des reverse proxies déclencher des blocs “en cascade” lors d’une mise à jour, ce qui a rendu la recherche d’erreurs pénible. Il faut tester, puis ajuster.
Une checklist de vérification rapide (sans changer tout le site)
- Tester login et mot de passe oublié avec un compte existant et un compte inexistant, comparer statut HTTP et rendu. Vérifier ce qui est accessible à wp-json sans authentification, surtout les routes liées aux utilisateurs. Contrôler l’accès aux pages auteur, y compris les comportements via paramètres d’ID. Mettre en place une limitation de débit pour les endpoints de connexion et de récupération.
Plugins et durcissement: utile, mais pas magique
Un plugin de sécurité peut réduire l’énumération. Il peut aussi ajouter:

- des messages plus neutres; des protections sur les formulaires; des règles pour l’API et des contrôles sur l’accès.
Mais je pars toujours d’une règle personnelle: un plugin n’est utile que s’il est testable dans votre environnement. Un plugin peut corriger un point, puis un autre plugin réintroduit une différence sur la page de login ou sur le formulaire de récupération. Ou bien votre proxy inverse peut modifier les en-têtes et les caches, rendant votre test invalide.
Le bon réflexe, c’est d’installer, tester, mesurer. Une fois qu’un durcissement est en place, refaites les comparaisons de réponses externes avant d’annoncer “c’est réglé”.
Edge cases: quand l’énumération passe par un détail
Il existe des cas où l’utilisateur n’est pas énuméré directement par une route d’API, mais via des détails annexes.
Caching et contenu mis en cache
Un exemple fréquent: une page ou un endpoint renvoie un gabarit qui contient parfois des fragments différents selon un paramètre. Si un CDN ou un cache met en cache une réponse partiellement, vous pouvez créer une “fuite” très concrète. L’attaquant n’a pas besoin d’un message. Il observe ce que le cache sert.
Sur WordPress, un cache bien configuré devrait varier selon les paramètres pertinents, mais les setups “hybrides” (cache côté serveur, plugin de cache, reverse proxy) peuvent introduire des incohérences.

Internationalisation et variantes de messages
Si vos pages ont des traductions différentes selon l’état du compte, vous pouvez révéler un détail. Ce n’est pas le message en lui-même qui est dangereux, c’est l’existence d’une branche.
La défense, c’est l’uniformisation complète, y compris le contenu rendu. Je l’ai observé sur des sites multilingues où la logique de récupération était “quasi identique” mais pas parfaitement alignée: l’attaquant a exploité la différence sur un langage spécifique.
Scripts front et messages AJAX
Même si la page globale affiche un message neutre, un script front peut lire une réponse JSON et afficher un état différent. Dans ce cas, l’énumération passe côté navigateur. C’est facile à rater si vous ne testez qu’au niveau “copier-coller du formulaire” sans regarder les requêtes réseau.
Désactiver des fonctionnalités: quand ça aide, quand ça gêne
Beaucoup d’administrateurs veulent une réponse simple: “désactive tout ce qui est exposé”. C’est tentant. Mais il faut gérer le coût fonctionnel.
Pour XML-RPC, par exemple, désactiver peut être parfaitement adapté à un site qui n’utilise pas de clients distants. Pour un site avec des outils externes, ça peut casser une fonctionnalité ou dégrader des intégrations.
Pour l’API REST, c’est similaire: certaines applications front, des dashboards, ou des intégrations marketing peuvent dépendre d’appels REST. Couper “en dur” peut casser des parcours, et déclencher des erreurs qui deviennent elles-mêmes des indices.
Voici comment je raisonne en pratique, en pesant impact et bénéfice.
| Option | Bénéfice pour l’énumération | Risque principal | |---|---|---| | Uniformiser login et récupération | Réduit les indices visibles et la confirmation | Peut compliquer le support si les erreurs sont trop neutres | | Restreindre routes REST sensibles | Diminue la surface d’énumération externe | Peut casser des plugins ou des intégrations | | Désactiver XML-RPC si non utilisé | Réduit une surface d’attaque et d’abus | Peut gêner des usages distants existants | | Rate limiting/WAF sur endpoints | Rend l’énumération massivement moins rentable | Faux positifs possibles si mal calibré |
Et concrètement, que surveiller dans vos logs ?
Une approche mature consiste à surveiller des signaux, pas uniquement à corriger. Cherchez des patterns d’automatisation autour de login, mot de passe oublié, et endpoints API.
Sans entrer dans une liste trop longue, je propose une idée centrale: si vous voyez des rafales sur une seule IP, des variations rapides d’identifiants, ou des requêtes à fort volume sur des routes connexes, vous avez probablement un début d’énumération ou de force brute.
L’idéal est de conserver des traces suffisantes pour distinguer:
- tentatives de login, d’un utilisateur réel; tests de reconnaissance automatisés; requêtes REST anormales; appels répétés sur pages auteur ou routes similaires.
Cette visibilité aide aussi à calibrer le rate limiting. Si vous bloquez “au hasard”, vous risquez de nuire à vos vrais visiteurs.
Un piège courant: croire que “WordPress est à jour” suffit
Mettre WordPress à jour est indispensable. Mais l’énumération peut venir de plusieurs sources:
- un plugin installé après la mise à jour; un changement de thème; une configuration de serveur, proxy ou cache; une règle WAF mal conçue qui modifie le comportement; un endpoint custom ajouté par un développeur.
J’ai déjà rencontré des sites où la version WordPress était récente, mais un plugin de formulaire réintroduisait une différence de réponse sur la récupération. Le formulaire renvoyait un code interne distinct et le frontend affichait un état légèrement différent. L’attaquant, lui, avait automatisé un test.
Donc la démarche la plus solide est un cycle: corriger, tester, vérifier la surface, puis seulement généraliser.
Le point de friction: “trop neutre” pour les utilisateurs
Un autre compromis à anticiper, c’est le support et l’expérience. Si vous rendez la récupération du mot de passe totalement identique pour tous les cas, les utilisateurs légitimes peuvent avoir plus de difficulté quand ils font une erreur d’e-mail, ou quand ils n’ont pas accès à leur boîte mail.
La réponse n’est pas de réintroduire des indices “compte existe ou non”, mais de guider autrement. Par exemple, vous pouvez garder une page neutre, tout en fournissant des explications générales sur la vérification de l’adresse e-mail, le contrôle des filtres anti-spam, ou la vérification des délais.
En pratique, le bon équilibre consiste à ne jamais confirmer un compte, tout en expliquant le parcours utilisateur sans rendre la réponse conditionnelle à l’existence.
Plan d’action raisonnable pour un site WordPress “en production”
Si vous cherchez une séquence pragmatique, elle peut ressembler à ceci en prose: commencez par tester l’état actuel. Prenez un compte existant et un compte inexistant, et mesurez ce que le système renvoie pour la connexion et la récupération, en regardant le code de statut et le contenu. Ensuite, inspectez wp-json depuis un contexte anonyme, vérifiez les routes relatives aux utilisateurs, et contrôlez l’accès aux pages auteur ou aux archives basées sur un identifiant. Enfin, ajoutez une couche anti-abus avec un filtrage au niveau approprié, et calibrez sur vos logs pour éviter les faux positifs.
Ce cycle évite un autre piège: installer des “réglages de sécurité” sans comprendre ce qu’ils changent réellement, puis passer à côté d’un endpoint oublié.
Vérifier l’effet réel: tests que vous pouvez refaire facilement
À un moment donné, ce qui compte est ce que quelqu’un observe de l’extérieur.
Je recommande de garder une petite routine de test, répétable, même si vous ne faites qu’une fois par mois. Vous pouvez:
- comparer les réponses HTML ou JSON sur les endpoints sensibles; vérifier si les statuts HTTP restent stables; mesurer si les endpoints API répondent toujours pareil pour des utilisateurs inexistants.
Si vous utilisez un outil d’audit ou un simple script maison, l’idée est d’avoir une base. Ensuite, vous pouvez déployer un correctif, puis refaire la comparaison pour constater l’écart.
La sécurité, ici, est surtout de la cohérence.
Conclusion fonctionnelle, sans slogans
Empêcher l’énumération des utilisateurs dans WordPress, ce n’est pas une seule case à cocher. C’est un travail de réduction d’indices sur plusieurs surfaces, et une défense contre l’automatisation. La connexion et la récupération du mot de passe sont des points centraux, mais l’API REST, les pages auteur, XML-RPC et même des plugins “invisibles” peuvent reintroduire des différences.
Le meilleur indicateur de réussite, c’est simple: quand vous testez depuis l’extérieur, un compte existant et un compte inexistant doivent produire des réponses suffisamment identiques pour que l’attaquant ne puisse pas confirmer une hypothèse. Et quand la réponse est identique, il faut encore rendre la répétition coûteuse, avec du rate limiting et une surveillance active.
Si vous voulez, donnez-moi votre configuration (version de WordPress, plugins de sécurité ou de cache, et si vous utilisez l’API REST ou des intégrations), et je peux vous proposer une approche ciblée, avec les points de test prioritaires pour votre cas.