Bloquer XML-RPC, sauf pour …

XML-RPC permet d’échanger des données entre un site WordPress et une application externe sans passer par un navigateur web (Firefox, Chrome, Edge…). Par exemple, il est possible de récupérer un article ou au contraire d’en publier à partir d’une application installée sur un smartphone.

Le souci, c’est que derrière l’application, il n’y a pas toujours quelqu’un de bien intentionné. Voilà pourquoi il est conseillé de bloquer l’accès XML-RPC… sauf pour les extensions actives sur votre site et qui l’utilisent.

En savoir un peu plus sur XML-RPC

XML-RPC échange les données en utilisant le protocole internet HTTP.
HTTP(S) permet  notamment d’accéder à un site en indiquant son adresse web dans la ligne de commande d’un navigateur web, par exemple : « https://dfarnier.fr/xmlrpc.php?test=oui ».

XML-RPC utilise la méthode ‘POST’ de HTTP en incluant des données au format XML dans le corps de la requête. Par exemple, la demande :

<?xml version="1.0" encoding="UTF-8"?>
<methodCall><methodName>wp.getUsersBlogs
</methodName>
 <params><param><value>
AdminWP1
 </value></param>
 <param><value>
mdp01
</value></param></params>
</methodCall>

peut permettre d’obtenir en retour les informations suivantes :

<?xml version="1.0" encoding="UTF-8"?>
<methodResponse>
 <params>
 <param>
 <value>
 <array><data>
 <value><struct>
 <member><name>isAdmin</name><value><boolean>1</boolean></value></member>
 <member><name>url</name><value><string>http://localhost/wordpress/</string></value></member>
 <member><name>blogid</name><value><string>1</string></value></member>
 <member><name>blogName</name><value><string>WampServer</string></value></member>
 <member><name>xmlrpc</name><value><string>http://localhost/wordpress/xmlrpc.php</string></value></member>
</struct></value>
</data></array>
 </value>
 </param>
 </params>
</methodResponse>

Dans l’exemple ci-dessus :

  • la requête demande les informations relatives à un utilisateur (wp.getUsersBlogs) d’identifiant AdminWP1 et de mot de passe mdp01,
  • le site WordPress retourne alors des informations sur cet utilisateur.

Les données XML doivent se conformer aux spécifications XML-RPC.

On trouvera la liste des fonctions XML-RPC disponibles pour WordPress dans le codex WordPress. Ces fonctions concernent les articles, les pages, les taxonomies, les médias, les commentaires, les options et les utilisateurs.

Haut de page

Quel est le problème de sécurité ?

XML-RPC permet d’insérer de multiples demandes dans une même requête. Dans l’exemple ci-dessous, un pirate recherche le mot de passe d’un utilisateur « canadawebservices » en tentant de nombreuses possibilités ( « 00 », « 000 », …, « 007007 », « 010101 »…) :

<value><struct><member><name>methodName</name><value><string>wp.getUsersBlogs</string></value></member><member><name>params</name><value><array><data><value><array><data><value><string>canadawebservices</string></value><value><string>00</string></value></data></array></value></data></array></value></member></struct></value>
<value><struct><member><name>methodName</name><value><string>wp.getUsersBlogs</string></value></member><member><name>params</name><value><array><data><value><array><data><value><string>canadawebservices</string></value><value><string>000</string></value></data></array></value></data></array></value></member></struct></value>
<value><struct><member><name>methodName</name><value><string>wp.getUsersBlogs</string></value></member><member><name>params</name><value><array><data><value><array><data><value><string>canadawebservices</string></value><value><string>0000</string></value></data></array></value></data></array></value></member></struct></value>
<value><struct><member><name>methodName</name><value><string>wp.getUsersBlogs</string></value></member><member><name>params</name><value><array><data><value><array><data><value><string>canadawebservices</string></value><value><string>000000</string></value></data></array></value></data></array></value></member></struct></value>
<value><struct><member><name>methodName</name><value><string>wp.getUsersBlogs</string></value></member><member><name>params</name><value><array><data><value><array><data><value><string>canadawebservices</string></value><value><string>00000000</string></value></data></array></value></data></array></value></member></struct></value>
<value><struct><member><name>methodName</name><value><string>wp.getUsersBlogs</string></value></member><member><name>params</name><value><array><data><value><array><data><value><string>canadawebservices</string></value><value><string>007007</string></value></data></array></value></data></array></value></member></struct></value>
<value><struct><member><name>methodName</name><value><string>wp.getUsersBlogs</string></value></member><member><name>params</name><value><array><data><value><array><data><value><string>canadawebservices</string></value><value><string>010101</string></value></data></array></value></data></array></value></member></struct></value>

La méthode, appelée « par force brute », peut finir par payer. Les requêtes pouvant être créées par programme, les pirates n’hésitent pas à tester des quantités énormes de combinaisons « identifiant / mot de passe »..

Attention aux identifiants trop courants et aux mots de passe trop faciles à découvrir.

Haut de page

Comment bloquer XML-RPC ?

Le code suivant doit être ajouté dans une extension (plugin) ou dans le fichier « functions.php » du thème actif :

add_filter ('xmlrpc_enabled', '__return_false');

L’instruction consiste à retourner la valeur « false » en retour du crochet « xmlrpc_enabled« .

Pour être précis, le crochet « xmlrpc_enabled » ne bloque pas toutes les fonctions XML-RPC mais seulement celles qui nécessitent de s’identifier (s’authentifier). C’est suffisant pour bloquer les attaques par force brute car ce crochet bloque notamment la fonction « wp.getUsersBlogs ».

Voici la réponse désormais retournée par le serveur à une demande de type « wp.getUsersBlogs » :

<?xml version="1.0" encoding="UTF-8"?>
<methodResponse>
<fault>
<value><struct><member>
<name>faultCode</name><value><int>405</int></value></member>
<member>
<name>faultString</name>
<value><string>Les services XML-RPC sont désactivés sur ce site.</string></value></member></struct></value>
</fault>
</methodResponse>
Haut de page

Ne pas bloquer Jetpack

Jetpack est une extension populaire qui offre de nombreuses fonctionnalités permettant d’améliorer un site WordPress. Or, si on bloque XML-RPC, Jetpack ne fonctionne plus, car il l’utilise pour assurer le dialogue entre le site et les serveurs de la société Automattic.

En fait, Jetpack ne passe pas par le filtre « xmlrpc_enabled ». Ce filtre n’est utilisé que pour l’authentification des appels à XML-RPC, or Jetpack utilise un processus d’authentification différent du processus proposé par WordPress en standard.

L’instruction « add_filter (‘xmlrpc_enabled’, ‘__return_false’); » peut donc être insérée dans le fichier « functions.php » ou dans une extension sans perturber le fonctionnement de Jetpack.

Néanmoins, j’ai contacté le support Jetpack pour leur demander si cela sera toujours vrai pour tous les module Jetpack à l’avenir. En gros, la réponse est que c’est fortement probable, mais que cela ne peut être garanti (« we don’t actively test against that type of setup so if you notice anything odd, please do let us know« ). Nous allons donc mettre en œuvre une solution permettant de se garantir de ce risque très faible. Franchement, c’est limite parano, mon objectif est plutôt de montrer comment faire pour d’autres extensions.

Toute requête Jetpack comprend le paramétrage « ?for=Jetpack » dans l’adresse web. Exemple de requête Jetpack :

  • dans l’adresse web (url) :
    https://dfarnier.fr/xmlrpc.php?for=jetpack&token=t8sV%2961IS%2663QO%5Eh7J%218dl%28Zdx1x8O47%3A1%3A0&timestamp=1501864171&nonce=scIiWQolC8&body-hash=PBiAPcy9QkOh1c7U7G5hw%2FJuT%2FI%3D&signature=7vCVIXsZLU0IFAG1l8%2F%2F88Co%2F7U%3D
  • dans le corps de la requête
    <?xml version="1.0"?>
    <methodCall><methodName>system.multicall</methodName>
    <params><param><value><array><data>
    <value><struct>
    <member><name>methodName</name><value><string>jetpack.jsonAPI</string></value></member>
    <member><name>params</name><value><array><data> <value><array><data>
    <value><string>GET</string></value>
    <value><string>https://public-api.wordpress.com/rest/v1.1/sites/98108117?http_envelope=1</string></value>
    <value><string></string></value>
    <value><int>98108117</int></value>
    <value><array><data></data></array></value>
    <value><string></string></value>
    </data></array></value>
    <value><boolean>0</boolean></value>
    </data></array></value></member>
    </struct></value>
    </data></array></value></param>
    </params></methodCall>

Nous ajoutons donc un test afin de ne pas bloquer XML-RPC lorsque la requête provient de Jetpack :

// Interdire connexion XML-RPC sauf pour jetpack 
add_filter('xmlrpc_enabled', 'wpdf_bloque_XMLRPC');

function wpdf_bloque_XMLRPC () { 
	if ( isset( $_GET['for'] ) && 'jetpack' == $_GET['for'] ) return true;
	return false; 
} // fin fonction wpdf_bloque_XMLRPC

« if ( isset( $_GET[‘for’] ) && ‘jetpack’ == $_GET[‘for’] ) » vérifie si le paramétrage contenu dans l’adresse web contient « for=jetpack ». Si oui, les requêtes XML-RPC sont autorisées, sinon XML-RPC est bloqué.

Toutes les requêtes contenant « for=jetpack » dans le paramétrage de l’adresse web sont prises en charge par l’extension Jetpack si elle est activée. Jetpack est capable de s’assurer que la requête provient effectivement d’un serveur de la société Automattic. Ainsi, on est protégé contre un pirate qui se contenterait d’ajouter « for=jetpack » dans ses requêtes.

À noter : cette façon de procéder est préférable à celles consistant à vérifier si la requête provient d’un serveur de la société Automattic (vérification à partir de l’adresse IP). En effet, le support Jetpack met en garde sur le fait que les adresses IP peuvent changer.

Et si Jetpack n’est pas activé ? La réponse est simple : nous avons introduit une faille de sécurité car dans ce cas XML-RPC va traiter les requêtes pour laquelle un paramétrage « for=Jetpack » est introduit dans l’adresse web.

Nous devons donc compléter le code pour qu’il s’assure que l’extension Jetpack est active :

function wpdf_bloque_XMLRPC () {
 if ( isset( $_GET['for'] ) && 'jetpack' == $_GET['for'] ) { 
  include_once( ABSPATH . 'wp-admin/includes/plugin.php' );
  return is_plugin_active('jetpack/jetpack.php');
 }
 return false;
} // fin fonction wpdf_bloque_XMLRP

Le marqueur conditionnel is_plugin_active() appliqué à l’extension Jetpack renvoie « true » si l’extension est active et « false » sinon.
À noter : pour pouvoir utiliser le marqueur conditionnel ‘is_active_plugin() », le fichier « plugin.php » contenu dans le répertoire « wp-admin/includes » doit être préalablement chargé, ce qui est réalisé par l’instruction « include_once( ABSPATH . ‘wp-admin/includes/plugin.php’ ); »

Haut de page

Et pour d’autres applications?

D’autres extensions utilisent XML-RPC. Pour bloquer XML-RPC sans bloquer le fonctionnement normal de ces extensions, il faut pratiquer comme pour Jetpack :

  • disposer d’un moyen permettant d’identifier la source de la requête (interroger le support de l’application ou de l’extension),
  • modifier le code proposé pour Jetpack afin de ne pas bloquer XML-RPC s’il s’agit d’un appel provenant d’une extension valide
  • vérifier que l’xtension appelante est activée.
Haut de page

Le code de l’extension

Voici le code à insérer pour Jetpack :

  • dans le fichier » functions.php » (facile à installer, mais qui disparaît si on met à jour ou on change le thème WordPress courant)
    //	Interdire connexion XML-RPC sauf pour jetpack
    add_filter('xmlrpc_enabled', 'wpdf_bloque_XMLRPC');
    
    function wpdf_bloque_XMLRPC () {
    	if ( isset( $_GET['for'] ) && 'jetpack' == $_GET['for'] ) {		
    		include_once( ABSPATH . 'wp-admin/includes/plugin.php' );
    		return is_plugin_active('jetpack/jetpack.php');
    	}
    	
    	return false;
    } // fin fonction wpdf_bloque_XMLRPC
    Appel du crochet permettant de bloquer XML-RPC sauf pour Jetpack

    ou

  • dans un fichier d’extension déposé dans le répertoire « wp-content/plugins » (ce qui permet d’activer ou désactiver l’extension) ou dans le répertoire « wp-content/mu-plugins » (l’extension est alors toujours active) :
    <?php
    /*
    Plugin Name: XML-RPC (WPDF)
    Author: D Farnier
    AuthorURI: http://dfarnier.fr
    */
    
    if ( !defined('ABSPATH') ) exit ('Faites demi-tour !'); // Bloquer si la fonction n'est pas appelée depuis WordPress
    
    //	Interdire connexion XML-RPC sauf pour jetpack
    add_filter('xmlrpc_enabled', 'wpdf_bloque_XMLRPC');
    
    function wpdf_bloque_XMLRPC () {
    	if ( isset( $_GET['for'] ) && 'jetpack' == $_GET['for'] ) {		
    		include_once( ABSPATH . 'wp-admin/includes/plugin.php' );
    		return is_plugin_active('jetpack/jetpack.php');
    	}
    	
    	return false;
    } // fin fonction wpdf_bloque_XMLRPC
    
    ?>
    L'extension bloquant XML-RPC sauf pour Jetpack

Si vous n’en êtes pas (encore) familier, l’article ci-dessous décrit l’utilisation du fichier de thème « functions.php », des extensions (plugins) et des extensions automatiques (mu-plugins) :

Extensions (plugins, mu-plugins) et functions.php

Tester XML-RPC

Tester XML-RPC

4 réflexions sur « Bloquer XML-RPC, sauf pour … »

  1. Hello,

    c’est une bonne pratique de sécurité que de vouloir bloquer XML-RPC si nous n’en avons pas l’utilité. Par contre, un blocage au niveau serveur (si on y a accès) reste la méthode la plus efficace car moins gourmande en termes de ressources. On peut passer par fail2ban pour faire cela.

  2. Bonjour Aurélien,

    Merci pour ce complément d’information.
    En effet, la solution fail2ban ne doit pas être utilisée si on utilise par exemple Jetpack et probablement pas réalisable si on est sur un mutualisé.
    Je dirais que la solution que je propose est plutôt adaptée à des amateurs / débutants (ce qui est le propos de mon site) ta solution étant plutôt professionnelle.

    Daniel, qui a débuté WordPress en regardant WP Channel

      1. Bonne remarque, mais attention : les serveurs d’Automattic peuvent évoluer, c’est pourquoi le support Jetpack déconseille de se baser sur les adresses IP (j’avais trouvé une réponse de Jérémy Hervé sur ce point).

Laisser un commentaire

Votre adresse de messagerie ne sera pas publiée. Les champs obligatoires sont indiqués avec *