XML-RPC di WordPress: 3 modi per disattivarlo & come riconoscere gli attacchi a xmlrpc.php | Eccezione Jetpack

Se nel log degli accessi del tuo sito WordPress compaiono centinaia di richieste a xmlrpc.php di fila dallo stesso IP, si tratta di tentativi di indovinare le password tramite XML-RPC di WordPress. Ho classificato 8.624 righe di un giorno di log degli accessi di un server Nginx + Apache che gestisce diversi siti WordPress, ho applicato di persona i tre modi per disattivarlo controllando i codici di risposta e ho riassunto a quale livello bisogna bloccarlo per ridurre anche l'esecuzione di PHP.
XML-RPC è un protocollo che scambia documenti XML via HTTP per richiamare funzioni di WordPress da remoto; da WordPress 3.5 la voce per attivarlo e disattivarlo non c'è più nelle impostazioni, quindi resta attivo fin dall'installazione.
1️⃣ A cosa serve xmlrpc.php e chi lo usa
Da quando esiste la REST API è facile considerare [xmlrpc.php] un file che nessuno usa più, ma Jetpack collega ancora il sito a WordPress.com proprio tramite questo file. La documentazione ufficiale di Jetpack dice chiaramente che dipende dalla connessione XML-RPC, e sugli hosting che bloccano XML-RPC per impostazione predefinita la connessione di Jetpack non riesce proprio. È come un ufficio che ancora oggi tiene un numero di fax.
Con WordPress 7.1 questo file accetta 77 metodi: 50 della famiglia wp, che gestiscono articoli, media e commenti, 23 dei vecchi protocolli per blog (MetaWeblog, MovableType, Blogger), 2 per i pingback e 2 demo di prova.
La famiglia wp effettua il login con nome utente e password contenuti nel corpo della richiesta, quindi non passa dalla schermata di login. Scrivere e modificare articoli, caricare media e gestire i commenti appartengono tutti a questa famiglia, mentre i 23 metodi dei vecchi protocolli per blog sono rimasti per scambiare articoli come fanno altri strumenti di blogging.
demo.sayHello è una chiamata di prova inclusa in XML-RPC di WordPress. Se la invii restituisce solo la parola [Hello!] e, poiché non richiede il login, si usa per verificare che XML-RPC funzioni. La sua gemella demo.addTwoNumbers somma due numeri e restituisce il risultato.
Rispondono tutti solo a un corpo XML inviato in POST; se apri l'indirizzo nel browser, torna un 405 con il messaggio [XML-RPC server accepts POST requests only.].
Anche i pingback passano da questo file. Quando pubblichi un articolo, un pingback viene inviato a xmlrpc.php dei siti linkati nel testo, e il server che lo riceve apre da sé l'indirizzo di provenienza per verificare che il link esista davvero.
2️⃣ Attacchi a xmlrpc.php visti nel log degli accessi
Il tentativo di indovinare le password non passa dalla schermata di login ma entra da [xmlrpc.php]. Nel log degli accessi di un server Nginx + Apache che gestisce diversi siti WordPress, il 14 ottobre dalle 0:00 alle 20:00 le richieste POST /xmlrpc.php sono state 8.624 da 72 IP, e 19 di questi IP ne hanno inviate esattamente 300 ciascuno.
Un IP ha inviato 300 richieste in 28 minuti, dalle 14:09 alle 14:37, con un intervallo di 5-6 secondi costante fino alla fine. 8.524 richieste sono arrivate con Jetpack o WordPress.com nello User-Agent, e lo stesso IP alternava più valori che imitavano il vero formato di Jetpack, come [Jetpack by WordPress.com (Jetpack 13.0; WordPress 6.3)].
Fino alle 14:00 di quel giorno la disattivazione di XML-RPC del plugin di sicurezza rimandava queste richieste alla home con un 302; dopo le 14:00, con il blocco in Nginx, sono finite con un 403. Il 302 è il risultato di PHP eseguito a ogni richiesta, anche se il corpo era di 0 byte; il 403 è una risposta che non è passata da PHP.
3️⃣ system.multicall e tentativi di indovinare le password
Molte spiegazioni dicono che con [system.multicall] si provano centinaia di password in una sola richiesta, ma quando un login fallisce una volta all'interno della richiesta, WordPress non confronta più le password delle chiamate successive. Solo la prima chiamata passa da wp_authenticate; le altre ricevono, senza controllo, lo stesso errore: [Incorrect username or password.].
Poiché per ogni chiamata torna comunque una risposta, una sola richiesta con 100 password sbagliate riceve 100 errori in una risposta da 23 KB in 0,12 secondi. Se nella stessa richiesta la password giusta sta più avanti, viene rifiutata insieme a causa del fallimento precedente; se sta all'inizio, riesce solo quella chiamata. La password viene confrontata una volta sola, ma l'analisi dell'XML e il caricamento di WordPress si ripetono a ogni richiesta, quindi il carico di questo attacco sul server nasce dal numero di richieste in sé, non dal controllo del login.
4️⃣ 3 modi per disattivare XML-RPC e i codici di risposta
Anche se disattivi XML-RPC in un plugin, le richieste a [xmlrpc.php] arrivano fino a PHP. Con il filtro attivo ho inviato una richiesta da 100 chiamate e sono tornati comunque HTTP 200 e 100 errori (24 KB). A seconda del livello che rifiuta la richiesta, i metodi sono tre e ognuno ha un codice di risposta diverso.
1. Disattivarlo via codice con il filtro xmlrpc_enabled
Basta aggiungere al functions.php del tema una riga di add_filter che fa restituire false al filtro [xmlrpc_enabled]. In questo stato le chiamate che richiedono il login vengono rifiutate con l'errore [XML-RPC services are disabled on this site.] e HTTP 405, ma la chiamata di prova demo.sayHello, che non richiede il login, risponde ancora con 200.
2. Disattivarlo dalle impostazioni del plugin: Perfmatters · Hide My WP
È il metodo che lo disattiva con l'impostazione Disable XML-RPC di plugin come Perfmatters o Hide My WP. Hide My WP usa lo stesso filtro visto sopra e quindi dà le stesse risposte, mentre Perfmatters, oltre al filtro, chiude con un 403 le richieste dirette a [xmlrpc.php] e rimuove anche l'header e il link di pingback, così dopo la disattivazione sia GET sia POST rispondono 403. Per produrre quel 403, però, WordPress viene eseguito fino alla fase init, quindi la risposta richiede 0,13–0,15 secondi, lo stesso tempo di quando è aperto, e il carico di PHP rimane.
3. Bloccarlo sul server web: Nginx · Apache
Che sia Nginx o Apache, la richiesta viene rifiutata prima di PHP, quindi, a differenza dei metodi con plugin, WordPress non viene eseguito.
# Nginx — dentro il blocco server, sopra il location che gestisce PHP
location = /xmlrpc.php {
deny all;
}Questo blocco location va messo sopra il location che gestisce PHP, e Nginx rifiuta subito le richieste che corrispondono esattamente a [xmlrpc.php]. Dopo averlo aggiunto, verifica la configurazione e ricaricala perché abbia effetto.
nginx -tnginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successfulsystemctl reload nginxDopo il ricaricamento GET e POST finiscono con un 403 senza arrivare a PHP; il corpo della risposta è la pagina 403 predefinita di Nginx da 153 byte e la risposta arriva in 0,02 secondi.
# Apache — .htaccess nella cartella principale del sito (Apache 2.4)
<Files xmlrpc.php>
Require all denied
</Files>Su un server che usa solo Apache basta inserire la direttiva Files qui sopra nel .htaccess della cartella principale del sito perché valga subito, e la pagina 403 predefinita di Apache (199 byte) torna negli stessi 0,02 secondi.
curl -s -o /dev/null -w '%{http_code}' -X POST https://example.com/xmlrpc.php -d '<methodCall><methodName>demo.sayHello</methodName></methodCall>'403Il comando qui sopra invia in POST la chiamata di prova demo.sayHello e controlla il codice di risposta; dopo il blocco sul server web torna 403. Se lo invii senza le opzioni [-o /dev/null] e [-w] vedi il corpo: se arriva [Hello!] è aperto. Un sito disattivato solo con il filtro dà la stessa risposta, quindi per verificare il 405 devi inviare anche una chiamata di login.
5️⃣ Quando non disattivarlo e le alternative
Bloccarlo del tutto sul server web è il metodo più efficace, ma non va bene per i siti collegati a WordPress.com tramite Jetpack. Jetpack dipende dalla connessione XML-RPC e, sugli hosting che bloccano XML-RPC per impostazione predefinita come WP Engine, per collegarsi bisogna aprire un'eccezione seguendo le indicazioni di Jetpack. Lo stesso vale per i siti che vogliono ricevere i pingback.
Questi siti restringono l'accesso consentendo solo l'elenco di IP pubblicato da Jetpack (jetpack.com/ips-v4.txt) e rifiutando il resto. Basta inserire nel blocco location di Nginx una riga allow per ogni intervallo di IP e chiudere con deny all.
Se non puoi bloccarlo del tutto, resta un limite al minuto per le richieste non autenticate. La configurazione è la stessa della sezione sul limite di richieste di Nginx nell'articolo Sicurezza di wp-admin e, poiché conta solo le richieste senza cookie di login, non tocca il lavoro di amministrazione svolto da connessi.
🔢 FAQ & contenuti consigliati










ℹ️ Informativa sull'affiliazione
I contenuti di questo sito includono link di affiliazione. Se un visitatore acquista un prodotto o un servizio tramite uno di questi link, il sito riceve una commissione dal venditore. In questo processo l'importo pagato dall'acquirente (durante le promozioni l'importo scende↓) non aumenta. Prezzi, sconti e disponibilità indicati si riferiscono al momento della stesura e possono differire da quelli reali: prima di acquistare verifica sempre presso il venditore. I prodotti vengono scelti e valutati secondo criteri propri, e le commissioni non influiscono sull'ordine di presentazione né sul contenuto delle valutazioni.