XML-RPC WordPress : 3 façons de le désactiver & repérer les attaques xmlrpc.php | exception Jetpack

Mention d'affiliation v3.1
Mention d'affiliation v3.2 (mobile)

Si le journal d'accès de votre site WordPress montre des centaines de requêtes xmlrpc.php d'affilée depuis la même IP, il s'agit d'une attaque par devinette de mots de passe visant le XML-RPC de WordPress. J'ai classé les 8 624 entrées d'une journée de journal d'un serveur Nginx + Apache qui héberge plusieurs sites WordPress, appliqué moi-même les trois méthodes de désactivation et vérifié les codes de réponse, pour établir à quel niveau il faut bloquer pour éviter jusqu'à l'exécution de PHP.

XML-RPC est un protocole qui échange des documents XML par HTTP pour appeler à distance des fonctions de WordPress ; depuis WordPress 3.5, l'option qui permettait de l'activer ou de le désactiver a disparu des réglages, si bien qu'il est actif dès l'installation.

1️⃣ Le rôle de xmlrpc.php et qui l'utilise

Depuis l'arrivée de l'API REST, on prend facilement [xmlrpc.php] pour un fichier qui ne sert plus, mais Jetpack relie encore aujourd'hui votre site à WordPress.com par ce fichier. La documentation officielle de Jetpack indique clairement qu'il dépend de la connexion XML-RPC, et chez les hébergeurs qui bloquent XML-RPC par défaut, la connexion Jetpack échoue d'emblée. C'est comme le numéro de fax qu'on garde encore au bureau.

Sous WordPress 7.1, ce fichier accepte 77 méthodes : 50 de la famille wp pour les articles, les médias et les commentaires, 23 des anciens protocoles de blog (MetaWeblog, MovableType, Blogger), 2 pour les pingbacks et 2 méthodes demo de test.

La famille wp se connecte avec l'identifiant et le mot de passe contenus dans le corps de la requête : elle ne passe donc jamais par l'écran de connexion. Rédiger et modifier des articles, téléverser des médias, gérer les commentaires : tout passe par cette famille, et les 23 méthodes des anciens protocoles de blog ont été conservées pour échanger des articles de la même façon que d'autres outils de blog.

demo.sayHello est un appel de test intégré au XML-RPC de WordPress. Envoyé, il ne renvoie qu'un mot, [Hello!] ; comme il ne demande pas de connexion, on s'en sert pour vérifier que XML-RPC fonctionne. Son pendant, demo.addTwoNumbers, additionne deux nombres et renvoie le résultat.

Toutes ne répondent qu'à un corps XML envoyé en POST ; si vous ouvrez l'adresse dans un navigateur, un 405 revient avec le message [XML-RPC server accepts POST requests only.].

Les pingbacks passent aussi par ce fichier. Quand vous publiez un article, un pingback part vers le xmlrpc.php de chaque site lié dans le texte, et le serveur qui le reçoit ouvre lui-même l'adresse d'envoi pour vérifier que le lien existe bien.

🧭 Les requêtes reçues par xmlrpc.php et leur traitement
📨 Expéditeur
↓
Entrée
xmlrpc.php
Ne traite que le corps XML envoyé en POST
405 · XML-RPC server accepts POST requests only.
77 méthodes
wp.*Articles · médias · commentaires, 50
metaWeblog · mt · bloggerAnciens protocoles de blog, 23
pingback.*Pingbacks, 2
demo.*Appels de test de fonctionnement, 2
Résultat
Maintient la connexion avec WordPress.com
Vérifie l'identifiant et le mot de passe du corps de la requête → rédaction et modification d'articles
Le serveur ouvre lui-même l'adresse d'envoi et vérifie le lien
Sans connexion : Hello! Réponse
Aucun traitement
Jetpack maintient sa connexion avec WordPress.com par ce fichier : si vous bloquez le fichier, la connexion se coupe.
Les outils de publication externes se connectent avec l'identifiant et le mot de passe placés dans le corps de la requête, sans passer par l'écran de connexion.
Un pingback part vers le xmlrpc.php du site lié dans l'article, et le serveur qui le reçoit ouvre lui-même l'adresse d'envoi pour vérifier le lien.
demo.sayHello est un appel de test qui vérifie que XML-RPC fonctionne ; il répond sans connexion par un seul mot, [Hello!].
Si vous ouvrez l'adresse dans un navigateur, un 405 revient avec le message [XML-RPC server accepts POST requests only.].

2️⃣ Les attaques xmlrpc.php vues dans le journal d'accès

La devinette de mots de passe ne passe pas par l'écran de connexion mais par [xmlrpc.php]. Dans le journal d'accès d'un serveur Nginx + Apache qui héberge plusieurs sites WordPress, du 14 octobre de 0 h à 20 h, on compte 8 624 requêtes POST /xmlrpc.php venant de 72 IP, dont 19 en ont envoyé exactement 300 chacune.

Une IP a envoyé 300 requêtes en 28 minutes, de 14 h 09 à 14 h 37, à un intervalle régulier de 5 à 6 secondes jusqu'au bout. 8 524 requêtes portaient Jetpack ou WordPress.com dans leur User-Agent, et une même IP alternait entre plusieurs valeurs imitant le vrai format de Jetpack, comme [Jetpack by WordPress.com (Jetpack 13.0; WordPress 6.3)].

Ce jour-là, jusqu'à 14 h, la désactivation de XML-RPC de l'extension de sécurité renvoyait ces requêtes vers l'accueil avec un 302 ; après 14 h, une fois le blocage posé dans Nginx, elles se terminaient par un 403. Le 302 signifie que PHP s'est exécuté à chaque requête, même avec un corps de 0 octet ; le 403 est une réponse qui n'est jamais passée par PHP.

🧭 Une attaque xmlrpc.php en une ligne de journal d'accès
Schéma explicatif
🛡️ État du serveur
Une ligne du journal d'accès (Nginx access.log)
203.0.113.25IP[14/Oct/2026:14:09:04 +0900]Heure"POST /xmlrpc.php HTTP/1.1"Requête302403Statut0153Octets"Jetpack by WordPress.com (Jetpack 13.0; WordPress 6.3)"User-Agent
PHP exécuté · 302 vers l'accueilSans PHP · page 403 par défaut de Nginx
Quand l'extension de sécurité a désactivé XML-RPC, le journal enregistre un 302 qui renvoie la requête vers l'accueil. Le corps fait 0 octet, mais PHP s'exécute pour produire ce 302.
Avec un blocage dans Nginx, le journal enregistre un 403 et les 153 octets de la page d'erreur par défaut, et PHP ne s'exécute pas.
Requêtes d'une même IP
14:09:0414:37:20
300 en 28 minutes, toutes les 5 à 6 s
8 624 POST de 0 h à 20 h72 IP19 IP à 300 chacune8 524 UA usurpant Jetpack ou WordPress.com

3️⃣ system.multicall et la devinette de mots de passe

On lit souvent qu'avec [system.multicall], une seule requête teste des centaines de mots de passe ; or, dès qu'une connexion échoue dans une requête, WordPress ne vérifie plus les mots de passe des appels suivants. Seul le premier appel passe par wp_authenticate, et les suivants reçoivent sans vérification la même erreur, [Incorrect username or password.].

Comme une réponse revient tout de même pour chaque appel, une requête contenant 100 mots de passe faux renvoie 100 erreurs dans une réponse de 23 Ko, en 0,12 seconde. Si le bon mot de passe se trouve plus loin dans la même requête, il est refusé à cause de l'échec précédent ; s'il est en premier, seul cet appel réussit. Le mot de passe n'est comparé qu'une fois, mais l'analyse du XML et le chargement de WordPress se répètent à chaque requête : la charge serveur de cette attaque vient donc du nombre de requêtes, et non de la vérification des connexions.

4️⃣ 3 façons de désactiver XML-RPC et leurs codes de réponse

Même si une extension désactive XML-RPC, les requêtes vers [xmlrpc.php] atteignent toujours PHP. Avec le filtre activé, j'ai envoyé une requête de 100 appels et reçu quand même un HTTP 200 avec 100 erreurs (24 Ko). Selon le niveau où la requête est refusée, il existe trois méthodes, chacune avec un code de réponse différent.

1. Le couper par code avec le filtre xmlrpc_enabled

Il suffit d'ajouter au functions.php du thème une ligne add_filter qui passe le filtre [xmlrpc_enabled] à false. Les appels qui exigent une connexion sont alors refusés avec l'erreur [XML-RPC services are disabled on this site.] et un HTTP 405, mais l'appel de test demo.sayHello, qui n'en exige pas, répond toujours 200.

2. Le couper dans les réglages d'une extension : Perfmatters · Hide My WP

Voici comment le désactiver avec le réglage Disable XML-RPC d'extensions comme Perfmatters ou Hide My WP. Hide My WP utilise le même filtre que ci-dessus, avec les mêmes réponses ; Perfmatters, en plus de ce filtre, termine les requêtes directes vers [xmlrpc.php] par un 403 et retire l'en-tête et le lien de pingback, si bien qu'une fois l'option activée, GET comme POST répondent 403. Mais pour produire ce 403, WordPress s'exécute jusqu'à l'étape init : la réponse prend 0,13 à 0,15 seconde, autant que lorsque le fichier est ouvert, et la charge PHP demeure.

🔌 Désactiver XML-RPC dans les réglages d'une extension
📍 Settings › Perfmatters › General › Core › Disable XML-RPC
Activez l'interrupteur et cliquez sur [Save Changes] : l'affichage visiteur ci-dessous change.
Administration
Settings saved.
perfmatters
⚙ GeneralVersion 2.6.8
Core
Disable Emojis?
Disable Dashicons?
Disable Embeds?
Disable XML-RPC?
Remove RSD Link?
Remove jQuery Migrate?
Hide WP Version?
Remove Shortlink?
Disable RSS Feeds?
Remove RSS Feed Links?
Disable Self Pingbacks?
Disable REST API?
Remove REST API Links?
Disable Google Maps?
Disable Password Meter?
Disable Comments?
Remove Comment URLs?
Add Blank Favicon?
Remove Global Styles?
Block Style Behavior?
Disable Heartbeat?
Heartbeat Frequency?
Limit Post Revisions?
Autosave Interval?
Login URL
Custom Login URL?
Disabled Behavior?
Message?
📍 Hide My WP › Settings › Cleanup › Disable XML RPC
Cochez la case et cliquez sur [Save Settings] : l'affichage visiteur ci-dessous change.
Administration
Hide My WP
Settings was updated successfully!
Cleanup
Minify HTML
Remove comments and whitespaces from HTML (Use with cache).
Minify style
Remove theme info and other comments from stylesheet. (Require new style name)(Use with cache!).
Replace \/ URLs
Choose if you see Javascript URLs (e.g. \/wp-content\/themes)
Feed Meta
Other Meta
Default Tagline
Remove Version
Body Classes
Menu Classes
Post Classes
Clean up other
Replace in AJAX
Change Nonce
Disable XML RPC
Internal CSS
Useful to paste internal CSS code (Require New Theme Path)
Internal JS
Useful to paste internal JS code (Require New Theme Path)
Affichage des visiteurs déconnectés — requêtes avec les réglages enregistrés
405
XML-RPC server accepts POST requests only.
Une requête GET reçoit un 405 quel que soit le réglage.
200
Hello!
C'est un appel de test de fonctionnement : il répond sans connexion.
200
faultCode 403 · Incorrect username or password.
La vérification du mot de passe s'exécute. Changer l'adresse de connexion n'y change rien.
403
Pas de corps
Perfmatters termine la requête par un 403 à l'étape init. PHP s'exécute quand même.
403
Pas de corps
Perfmatters termine la requête par un 403 à l'étape init. PHP s'exécute quand même.
403
Pas de corps
Se termine par un 403 sans vérification du mot de passe. PHP s'exécute quand même.
200
Hello!
C'est la méthode du filtre : les appels qui ne demandent pas de connexion répondent toujours.
405
faultCode 405 · XML-RPC services are disabled on this site.
Seuls les appels qui exigent une connexion sont refusés.

3. Le bloquer sur le serveur web : Nginx · Apache

Avec Nginx comme avec Apache, la requête est refusée avant PHP : contrairement aux méthodes par extension, WordPress ne s'exécute pas du tout.

# Nginx — dans le bloc server, au-dessus du location qui traite PHP
location = /xmlrpc.php {
    deny all;
}

Ce bloc location se place au-dessus du location qui traite PHP, et Nginx refuse aussitôt les requêtes qui correspondent exactement à [xmlrpc.php]. Après l'ajout, vérifiez la configuration puis rechargez-la, sinon elle ne s'applique pas.

nginx -t
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
systemctl reload nginx

Dès le rechargement, GET et POST se terminent par un 403 sans atteindre PHP ; le corps de la réponse est la page 403 par défaut de Nginx (153 octets), et la réponse prend 0,02 seconde.

# Apache — .htaccess à la racine du site (Apache 2.4)
<Files xmlrpc.php>
    Require all denied
</Files>

Sur un serveur uniquement Apache, ajoutez la directive Files ci-dessus au .htaccess de la racine du site : elle s'applique aussitôt, et la page 403 par défaut d'Apache (199 octets) revient dans les mêmes 0,02 seconde.

curl -s -o /dev/null -w '%{http_code}' -X POST https://example.com/xmlrpc.php -d '<methodCall><methodName>demo.sayHello</methodName></methodCall>'
403

La commande ci-dessus envoie en POST l'appel de test demo.sayHello et vérifie le code de réponse ; après le blocage sur le serveur web, c'est un 403 qui revient. Sans les options [-o /dev/null] et [-w], vous voyez le corps : si [Hello!] revient, c'est ouvert — mais un site désactivé seulement par le filtre répond de la même façon, il faut donc envoyer aussi un appel de connexion pour voir le 405.

5️⃣ Quand ne pas le désactiver, et les alternatives

Le blocage complet sur le serveur web est le plus efficace, mais il ne convient pas aux sites reliés à WordPress.com par Jetpack. Jetpack dépend de la connexion XML-RPC, et chez les hébergeurs qui bloquent XML-RPC par défaut, comme WP Engine, il faut ouvrir une exception en suivant les instructions de Jetpack pour que la connexion se fasse. Il en va de même pour les sites qui veulent recevoir des pingbacks.

Ces sites restreignent l'accès en n'autorisant que la liste d'IP publiée par Jetpack (jetpack.com/ips-v4.txt) et en refusant le reste. Dans le bloc location de Nginx, ajoutez une ligne allow par plage d'IP, puis deny all à la fin.

Si vous ne pouvez pas tout bloquer, il reste à limiter le nombre de requêtes par minute pour les visiteurs non connectés. Le réglage est le même que dans la partie sur la limitation de débit Nginx de l'article Sécurité de wp-admin qui y est consacré ; seules les requêtes sans cookie de connexion sont comptées, et le travail des administrateurs connectés n'est donc pas touché.

🔢 FAQ & contenus recommandés

Même si vous le supprimez, la prochaine mise à jour du cœur de WordPress recopie le fichier du paquet à sa place : il revient donc à la mise à jour suivante. Au lieu de supprimer le fichier, bloquer l'adresse sur le serveur web ou le désactiver par filtre tient aussi après les mises à jour.

L'API REST est une entrée distincte, à l'adresse [wp-json] : elle reste ouverte même si XML-RPC est désactivé. Comme l'éditeur de blocs utilise cette entrée, il vaut mieux ne pas la désactiver complètement, mais bloquer seulement les requêtes des visiteurs déconnectés.

Ils ne vérifient pas, ils envoient. Sur tous les sites WordPress, le fichier se trouve au même chemin : les scanners changent simplement l'adresse et envoient des POST. Un WordPress dans son état par défaut révèle même lui-même l'adresse de xmlrpc.php, par le lien [EditURI] dans le head des pages et par l'en-tête [X-Pingback] des articles qui acceptent les pingbacks.

🛡️ Sécurité WordPress : contenus recommandés 8 articles · 2 externes
🗂️ Sécurité WordPress
📋 Sécurité de wp-admin 📄 Force brute : 9 méthodes 📄 Hide My WP 📄 Les 5 meilleures extensions de sécurité
📄 Désactiver XML-RPC 📄 API REST 📄 Pingbacks · trackbacks 📄 Sécurité de wp-config.php
📡 Nanaco Japan : contrer les attaques xmlrpc.php 📡 サイトの主治医 : désactiver xmlrpc.php et vérifier
Aucun résultat.

ℹ️ Mention d'affiliation
Le contenu de ce site contient des liens d'affiliation. Lorsqu'un visiteur achète un produit ou un service via l'un de ces liens, le site perçoit une commission du vendeur. Le montant payé par l'acheteur(il baisse lors des promotions ↓), lui, n'augmente pas. Les prix, remises et stocks indiqués correspondent à la date de rédaction et peuvent différer ; vérifiez-les donc auprès du vendeur avant d'acheter. Les produits sont choisis et évalués selon nos propres critères, et les commissions n'influencent ni l'ordre de présentation ni le contenu des évaluations.