Comment bloquer les attaques par force brute sur xmlrpc.php dans WordPress
Dernière mise à jour:
xmlrpc.php est l'ancienne API distante de WordPress. Peu de sites en ont encore besoin, et chaque site WordPress d'internet est attaqué par ce biais. Sa méthode system.multicall exécute de nombreux appels en une seule requête : un seul POST peut essayer des centaines de mots de passe, et c'est pourquoi les limiteurs de connexion qui comptent les requêtes vers wp-login.php ne le voient pas. Sa méthode pingback.ping sert à faire envoyer par votre site des requêtes vers celui de quelqu'un d'autre.
Ci-dessous : comment reconnaître l'attaque dans les logs d'accès, comment bloquer xmlrpc.php dans nginx, Apache ou WordPress lui-même, que faire si vous utilisez Jetpack, et comment limiter le débit ou bannir avec fail2ban quand vous devez le laisser ouvert. Les commandes sont pour Debian et Ubuntu et pour la famille RHEL ; example.com désigne votre site.
Reconnaître une attaque XML-RPC dans les logs d'accès
Comptez les requêtes POST vers xmlrpc.php par adresse. Un site normal en voit quelques-unes par jour, venant de Jetpack ou d'une application. Des centaines depuis une seule adresse, ou un flux régulier depuis de nombreuses adresses, c'est une attaque.
sudo sh -c "grep -hI 'POST /xmlrpc.php' /var/log/nginx/*access*.log /var/log/apache2/*access*.log \
/var/log/httpd/*access_log /usr/local/apache/domlogs/* /var/log/apache2/domlogs/* 2>/dev/null" \
| awk '{print $1}' | sort | uniq -c | sort -rn | head -20La commande lit les emplacements habituels : nginx, Apache sur Debian et Ubuntu, httpd sur la famille RHEL, et les logs par domaine de cPanel. Les requêtes par heure montrent quand l'attaque a commencé :
sudo sh -c "grep -hI 'POST /xmlrpc.php' /var/log/nginx/access.log /var/log/apache2/access.log /var/log/httpd/access_log 2>/dev/null" \
| awk '{print substr($4, 2, 14)}' | uniq -c | tail -n 24- Le statut est
200même pour un mauvais mot de passe : XML-RPC signale l'échec à l'intérieur de la réponse. Ne lisez pas200comme une connexion réussie. - Des réponses volumineuses, répétées depuis une même adresse toutes les quelques secondes, sont en général du
system.multicall: une seule réponse pour de nombreuses tentatives de mot de passe. - Le log ne montre pas quelle méthode a été appelée : le corps de la requête n'est pas journalisé. Force brute et abus de pingback se ressemblent ici.
Pour savoir si XML-RPC répond sur un site, demandez-lui la liste de ses méthodes depuis n'importe quelle machine. Une liste de méthodes signifie qu'il est actif ; un 403 signifie qu'il est bloqué.
curl -s -X POST -H 'Content-Type: text/xml' \
-d '<?xml version="1.0"?><methodCall><methodName>system.listMethods</methodName></methodCall>' \
https://example.com/xmlrpc.php | head -c 400; echoBloquer xmlrpc.php dans nginx ou Apache
Bloquer au niveau du serveur web est l'option la moins coûteuse : la requête est refusée avant que PHP et WordPress ne se chargent. Dans nginx, ajoutez ceci au bloc server de chaque site WordPress :
# In the site's server { } block, before the "location ~ \.php$" block
location = /xmlrpc.php {
deny all;
}sudo nginx -t && sudo systemctl reload nginxDans Apache 2.4, placez ceci dans le .htaccess du site (pas besoin de recharger ; LiteSpeed le lit aussi) ou dans son <VirtualHost> :
# In the site's .htaccess or <VirtualHost>
<Files "xmlrpc.php">
Require all denied
</Files>sudo apachectl configtest && sudo systemctl reload apache2sudo apachectl configtest && sudo systemctl reload httpdAttention: Bloquer xmlrpc.php casse ce qui l'utilise encore : Jetpack (voir plus bas), les pingbacks, et certaines applications et outils de publication anciens. En cas de doute, cherchez d'abord les appelants légitimes dans les logs de l'étape 1.
Désactiver XML-RPC dans WordPress
Si vous ne pouvez pas modifier la configuration du serveur web, une extension must-use le fait depuis WordPress. Les extensions must-use se chargent à chaque requête et ne peuvent pas être désactivées par erreur depuis l'administration. Remplacez le chemin par celui de votre site :
sudo mkdir -p /var/www/example.com/wp-content/mu-plugins
sudo tee /var/www/example.com/wp-content/mu-plugins/disable-xmlrpc.php > /dev/null <<'EOF'
<?php
// Turns off the XML-RPC methods that need a login, and pingbacks.
add_filter( 'xmlrpc_enabled', '__return_false' );
add_filter( 'xmlrpc_methods', function ( $methods ) {
unset( $methods['pingback.ping'], $methods['pingback.extensions.getPingbacks'] );
return $methods;
} );
EOFRemarque: Le filtre xmlrpc_enabled ne désactive que les méthodes qui demandent une connexion, comme le dit la référence WordPress ; le second filtre retire les méthodes de pingback. PHP s'exécute quand même à chaque requête : sous une attaque intense, le blocage au niveau du serveur web ci-dessus est plus léger.
Des extensions font la même chose : des extensions dédiées « Disable XML-RPC », et des extensions de sécurité comme Wordfence et Solid Security ont une option pour cela (en novembre 2026). Une extension se désactive facilement par accident lors d'une mise à jour ; l'extension must-use et la règle du serveur web, non.
Garder Jetpack fonctionnel
Jetpack communique avec votre site via xmlrpc.php : le bloquer pour tout le monde casse la connexion Jetpack. Jetpack publie les plages d'adresses de ses serveurs sur sa page de liste d'autorisation : autorisez-les et bloquez tous les autres. Dans nginx, le bloc location doit alors aussi transmettre la requête à PHP :
location = /xmlrpc.php {
# Jetpack's ranges, from its allowlist page (check it for changes)
allow 122.248.245.244/32;
allow 54.217.201.243/32;
allow 54.232.116.4/32;
allow 192.0.64.0/18;
allow 195.234.108.0/22;
deny all;
# then the same lines as in your "location ~ \.php$" block, for example:
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_pass unix:/run/php/php-fpm.sock;
}Copiez les lignes PHP du bloc location ~ \.php$ du site lui-même : le chemin du socket varie d'un système à l'autre. Dans Apache, Require ip seul n'autorise que ces plages :
<Files "xmlrpc.php">
Require ip 122.248.245.244/32 54.217.201.243/32 54.232.116.4/32 192.0.64.0/18 195.234.108.0/22
</Files>Remarque: Plages telles que listées par Jetpack en novembre 2026. Elles peuvent changer : vérifiez la page de temps en temps. Derrière Cloudflare ou un autre proxy, ces règles voient l'adresse du proxy, sauf si l'adresse réelle du visiteur est restaurée d'abord (real_ip de nginx, mod_remoteip d'Apache).
Limiter le débit de xmlrpc.php quand il doit rester ouvert
Si une application ou un service que vous ne pouvez pas lister par adresse a besoin de XML-RPC, limitez la fréquence à laquelle chaque adresse peut l'appeler. Dans nginx, définissez une zone dans le contexte http, puis utilisez-la pour xmlrpc.php : ici 6 requêtes par minute et par adresse, avec une rafale de 5, et 429 au-delà.
# /etc/nginx/conf.d/xmlrpc-limit.conf (read inside the http { } block)
limit_req_zone $binary_remote_addr zone=xmlrpc:10m rate=6r/m;# In the site's server { } block
location = /xmlrpc.php {
limit_req zone=xmlrpc burst=5 nodelay;
limit_req_status 429;
# then the same lines as in your "location ~ \.php$" block, for example:
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_pass unix:/run/php/php-fpm.sock;
}sudo nginx -t && sudo systemctl reload nginxRemarque: Une limite de débit compte les requêtes, pas les mots de passe : une seule requête system.multicall dans la limite peut encore contenir des centaines de tentatives. Associez-la à des mots de passe robustes, ou bannissez les adresses avec fail2ban. Apache n'a pas d'équivalent intégré ; utilisez fail2ban ci-dessous.
Bannir les attaquants XML-RPC avec fail2ban
fail2ban lit le log d'accès et bannit une adresse au niveau du pare-feu : il fonctionne aussi bien avec nginx qu'avec Apache. Installez-le comme dans Comment stopper les attaques par force brute SSH (dépôts Debian et Ubuntu, EPEL sur la famille RHEL). Créez ensuite un filtre pour les requêtes POST vers xmlrpc.php :
sudo tee /etc/fail2ban/filter.d/wordpress-xmlrpc.conf > /dev/null <<'EOF'
[Definition]
failregex = ^<HOST> \S+ \S+ \[[^]]+\] "POST /xmlrpc\.php
ignoreregex =
EOFPuis une jail : 5 requêtes en 60 secondes, un bannissement d'une heure. Mettez votre propre adresse dans ignoreip et, si vous utilisez Jetpack, ses plages. Pour Apache, réglez logpath sur /var/log/apache2/*access.log sur Debian et Ubuntu ou sur /var/log/httpd/*access_log sur la famille RHEL.
sudo tee /etc/fail2ban/jail.d/wordpress-xmlrpc.local > /dev/null <<'EOF'
[wordpress-xmlrpc]
enabled = true
port = http,https
filter = wordpress-xmlrpc
logpath = /var/log/nginx/access.log
maxretry = 5
findtime = 60
bantime = 3600
ignoreip = 127.0.0.1/8 ::1 192.0.2.10
EOFTestez le filtre sur le vrai log avant de l'activer : fail2ban-regex indique combien de lignes correspondent. Redémarrez ensuite fail2ban et vérifiez la jail.
sudo fail2ban-regex /var/log/nginx/access.log /etc/fail2ban/filter.d/wordpress-xmlrpc.conf
sudo systemctl restart fail2ban
sudo fail2ban-client status wordpress-xmlrpcAttention: Derrière Cloudflare ou un autre proxy, le log d'accès montre l'adresse du proxy : fail2ban bannirait le proxy et rendrait le site inaccessible à de nombreux visiteurs. Restaurez d'abord l'adresse réelle dans le log, ou bloquez au niveau du proxy.
Comment InfraFence gère les attaques XML-RPC
Le pare-feu web d'InfraFence lit les logs d'accès de nginx, Apache et LiteSpeed, et depuis l'agent 1.0.42 aussi ceux de Traefik, Caddy, HAProxy et des serveurs web en conteneurs. Derrière Cloudflare, il prend l'adresse du visiteur dans CF-Connecting-IP, et uniquement depuis les plages de Cloudflare.
- Toutes les 5 requêtes POST vers
xmlrpc.phpvenant d'une même adresse sur un même site en moins d'une minute ajoutent 25 points au score de cette adresse. Une attaque soutenue continue d'en ajouter. - Le score cumule aussi les autres attaques de l'adresse, comme la force brute sur
wp-login.php, le scan d'extensions ou les tentatives d'exploit, et baisse de 5 points par minute : une requête isolée et étrange s'efface d'elle-même. - À 80 points, l'adresse est bannie au niveau du pare-feu et l'événement est signalé comme critique. Seuils et points se modifient par serveur, et le mode surveillance signale sans bannir.
Voir Pare-feu web pour les règles et le score. Ce qu'il ne fait pas : il compte les requêtes, il ne peut donc pas voir combien de mots de passe contient une requête system.multicall ; il ne modifie pas votre configuration nginx, Apache ou WordPress, donc xmlrpc.php reste ouvert tant que vous ne le bloquez pas comme ci-dessus ; et il n'a pas d'exception intégrée pour Jetpack : si les serveurs de Jetpack appellent assez souvent pour être notés, ajoutez leurs plages à la liste blanche. Le bannissement vient du log : la requête qui l'a déclenché a déjà reçu sa réponse.
Questions
- Peut-on désactiver xmlrpc.php sans risque ?
- Pour la plupart des sites, oui : l'éditeur de blocs et l'administration utilisent l'API REST, pas XML-RPC. Vérifiez d'abord si vous utilisez Jetpack, les pingbacks, une application ou un outil de publication qui en dépend encore.
- Pourquoi les attaques affichent-elles le statut 200 ?
- XML-RPC répond
200et signale l'échec de connexion à l'intérieur de la réponse. Le code de statut ne dit rien sur la validité d'un mot de passe. - Mon extension de limitation des connexions ne l'arrête pas. Pourquoi ?
- Beaucoup de limiteurs comptent les tentatives sur
wp-login.php. Une requêtesystem.multicallviaxmlrpc.phpcontient des centaines de tentatives en une seule requête et les contourne. Bloquez ou limitezxmlrpc.phplui-même.
Essayez gratuitement sur 1 serveur
Starter est gratuit pour un serveur, avec la protection complète et le blocage automatique. Sans carte bancaire.
Installez l'agent en root, avec votre jeton à la place de <TOKEN> :
curl -fsSL https://github.com/infrafence/infrafence-agent/releases/latest/download/install.sh | sudo bash -s -- --token <TOKEN>Le jeton se crée dans le tableau de bord, dans Serveurs › Ajouter un serveur.
