Hardening WordPress : filtrer le trafic indésirable avec un pare-feu applicatif

Quand on parle de hardening WordPress, on pense souvent à la surface “visible” : mises à jour, mots de passe solides, droits bien calés, plugins minimalistes. Tout cela compte énormément. Mais sur une vraie application web, le problème arrive rarement en premier là où on a l’habitude de regarder. Le plus souvent, c’est le trafic, avant même qu’il ne touche WordPress, qui décide de la journée.

Un pare-feu applicatif, c’est précisément ce garde-frontière applicatif. Il ne se contente pas de bloquer des requêtes “bizarres” au niveau réseau, il essaie de comprendre l’intention. Résultat, vous réduisez l’exposition aux attaques par requête (injections, probes de endpoints, tentatives de brute force déguisées), vous alliez propreté et performance, et vous rendez la vie plus compliquée aux scripts qui grattent votre site en continu.

Dans ce billet, je vais partir d’un constat opérationnel : la plupart des sites WordPress subissent déjà des volumes de trafic indésirable, même quand la console d’administration reste stable et que “tout semble fonctionner”. Le travail consiste à filtrer intelligemment, sans casser les parcours légitimes (API, formulaires, SEO, vérifications de services externes).

Le vrai rôle d’un pare-feu applicatif devant WordPress

WordPress, ce n’est pas seulement PHP qui s’exécute. C’est aussi une application avec des endpoints implicites, des schémas de requêtes attendus, des redirections, des cookies de session, parfois une API REST, et des plugins qui ajoutent leurs propres routes et paramètres.

Un WAF (Web Application Firewall) vise à distinguer, autant que possible, un trafic légitime d’un trafic “écrasé” par une intention hostile. Il ne cherche pas une perfection théorique. Il cherche une amélioration durable, avec une gestion claire des faux positifs.

Concrètement, un WAF examine la requête avant qu’elle n’atteigne PHP et WordPress. Selon votre architecture, il peut être placé :

    en amont via un reverse proxy, au niveau d’un service managé, ou intégré à votre stack serveur.

À partir de là, il applique des règles : détection de motifs (patterns), analyse de paramètres, normalisation de champs, contrôle de taille, parfois corrélation par session ou par adresse IP.

Le bénéfice immédiat, sur un WordPress “moyen” exposé au public, c’est la baisse de requêtes inutiles. Même si votre serveur peut encaisser, chaque requête représente un coût : CPU, I/O disque, logs, ralentissements ponctuels. Un WAF réduit le bruit.

Pourquoi le trafic indésirable persiste même avec de bonnes bases

J’ai vu des sites où WordPress était à jour, l’hygiène admin respectée, et pourtant les logs ressemblaient à une chasse au trésor. La sécurité ne décolle pas dès qu’un plugin est mis à jour. Les attaquants testent en permanence.

Ils scannent :

    des chemins classiques (wp-admin, wp-login, xmlrpc.php), des variantes d’URL, des paramètres dans des formulaires, des requêtes visant l’API REST, des tentatives de contournement via encodages.

Même quand vous ne l’avez jamais explicitement “exposé”, votre site répond quand même. Un serveur web est un miroir. Il renvoie des codes, il crée des délais, il laisse des indices dans les headers. C’est suffisant pour qu’un bot apprenne et adapte son pattern.

Un WAF joue ici le rôle de filtre avant la discussion. Il ne supprime pas votre responsabilité de maintenir WordPress et les plugins. Il réduit l’impact de ce qui passe malgré tout.

Choisir l’endroit du pare-feu : reverse proxy, service managé ou module

La décision la plus importante n’est pas “quel fournisseur”, c’est “où se place le traitement”.

Un WAF en reverse proxy (ou dans un load balancer) est souvent plus simple à intégrer. Vous gardez votre serveur applicatif concentré sur WordPress. La latence additionnelle existe, mais elle est généralement maîtrisable.

Avec un service managé, vous déléguez la partie intelligence (règles, mises à jour, optimisation). C’est pratique et efficace, mais vous devez accepter une dépendance externe, une logique de gestion de clés et un modèle de logs qui peut être différent de votre serveur.

Avec un module sur serveur (selon le logiciel, configuration plus fine), vous gardez un contrôle total, mais vous vous exposez à une charge de maintenance plus importante, notamment sur l’ajustement des règles et le tuning des faux positifs.

Dans tous les cas, l’important est de pouvoir :

Observer (voir ce qui est bloqué et pourquoi), Tester (mettre en mode permissif, puis durcir), Déployer avec discipline (pas en aveugle un jour de promo).

Les éléments du durcissement qui “travaillent ensemble” avec le WAF

Un WAF n’est pas une baguette magique. Il fait mieux son job quand l’application est cohérente. Les ajustements “autour” sont donc un investissement.

Par exemple :

    réduire la surface exposée de WordPress (désactivation d’API inutilisée, limitation de certaines fonctions), limiter les endpoints réellement nécessaires, utiliser des politiques de cookies et de sessions cohérentes, maîtriser les rôles et les droits (pour éviter que des tentatives “réussissent”), garder une hygiène de sécurité côté plugins (un plugin sur 20 peut introduire une route sensible).

Ce qui m’a le plus aidé sur des déploiements réels, c’est d’aligner le WAF sur le fonctionnement exact du site. Si votre formulaire de contact envoie un champ “message” très long, il peut déclencher des règles taille ou pattern. Si votre thème appelle l’API REST côté front pour une recherche interne, certaines règles trop agressives sur les paramètres peuvent casser la fonctionnalité. Le WAF doit suivre la réalité du https://gardewp.fr/securite-wordpress/ site, pas une fiction.

Mettre un WAF en place sans casser le site

Je vous propose une démarche prudente, qui limite les surprises.

Déploiement progressif en trois temps

D’abord, vous observez. Ensuite, vous appliquez. Puis vous durcissez.

Voici une approche que j’utilise quand je dois agir vite, tout en gardant le contrôle :

Activez le WAF en mode “monitoring” ou “détection” si disponible, pendant quelques jours, en collectant les raisons de blocage ou d’alerte. Créez une liste d’exceptions temporaires pour les parcours que vous savez indispensables (connexion, formulaires, API utilisées par le front, webhooks tiers). Passez à un mode “block” progressif, en commençant par des règles à faible risque et en laissant les règles sensibles en “log only”. Ajustez au fil des journaux, en confirmant chaque faux positif avec une vérification fonctionnelle côté navigateur, pas seulement via des tests unitaires. Une fois stable, durcissez les règles restantes et documentez les exceptions (qui, pourquoi, jusqu’à quelle date).

Le point clé ici, c’est la validation fonctionnelle. Un WAF peut bloquer une requête spécifique, mais l’impact réel se voit au niveau utilisateur. Et parfois l’impact n’apparaît pas tout de suite, par exemple sur des comportements asynchrones (chargement différé, requêtes déclenchées après un scroll, formulaires conditionnels).

Lire les logs WAF comme un enquêteur, pas comme un spectateur

Les journaux WAF sont votre meilleur levier. Regardez :

    l’horodatage (les pics coïncident-ils avec des campagnes de scan ?), le pays ou les plages IP (un bot peut venir de régions inattendues), les paths et paramètres impliqués, la “classe” de règle (injection, anomalie de requête, méthode inattendue, etc.), le verdict (log, challenge, block).

Un piège classique : se focaliser uniquement sur les requêtes bloquées. Les requêtes autorisées mais “suspectes” en mode monitoring sont parfois plus instructives. Elles montrent les patterns que vos règles ne voient pas encore comme malveillants, ou qui nécessitent une normalisation supplémentaire.

Sur un WordPress, j’ai déjà vu un “bruit” venir d’un plugin de galerie qui envoyait des paramètres très encodés. Les règles d’URL encoding et certains contrôles de caractère spécial se déclenchaient. Le site était “fonctionnel” parce que le navigateur réessayait, mais en arrière-plan, des requêtes échouaient, ce qui générait des erreurs de chargement et une augmentation du temps de page. Le WAF ne cassait pas totalement, mais il nuisait à l’expérience.

Votre objectif n’est pas seulement de bloquer. C’est de bloquer bien.

Quelles attaques un WAF réduit le plus souvent sur WordPress

Sans entrer dans une liste “catalogue”, on retrouve des catégories récurrentes :

    Tentatives d’exploitation via paramètres, par exemple des requêtes visant à injecter des charges dans des champs qui devraient contenir des identifiants simples. Reconnaissance d’endpoints sensibles, souvent répétée et automatisée (et parfois accompagnée de variations d’URL). Attaques par chaînes de requêtes anormales (method tampering, headers incohérents, encodages multiples). Exploitation des surfaces historiques liées à WordPress, notamment lorsque des endpoint sont accessibles et que les règles ne sont pas adaptés (un classic, c’est l’exposition d’anciens mécanismes si on n’a pas mis des contrôles additionnels).

Le gain le plus tangible, c’est souvent la réduction du volume avant même l’exécution de PHP. Vous sentez la différence dans les métriques serveur, et vous le voyez aussi dans la qualité de vos logs applicatifs, moins pollués.

Les faux positifs : comment les anticiper et les traiter proprement

Un WAF doit être agressif contre les patterns malveillants, mais pas au point de punir vos usages légitimes. Sur WordPress, les faux positifs arrivent le plus souvent sur :

    des formulaires (contenu riche, emojis, textes longs, champs avec URL), l’API REST (paramètres, filtres, requêtes côté front), des webhooks ou callbacks (headers et body encodés différemment), des plugins e-commerce ou réservation (paramètres de recherche, calculs, filtres).

Le traitement doit être discipliné. Si vous laissez une exception trop large, vous rendez le WAF inutile. Si vous supprimez une règle sans compréhension, vous perdez la protection et vous ne saurez pas pourquoi le problème revient.

Je conseille de raisonner “signature” plutôt que “site”. Autrement dit, vous limitez l’exception à un path et idéalement à un ensemble de conditions (méthode, endpoint, paramètres). Une exception “tout le domaine” est rarement acceptable.

Voici un exemple de type d’arbitrage que j’ai déjà fait sur un WordPress avec un formulaire très riche :

    Le WAF bloquait des requêtes avec certains caractères, à cause d’une règle d’analyse trop stricte. Le contenu “message” contenait des séquences qui ressemblaient à un encodage agressif. On a ajusté la règle pour le seul endpoint du formulaire, et on a aussi corrigé côté front le fait d’encoder certains caractères deux fois. Le résultat : moins de faux positifs, et une application plus saine.

Trois signatures de faux positifs fréquentes

    Requêtes POST vers un endpoint de formulaire dont le champ texte est long et contient des caractères spéciaux, parfois doublement encodés par une chaîne de scripts. Appels à l’API REST avec des paramètres de filtres qui déclenchent des patterns d’injection, surtout quand des requêtes sont construites dynamiquement côté navigateur. Webhooks de services tiers où le body est sérialisé autrement que ce que la règle attend, et où certains headers semblent “hors norme”.

Si vous gardez ces familles en tête, vous gagnerez du temps au premier tuning.

Cas pratique : réduire la charge sans impacter l’authentification

L’authentification est souvent la zone la plus sensible. Sur WordPress, on a wp-login, wp-admin, parfois des endpoints liés à l’API REST pour les interactions côté application. Un WAF peut aider, mais il peut aussi casser des flux si la configuration n’est pas alignée.

Une façon de faire raisonnable est d’utiliser le WAF pour le tri initial, tout en gardant une cohérence :

    règles de challenge ou de rate limiting sur les patterns de brute force, vérification stricte des méthodes et chemins, et surtout, une gestion des sessions sans surprise (cookies, redirections).

Dans mes déploiements, je préfère éviter une règle “bloquer tout ce qui ressemble à une injection” sur wp-login sans observation. Au lieu de ça, je commence par des règles à haut signal et bas risque, je surveille, puis je durcis.

Un WAF peut aussi réduire le bruit des tentatives de connexion sans toucher la légitimité. Par exemple, les bots n’utilisent pas la même cadence, ils activent rarement les mécanismes de session correctement, et leurs requêtes ont souvent des incohérences de headers. Ce sont des signatures que l’on peut exploiter sans faire sauter des utilisateurs réels.

Hardening WordPress : que faire des règles de “l’OWASP-like” ?

Beaucoup de WAF s’appuient sur des ensembles de règles influencés par des taxonomies comme OWASP. Le problème n’est pas la référence, c’est le fait que chaque site a sa propre réalité.

Deux recommandations issues du terrain :

Premièrement, séparez “attaque probable” et “attaque possible”. Certaines règles sont calibrées pour déclencher plus souvent, parfois au prix de faux positifs. Si votre objectif est d’abord la stabilité, démarrez avec un niveau de blocage modéré.

Deuxièmement, traitez les règles comme un produit à optimiser, pas comme une option à cocher. Une fois en production, vous devez pouvoir ajuster :

    les seuils, les exceptions, le comportement (log, challenge, block), l’agrégation d’événements (par IP, par session, par pattern).

Le WAF devient alors un outil d’apprentissage, qui s’adapte au fonctionnement de votre WordPress.

Performance et latence : le compromis réel

On parle souvent sécurité, rarement performance. Pourtant un WAF peut influencer la latence.

Sur un site WordPress, la latence perçue dépend de plusieurs facteurs : temps de génération PHP, cache, requêtes externes, base de données, et aussi le traitement amont. Un WAF ajoute une étape.

Dans la pratique, si votre WAF est bien configuré et que vous ne surchargez pas avec trop de règles coûteuses, la latence additionnelle est généralement acceptable. Le gain vient parfois par le fait que beaucoup de requêtes indésirables n’atteignent jamais PHP, donc elles coûtent moins cher que leur traitement applicatif.

Le point d’attention, c’est le “mode observation” et la volumétrie de logs. Si vous loguez trop, vous pouvez créer un goulet d’étranglement secondaire, soit côté stockage, soit côté pipeline de logs. Le WAF doit être observé, mais pas au point de transformer votre sécurité en charge.

Mon conseil : ajustez d’abord les décisions (log vs block), puis optimisez le niveau de logging une fois que vous avez identifié les patterns les plus utiles.

Un guide de configuration orienté “WordPress” (sans magie)

Chaque stack est différente, mais il y a des invariants. Un WordPress “standard” expose :

    wp-admin, wp-login, des endpoints de thèmes et plugins, éventuellement l’API REST.

Votre WAF doit comprendre vos endpoints légitimes. Par exemple, si vous avez besoin de l’API REST pour votre front, bloquez moins ou challengez plutôt sur les routes correspondantes, puis attachez des limites sur les paramètres sensibles.

Voici les ajustements que j’ai vus revenir le plus souvent en configuration concrète :

    Normaliser les règles selon le trafic réel. Si votre site a un trafic mobile majoritaire, vos patterns attendus sur les headers peuvent différer, mais les règles ne doivent pas être “adaptées au mobile”. Elles doivent être adaptées à la cohérence. Éviter les exceptions trop larges. Un exception globale sur l’ensemble des requêtes vers WordPress, c’est rarement justifiable. Mieux vaut cibler un path précis. Contrôler les tailles et les formats. Beaucoup de bots envoient des payloads absurdes. Les règles de taille et de format protègent sans coûter trop cher en tuning. Garder l’œil sur xmlrpc.php et les usages obsolètes. Si vous n’en avez pas besoin, il faut éviter l’exposition. Si vous en avez besoin, alors vos règles doivent être spécifiques et cohérentes avec ce besoin.

Ce sont des principes, pas des recettes. Mais ils évitent les erreurs qui reviennent régulièrement : “j’ai mis toutes les règles en block” et, deux heures après, plus de login.

Comment valider que ça marche (et que ça ne gêne pas)

La validation, c’est le moment où vous démontrez le gain. Vous ne voulez pas “voir des bloque” sans savoir si ça empêche un usage.

Je valide généralement en trois couches :

image

    vérification de navigation standard (pages, formulaires), vérification d’actions d’authentification (connexion, déconnexion), vérification des fonctionnalités dynamiques (recherche, formulaires asynchrones, chargement via API REST).

Ensuite, côté sécurité, je regarde :

    le volume de requêtes bloquées ou challengées, la baisse des requêtes “bruyantes” arrivées jusqu’à WordPress, la stabilité des erreurs applicatives (pas d’augmentation de 4xx/5xx côté utilisateurs).

Il faut aussi vérifier le comportement des outils externes : services SEO, connecteurs, monitoring uptime, et en particulier tout ce qui fait des requêtes vers votre domaine. Certains Uptime monitors ou services d’indexation peuvent déclencher des règles si leur User-Agent et leurs patterns ressemblent à du trafic automatisé. Le bon traitement, c’est une exception ciblée ou un ajustement de seuil, pas un “tout autoriser”.

Le piège du “tout bloquer” sur les règles sensibles

Quand on configure un WAF, on est souvent tenté de choisir le mode le plus strict. Le problème, c’est que WordPress, avec ses plugins, ses thèmes et ses formulaires, a une surface d’entrées variable. Plus vous bloquez, plus vous forcez des comportements imprévus.

Le bon rythme, c’est :

    durcir progressivement, corriger au niveau du site quand c’est du double encodage, des champs mal formatés, ou des requêtes mal construites, et uniquement ensuite ajuster les exceptions.

Sur un projet, j’ai rencontré un cas où un script de formulaire encodait deux fois certains caractères. Les règles WAF de type “obfuscation” se déclenchaient, et en forçant trop tôt, on a cassé le submit pour une partie des navigateurs. Quand on a corrigé l’encodage côté front, le nombre d’alertes a chuté, et on a pu durcir la politique sans exceptions longues.

C’est ce genre de correction qui transforme le WAF en allié plutôt qu’en frein.

Plan d’exploitation : garder le WAF utile dans la durée

Un WAF n’est pas une configuration figée. WordPress évolue, et avec lui les plugins, les formulaires, les endpoints. Un site qui était “propre” il y a six mois peut devenir “bruyant” aujourd’hui, soit à cause de mises à jour, soit à cause d’un nouveau plugin.

Pour garder une posture saine, je recommande de maintenir une petite routine opérationnelle :

    relire régulièrement les logs des verdicts “block” et “challenge”, repérer les nouvelles familles de faux positifs après une mise à jour plugin, documenter les exceptions, et faire une revue après chaque changement majeur (ajout de fonctionnalité, migration, changement de thème).

Si vous traitez le WAF comme un projet d’optimisation continu, vous évitez le scénario typique : au bout de quelques mois, tout est bloqué, puis vous neutralisez des règles entières en panique, et la protection retombe.

Ce que vous gagnez concrètement avec un pare-feu applicatif

Au-delà de la sécurité, le WAF agit comme un filtre anti-bruit. Moins de requêtes indésirables signifie :

    moins d’exécution inutile côté serveur, des logs plus lisibles, un temps serveur plus stable pendant les pics, et une meilleure capacité à diagnostiquer de vrais problèmes applicatifs.

Et surtout, vous réduisez le risque d’incident lié à des patterns d’attaque par requête. Le WAF ne remplace pas les correctifs WordPress, il réduit l’exposition à ce qui tente d’en profiter avant même que vous ne voyiez le problème.

Dans une démarche de hardening WordPress, le pare-feu applicatif est un investissement pragmatique. Il ne vous demande pas d’imaginer des scénarios abstraits. Il vous donne un levier tangible sur la réalité du trafic, celui que votre site reçoit vraiment.

Si vous avez déjà des logs WAF ou des métriques serveur, je peux aussi vous aider à interpréter ce que vous voyez, et à identifier quelles règles ajouter, lesquelles garder en monitoring, et où il faut faire du tuning fin pour respecter vos parcours légitimes.