WordPress XML-RPC: 3 Wege zum Deaktivieren & xmlrpc.php-Angriffe erkennen | Jetpack-Ausnahme

Zeigt das Zugriffslog deiner WordPress-Website Hunderte xmlrpc.php-Anfragen hintereinander von derselben IP, ist das ein Passwortangriff auf WordPress XML-RPC. Ich habe die 8.624 Log-Einträge eines Tages auf einem Nginx + Apache-Server mit mehreren WordPress-Websites ausgewertet, die drei Wege zum Deaktivieren selbst angewendet und die Antwortcodes geprüft – um zu klären, auf welcher Ebene man sperren muss, damit auch die PHP-Ausführung wegfällt.
XML-RPC ist ein Protokoll, das XML-Dokumente über HTTP austauscht, um WordPress-Funktionen aus der Ferne aufzurufen. Seit WordPress 3.5 gibt es dafür keinen Schalter mehr in den Einstellungen, es läuft also ab der Installation eingeschaltet.
1️⃣ Was xmlrpc.php macht und wer es nutzt
Seit es die REST API gibt, hält man [xmlrpc.php] leicht für eine Datei, die niemand mehr nutzt – doch Jetpack verbindet deine Website bis heute über diese Datei mit WordPress.com. Die offizielle Jetpack-Dokumentation nennt die XML-RPC-Verbindung ausdrücklich als Voraussetzung, und bei Hostern, die XML-RPC standardmäßig sperren, scheitert schon die Jetpack-Verbindung. Das ist wie das eine Faxgerät, das im Büro immer noch steht.
Stand WordPress 7.1 nimmt diese Datei 77 Methoden an: 50 aus der wp-Familie für Beiträge, Medien und Kommentare, 23 aus den alten Blog-Protokollen (MetaWeblog, MovableType, Blogger), 2 für Pingbacks und 2 demo-Methoden zum Testen.
Die wp-Familie meldet sich mit Benutzername und Passwort aus dem Anfragetext an und kommt deshalb nie an der Login-Seite vorbei. Beiträge schreiben und bearbeiten, Medien hochladen, Kommentare verwalten – all das gehört zu dieser Familie; die 23 Methoden der alten Blog-Protokolle sind geblieben, damit andere Blog-Tools auf dieselbe Weise Beiträge austauschen können.
demo.sayHello ist ein Testaufruf, der in WordPress XML-RPC eingebaut ist. Schickst du ihn, kommt nur ein Wort zurück, [Hello!]; da kein Login nötig ist, prüft man damit, ob XML-RPC läuft. Sein Gegenstück demo.addTwoNumbers addiert zwei Zahlen und gibt die Summe zurück.
Alle antworten nur auf einen per POST gesendeten XML-Text; öffnest du die Adresse im Browser, kommt ein 405 mit der Meldung [XML-RPC server accepts POST requests only.] zurück.
Auch Pingbacks laufen über diese Datei. Veröffentlichst du einen Beitrag, geht ein Pingback an die xmlrpc.php jeder im Text verlinkten Website, und der empfangende Server öffnet die Absenderadresse selbst, um zu prüfen, ob der Link wirklich existiert.
2️⃣ xmlrpc.php-Angriffe im Zugriffslog
Passwortversuche laufen nicht über die Login-Seite, sondern über [xmlrpc.php]. Im Zugriffslog eines Nginx + Apache-Servers mit mehreren WordPress-Websites gab es am 14. Oktober zwischen 0 und 20 Uhr 8.624 POST-Anfragen an /xmlrpc.php von 72 IPs, und 19 dieser IPs schickten genau 300 Stück.
Eine IP schickte zwischen 14:09 und 14:37 Uhr in 28 Minuten 300 Anfragen, im gleichmäßigen Abstand von 5–6 Sekunden bis zum Schluss. 8.524 Anfragen trugen Jetpack oder WordPress.com im User-Agent, und dieselbe IP wechselte zwischen mehreren Werten, die das echte Jetpack-Format nachahmten, etwa [Jetpack by WordPress.com (Jetpack 13.0; WordPress 6.3)].
Bis 14 Uhr an diesem Tag schickte die XML-RPC-Aus-Einstellung des Sicherheits-Plugins diese Anfragen mit 302 zur Startseite; ab 14 Uhr, nach der Sperre in Nginx, endeten sie mit 403. Ein 302 heißt, dass PHP bei jeder Anfrage lief, auch wenn der Body 0 Byte hatte; ein 403 ist eine Antwort, die PHP nie erreicht hat.
3️⃣ system.multicall und Passwortversuche
Oft heißt es, mit [system.multicall] teste eine Anfrage Hunderte Passwörter – doch sobald innerhalb einer Anfrage ein Login fehlschlägt, prüft WordPress die Passwörter der übrigen Aufrufe nicht mehr. Nur der erste Aufruf durchläuft wp_authenticate, die folgenden bekommen ungeprüft denselben Fehler [Incorrect username or password.].
Da trotzdem für jeden Aufruf eine Antwort zurückkommt, bringt eine Anfrage mit 100 falschen Passwörtern 100 Fehler in einer 23 KB großen Antwort – in 0,12 Sekunden. Steht das richtige Passwort in derselben Anfrage weiter hinten, wird es wegen des vorherigen Fehlschlags mit abgelehnt; steht es vorn, gelingt nur dieser Aufruf. Das Passwort wird einmal verglichen, aber das Parsen des XML und das Laden von WordPress wiederholen sich bei jeder Anfrage – die Serverlast dieses Angriffs entsteht also durch die Zahl der Anfragen, nicht durch die Login-Prüfung.
4️⃣ 3 Wege, XML-RPC zu deaktivieren, und ihre Antwortcodes
Auch wenn ein Plugin XML-RPC abschaltet, erreichen Anfragen an [xmlrpc.php] weiterhin PHP. Mit gesetztem Filter habe ich eine Anfrage mit 100 Aufrufen geschickt – und trotzdem HTTP 200 mit 100 Fehlern (24 KB) bekommen. Je nachdem, auf welcher Ebene abgelehnt wird, gibt es drei Methoden, jede mit einem anderen Antwortcode.
1. Per Code über den Filter xmlrpc_enabled abschalten
Eine add_filter-Zeile in der functions.php des Themes, die den Filter [xmlrpc_enabled] auf false setzt, genügt. Aufrufe, die ein Login brauchen, werden dann mit dem Fehler [XML-RPC services are disabled on this site.] und HTTP 405 abgelehnt – der Testaufruf demo.sayHello, der kein Login braucht, antwortet aber weiterhin mit 200.
2. In den Plugin-Einstellungen abschalten: Perfmatters · Hide My WP
So deaktivierst du es über die Einstellung Disable XML-RPC in Plugins wie Perfmatters oder Hide My WP. Hide My WP arbeitet mit demselben Filter wie oben, die Antworten sind also gleich; Perfmatters beendet zusätzlich direkte Anfragen an [xmlrpc.php] mit 403 und entfernt Pingback-Header und Pingback-Link, sodass nach dem Abschalten GET und POST beide mit 403 antworten. Für diesen 403 läuft WordPress allerdings bis zur init-Phase, die Antwort dauert also 0,13–0,15 Sekunden – genauso lange wie im offenen Zustand – und die PHP-Last bleibt.
3. Auf dem Webserver sperren: Nginx · Apache
Ob Nginx oder Apache – die Anfrage wird vor PHP abgelehnt, WordPress läuft anders als bei den Plugin-Methoden gar nicht erst.
# Nginx — im server-Block, oberhalb der PHP-location
location = /xmlrpc.php {
deny all;
}Dieser location-Block kommt oberhalb der PHP-location, und Nginx lehnt Anfragen, die genau auf [xmlrpc.php] passen, sofort ab. Nach dem Eintragen die Konfiguration prüfen und neu laden, sonst greift sie nicht.
nginx -tnginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successfulsystemctl reload nginxAb dem Neuladen enden GET und POST mit 403, ohne PHP zu erreichen; der Antwort-Body ist die 153 Byte große Nginx-Standard-403-Seite, die Antwort dauert 0,02 Sekunden.
# Apache — .htaccess im Site-Root (Apache 2.4)
<Files xmlrpc.php>
Require all denied
</Files>Auf einem reinen Apache-Server trägst du die Files-Direktive oben in die .htaccess im Site-Root ein, und sie greift sofort; die Apache-Standard-403-Seite (199 Byte) kommt in denselben 0,02 Sekunden zurück.
curl -s -o /dev/null -w '%{http_code}' -X POST https://example.com/xmlrpc.php -d '<methodCall><methodName>demo.sayHello</methodName></methodCall>'403Der Befehl oben schickt den Testaufruf demo.sayHello per POST und prüft den Antwortcode; nach der Sperre auf dem Webserver kommt 403 zurück. Lässt du die Optionen [-o /dev/null] und [-w] weg, siehst du den Body: Kommt [Hello!], ist es offen – eine nur per Filter abgeschaltete Website antwortet aber genauso, deshalb musst du auch einen Login-Aufruf schicken, um den 405 zu sehen.
5️⃣ Wann du es nicht abschalten solltest – und die Alternativen
Die komplette Sperre auf dem Webserver wirkt am stärksten, passt aber nicht zu Websites, die über Jetpack mit WordPress.com verbunden sind. Jetpack ist auf die XML-RPC-Verbindung angewiesen, und bei Hostern, die XML-RPC standardmäßig sperren – etwa WP Engine – musst du nach Jetpacks Anleitung eine Ausnahme öffnen, bevor die Verbindung steht. Dasselbe gilt für Websites, die Pingbacks empfangen wollen.
Solche Websites grenzen es ein: Nur die von Jetpack veröffentlichte IP-Liste (jetpack.com/ips-v4.txt) wird erlaubt, alles andere abgelehnt. Im location-Block von Nginx kommt je IP-Bereich eine allow-Zeile, am Ende deny all.
Lässt es sich nicht komplett sperren, bleibt ein Limit pro Minute für Anfragen ohne Login. Die Einstellung ist dieselbe wie im Abschnitt zum Nginx-Rate-Limit im Beitrag wp-admin-Sicherheit ; gezählt werden nur Anfragen ohne Login-Cookie, eingeloggte Admin-Arbeit bleibt unberührt.
🔢 FAQ & empfohlene Inhalte










ℹ️ Affiliate-Hinweis
Die Inhalte dieser Website enthalten Affiliate-Links. Kauft ein Besucher über einen dieser Links ein Produkt oder eine Dienstleistung, erhält die Website vom Verkäufer eine Provision. Der Betrag, den der Käufer zahlt(bei Aktionsrabatten sinkt er ↓), steigt dadurch nicht. Angegebene Preise, Rabatte und Lagerbestände entsprechen dem Stand bei Erstellung und können abweichen; prüfe sie daher vor dem Kauf beim Verkäufer. Produkte werden nach eigenen Kriterien ausgewählt und bewertet, und Provisionen beeinflussen weder die Reihenfolge noch den Inhalt der Bewertungen.