Sur un site WordPress professionnel, la sécurité ne se résume pas à un plugin de plus. Elle passe par une hygiène de configuration, une réduction des surfaces d’attaque et une politique claire sur ce qu’on autorise ou non. Le fichier .htaccess, côté Apache, peut contribuer de manière très concrète, surtout pour limiter les actions “évidentes” et réduire la quantité d’informations exposées.
Je le dis sans dramatiser: bien réglé, .htaccess n’élimine pas tous les risques. Il rend en revanche certaines attaques plus difficiles, moins automatisables, et il améliore la robustesse contre des comportements nuisibles, y compris quand le reste du stack est perfectible.
Dans ce billet, je vais me concentrer sur des règles réalistes et utilisables, avec les compromis à connaître avant de copier-coller.
Ce que fait vraiment .htaccess dans un site WordPress
Le fichier .htaccess est un mécanisme de configuration Apache chargé par le serveur au niveau d’un répertoire. Sur WordPress, il sert souvent à:
- gérer le “rewrite” pour les URLs propres (permalinks); contrôler l’accès à certains dossiers; filtrer des requêtes et des méthodes HTTP; ajouter des en-têtes de sécurité (selon les cas); réduire certaines traces côté webserver.
Le point clé: .htaccess n’est pas un bouclier magique. Si une application a une faille logique, une règle de réécriture ou de blocage ne règlera pas le problème. Mais si quelqu’un essaie d’attaquer “comme sur tous les autres sites”, .htaccess peut casser l’automatisation.
Autre nuance importante: sur certains hébergeurs, le fichier AllowOverride peut limiter ce qui est autorisé. Si des directives semblent ignorées, ce n’est pas forcément votre faute. D’où l’intérêt de valider en test, puis en production.
Avant de toucher: sécuriser la mécanique de base (et éviter le casse-tête)
WordPress dépend beaucoup des règles de réécriture pour que tout fonctionne. La première erreur classique, c’est d’ajouter des directives au mauvais endroit ou de remplacer les blocs existants. J’ai déjà vu des sites où un bloc ajouté pour “bloquer les fichiers sensibles” a cassé le chargement de polices, ou a interrompu l’accès à /wp-admin/admin-ajax.php.
Avant toute modification, je fais systématiquement trois choses:
Je prends une copie du .htaccess en place. Je teste sur une URL de staging si possible. Je roule par petites étapes, une famille de règles à la fois, pour pouvoir identifier la cause en cas de régression.Si vous ne pouvez pas faire de staging, privilégiez au minimum une fenêtre de maintenance courte et des logs bien lisibles. WordPress se prête mal au “je modifie tout et on verra”.
Règles “fondation”: empêcher l’accès direct à des fichiers sensibles
WordPress laisse parfois des fichiers ou des dossiers utiles pour l’administration mais inutiles au grand public. Selon votre configuration, ces fichiers ne sont pas toujours protégés par défaut, ou ils peuvent exposer des informations en fonction des droits. Le but n’est pas de “cacher tout”, mais de fermer ce qui est inutile.
Sur un site standard, vous pouvez bloquer l’accès direct aux fichiers de configuration et à certains emplacements d’admin. Voici un bloc typique, à adapter:
# Bloquer l'accès direct aux fichiers sensibles (à ajuster selon l'arborescence) Require all denied # Bloquer les fichiers de sauvegarde WordPress courants Require all denied # Bloquer l'accès direct aux dossiers de configuration fréquents Require all deniedIci, je marque une limite: le dernier bloc tel quel n’a pas de sens isolé, il faut plutôt cibler un dossier précis. Je le laisse volontairement comme exemple de prudence: tout bloc doit correspondre à un chemin réel. Dans la pratique, vous ciblerez plutôt des répertoires comme wp-config.php ou certains dossiers de logs si vous en avez.
Une règle plus directe et sans ambiguïté est celle ci-dessous, pour les fichiers critiques:
Require all denied Require all denied Require all deniedRemarque de terrain: sur certains hébergeurs, .htaccess est déjà correctement géré. L’intérêt de la règle est surtout de renforcer la cohérence.
Protection contre l’énumération et les attaques opportunistes
Les scans automatisés détestent les serveurs qui répondent de façon “informatrice”. WordPress expose parfois des points d’entrée évidents, comme xmlrpc.php, ou des comportements qui permettent de deviner la présence de certains plugins. On peut aussi réduire certaines réponses.
XML-RPC: quand le fermer est logique
xmlrpc.php sert à des fonctionnalités comme l’API distante WordPress, et certains outils tiers. Si vous n’utilisez pas ces fonctions, le fermer peut réduire le bruit des attaques de bruteforce et les tentatives de ping.
Une version prudente:
Require all deniedCompromis: si vous utilisez un client externe qui dépend de XML-RPC, vous allez casser la synchro. Avant de désactiver, vérifiez le besoin réel.
Désactiver les méthodes inutiles
Dans le monde WordPress, les navigateurs ne font pas de PUT ou de DELETE “normaux” sur les pages publiques. Refuser explicitement ces méthodes peut aider contre certains scénarios. Gardez l’approche raisonnable, parce qu’un plugin ou un mécanisme de upload peut dépendre de comportements spécifiques.
Un exemple:
Require all deniedCette règle n’est pas universelle. Sur certains environnements, elle peut nuire à des endpoints spécifiques, par exemple si vous utilisez des webhooks ou des intégrations particulières. Testez, et gardez une méthode de retour arrière.
Réduction de l’exposition via les en-têtes
Les en-têtes HTTP, c’est du “petit détail” qui finit souvent par se voir. Ce ne sont pas des règles .htaccess au sens strict de blocage d’accès, mais elles améliorent la défense en profondeur, notamment contre certaines attaques de type script injection et clickjacking.
Selon votre stack Apache, vous pouvez ajouter:
# Clickjacking Header always set X-Frame-Options "SAMEORIGIN" # MIME sniffing Header always set X-Content-Type-Options "nosniff" # Désactivation du sniffing et contrôle de referer Header always set Referrer-Policy "strict-origin-when-cross-origin"Ici, je privilégie une approche prudente: mieux vaut quelques en-têtes bien choisis que dix lignes copiées qui entrent en conflit avec un thème, un proxy, ou un CDN.
Pour Content-Security-Policy (CSP), on peut aussi en ajouter via .htaccess, mais c’est plus délicat. Une CSP trop stricte peut casser des scripts, des trackers, ou des éléments chargés dynamiquement. Sur un site professionnel, on la met souvent en place après audit, en commençant en mode “report-only” si possible.
Limiter l’accès à wp-admin et wp-login: méthode “pro”
Restreindre l’accès à wp-login.php et certaines pages d’admin réduit énormément le bruit des attaques. Mais il faut respecter un principe simple: si vous bloquez, vous bloquez aussi les vrais utilisateurs. Donc on applique une restriction basée sur IP, sur un second facteur, ou via un accès protégé au niveau serveur.

Sur Apache, une méthode courante est le blocage par IP. Le schéma est robuste, mais exige une liste d’adresses fiable.
Exemple conceptuel, à personnaliser:
# Exemple: restreindre wp-login.php à une plage IP Require ip 203.0.113.10 Require ip 198.51.100.0/24Compromis: dès que vous changez d’IP (VPN, mobile, télétravail), l’accès peut devenir pénible. Sur un site “professionnel”, je recommande de centraliser ça avec un reverse proxy ou une solution d’authentification en amont, plutôt que de maintenir des IP dans .htaccess à la main. Mais si votre environnement est stable, ça marche très bien.
Une autre approche utile est de restreindre certains accès sensibles, tout en laissant le reste public. En pratique, vous ciblerez des fichiers comme wp-login.php et parfois wp-admin/admin-ajax.php selon votre usage, mais là encore, c’est plus risqué: beaucoup de fonctionnalités front reposent sur admin-ajax.php.
Désactiver l’exécution PHP dans des dossiers uploadés
Le cœur de ce sujet, c’est le scénario où un attaquant réussit à uploader un fichier malveillant. Sur WordPress, les uploads finissent souvent dans wp-content/uploads/. Le bon réflexe consiste à empêcher l’exécution PHP dans ces dossiers.
Sur Apache, on peut utiliser une règle qui force le traitement non exécutable des fichiers. L’idée typique:
Require all deniedMais appliquée trop largement, cette règle casserait WordPress (beaucoup de fichiers PHP doivent être exécutés). La bonne approche consiste à la limiter à uploads:
Require all deniedLe point pratique: le chemin exact dépend de votre hébergement. Et si vous utilisez une structure différente, adaptez. Sur un hébergeur managé, il arrive aussi que l’exécution PHP dans uploads soit déjà empêchée au niveau global, auquel cas ces règles sont redondantes.
Si vous hésitez, vérifiez d’abord le comportement actuel: essayez de charger un fichier PHP inoffensif dans uploads et observez la réponse. Attention, faites cela sur un environnement de test, et pas en production avec des scripts “bizarres”.
Bloquer les tentatives sur des chemins sans intérêt pour WordPress
Les scanners balancent souvent des requêtes sur des chemins universels: /.env, /wp-content/uploads/, des variants de .git, ou des ressources inventées. On peut réduire la surface en renvoyant 404 ou en refusant.
Voici un bloc que j’utilise souvent, à adapter au contexte:
# Refus fichiers fréquemment scannés RedirectMatch 404 ^/\.env RedirectMatch 404 ^/\.git RedirectMatch 404 ^/\.svn RedirectMatch 404 ^/composer\.json$ RedirectMatch 404 ^/vendor/Important: selon votre serveur et votre stratégie, RedirectMatch peut déclencher des comportements différents. L’objectif est surtout de ne pas donner une réponse “utile”. Si vous préférez, vous pouvez remplacer par des règles de type RewriteRule ou Require all denied ciblées.
WordPress, thèmes, plugins et fichiers statiques: attention à la casse
Les thèmes modernes et les plugins premium chargent souvent des assets via des mécanismes d’URL variés, et certains utilisent des endpoints. J’ai déjà vu des règles “anti hotlink” mal placées ou des restrictions trop agressives qui bloquent des polices depuis un CDN, ou des scripts depuis admin-ajax.php.
C’est pour ça que je préfère une stratégie en couches:
- d’abord, fermer ce qui est objectivement inutile (fichiers sensibles, xmlrpc si pas utilisé); ensuite, réduire l’exposition aux endpoints sans casser le site (en évitant de toucher au rewrite de permaliens); enfin, ajouter des en-têtes et des protections complémentaires, en observant les logs.
Un exemple de configuration cohérente (à intégrer avec prudence)
Voici une base “raisonnable” qui respecte l’idée de ne pas casser WordPress. Elle ne remplace pas votre bloc rewrite WordPress, elle s’ajoute plutôt en haut ou en bas du fichier, selon les recommandations de votre hébergeur. Sur beaucoup de sites, l’ordre compte.
# Sécurité basique, sans toucher au cœur du rewrite WordPress Require all denied Require all denied # Empêcher l'accès direct à des fichiers sensibles Require all denied # Méthodes HTTP inutiles Require all denied # En-têtes de sécurité simples Header always set X-Frame-Options "SAMEORIGIN" Header always set X-Content-Type-Options "nosniff" Header always set Referrer-Policy "strict-origin-when-cross-origin"À partir de là, vous pouvez ajouter une restriction d’accès à wp-login.php si votre contexte le permet, ou la protection “php non exécutable” dans uploads si elle n’est pas déjà gérée ailleurs.
Journal Apache, logs WordPress, et validation: la vraie méthode
Le meilleur test n’est pas “ça marche sur mon PC”. C’est “ça marche dans les conditions réelles”. Concrètement, quand vous ajoutez des règles, je conseille de vérifier:
- les logs Apache pour les codes 403 ou 404 anormaux; les pages front qui reposent sur des scripts (cache, polices, requêtes AJAX); la zone d’administration si vous avez des restrictions IP.
Si vous voyez une augmentation de 403 sur admin-ajax.php, vous avez probablement bloqué une route qui sert au front. Là, l’erreur est fréquente, parce que les gens confondent wp-admin et les appels AJAX destinés au front.
Voici une petite discipline de travail, qui m’évite beaucoup de retours en arrière:
- tester une règle à la fois, pas un gros bloc d’un coup; vérifier les pages critiques avec un profil utilisateur “vraie vie” (abonné, utilisateur non connecté); conserver un fichier modèle .htaccess versionné pour revenir vite en cas de surprise; regarder les codes HTTP exacts dans les logs (403, 404, 500), ils donnent presque toujours la cause.
(Je limite volontairement l’approche: trop de checklists “à rallonge” finissent ignorées dans l’urgence.)
Les pièges classiques à connaître avant de verrouiller trop fort
Les règles .htaccess sont puissantes, mais elles peuvent aussi masquer des problèmes, ou créer un “faux sentiment de sécurité”. Voici ce que j’ai vu le plus souvent sur des sites WordPress professionnels:
Casser les permaliens en modifiant le bloc rewrite sans comprendre l’ordre. Résultat: 404 partout, et on perd du temps. Bloquer admin-ajax.php par des règles “trop génériques”, ou par des patterns sur les chemins. Refuser l’accès à des ressources statiques via des contrôles de répertoire ou des fichiers match trop larges. Supposer que la règle s’applique partout alors que votre hébergeur désactive AllowOverride ou certaines directives.Si vous devez choisir, choisissez d’abord des règles “ciblées” sur des fichiers précis. Plus vous attaquez https://gardewp.fr/securite-wordpress/ large, plus vous risquez de casser.
Quand .htaccess ne suffit pas (et ce que j’ajoute en complément)
Une vraie stratégie de sécurité WordPress professionnelle combine plusieurs niveaux. .htaccess est une couche, pas l’architecture entière. Sans tomber dans une liste infinie, voilà les compléments qui changent vraiment le résultat:
- mise à jour WordPress, thèmes et plugins, avec une politique claire de maintenance; durcissement des identifiants (et idéalement de l’authentification forte); limitation de l’accès à wp-login.php côté serveur ou reverse proxy; surveillance des tentatives d’accès, avec alertes simples sur les pics; backups testés, parce que la meilleure sécurité reste parfois une reprise.
Et sur le plan “hygiène applicative”, si un plugin est obsolète ou trop permissif, aucune règle Apache ne remplacera sa correction.
Petite liste de décisions à prendre (pas des recettes)
Plutôt que de prétendre qu’il existe un “.htaccess parfait”, j’encadre les choix avec des décisions concrètes. Vous gagnerez du temps en tranchant sur ces points:
- désactiver ou non XML-RPC selon vos usages réels; autoriser ou restreindre wp-login.php selon votre organisation (IP stable, VPN, mobile); bloquer l’exécution PHP dans uploads seulement si votre environnement ne le fait pas déjà; ajouter des en-têtes simples, mais éviter de lancer une CSP bloquante sans plan; décider si vous voulez répondre en 403 ou en 404 quand vous refusez un accès, selon votre stratégie de visibilité.
Ces choix dépendent de votre site, de vos utilisateurs, et de l’hébergement. L’objectif reste identique: réduire les surfaces sans casser le business.
Vérifier après déploiement: signaux à surveiller
Une fois les règles en place, il faut regarder les signaux. Je ne parle pas de “résultats magiques”. Je parle de signaux concrets dans les logs et dans le comportement du site:
- baisse des requêtes sur les endpoints scannés; stabilisation des codes 403 sur les routes attendues; absence d’augmentation des erreurs front (500, 502) liées à des fichiers bloqués; conformité aux fonctionnalités clés (recherche, formulaires, paiements, téléchargements).
Sur un site WordPress professionnel, ces points sont souvent plus importants que la perfection technique de la configuration. Un serveur plus sécurisé mais inutilisable ne sert à rien.
Récapitulatif pragmatique des familles de règles
Si vous devez retenir une logique simple, retenez celle-ci: on commence par fermer les fichiers et endpoints réellement inutiles, on réduit les comportements suspects, puis on ajoute des en-têtes et des protections ciblées.
Le succès, c’est quand vos règles:
- sont cohérentes avec WordPress, respectent votre hébergement, et n’entrent pas en conflit avec les plugins ou le front.
C’est précisément là que .htaccess devient un outil professionnel. Pas parce qu’il “fait tout”, mais parce qu’il permet, à coût quasi nul, de rendre votre site plus difficile à attaquer.