WordPress XML-RPC: 3 manieren om het uit te schakelen & xmlrpc.php-aanvallen herkennen | Jetpack-uitzondering

Affiliatemelding v3.1
Affiliatemelding v3.2 (mobiel)

Zie je in de toegangslog van je WordPress-website honderden xmlrpc.php-verzoeken achter elkaar vanaf hetzelfde IP, dan is dat wachtwoordraden gericht op WordPress XML-RPC. Ik heb 8.624 regels uit één dag toegangslog van een Nginx + Apache-server met meerdere WordPress-sites ingedeeld, de drie manieren om het uit te schakelen zelf toegepast en de responscodes gecontroleerd, en zet hier op een rij op welke laag je moet blokkeren om ook de PHP-uitvoering terug te dringen.

XML-RPC is een protocol dat XML-documenten via HTTP uitwisselt om WordPress-functies op afstand aan te roepen. Sinds WordPress 3.5 staat er in de instellingen geen schakelaar meer voor, dus het staat vanaf de installatie aan.

1️⃣ Wat xmlrpc.php doet en wie het gebruikt

Sinds de REST API er is, lijkt [xmlrpc.php] een bestand dat niemand meer gebruikt, maar Jetpack verbindt je site nog altijd via dit bestand met WordPress.com. De officiële Jetpack-documentatie zegt uitdrukkelijk dat het van de XML-RPC-verbinding afhangt, en bij hosting die XML-RPC standaard blokkeert, mislukt de Jetpack-verbinding helemaal. Het is als een kantoor dat nog steeds één faxnummer aanhoudt.

Vanaf WordPress 7.1 accepteert dit bestand 77 methoden: 50 uit de wp-familie voor berichten, media en reacties, 23 uit de oude blogprotocollen (MetaWeblog, MovableType, Blogger), 2 voor pingbacks en 2 demo-methoden om te testen.

De wp-familie logt in met de gebruikersnaam en het wachtwoord in de body van het verzoek en gaat dus niet via het inlogscherm. Berichten schrijven en bewerken, media uploaden en reacties beheren vallen allemaal onder deze familie; de 23 oude blogprotocolmethoden zijn gebleven zodat berichten op dezelfde manier als met andere blogtools kunnen worden uitgewisseld.

demo.sayHello is een testaanroep die in WordPress XML-RPC is ingebouwd. Stuur je hem, dan krijg je alleen het woord [Hello!] terug; omdat er geen login voor nodig is, wordt hij gebruikt om te controleren of XML-RPC werkt. Zijn tegenhanger demo.addTwoNumbers telt twee getallen op en geeft de som terug.

Ze reageren allemaal alleen op een XML-body die via POST wordt verstuurd; open je het adres in een browser, dan krijg je een 405 met de melding [XML-RPC server accepts POST requests only.].

Ook pingbacks lopen via dit bestand. Publiceer je een bericht, dan gaat er een pingback naar de xmlrpc.php van elke site waarnaar je in de tekst linkt, en de ontvangende server opent zelf het verzendende adres om te controleren of de link echt bestaat.

🧭 Verzoeken aan xmlrpc.php en hoe ze worden afgehandeld
📨 Afzender
↓
Ingang
xmlrpc.php
Verwerkt alleen een XML-body die via POST is verstuurd
405 · XML-RPC server accepts POST requests only.
77 methoden
wp.*berichten · media · reacties, 50
metaWeblog · mt · bloggeroude blogprotocollen, 23
pingback.*pingbacks, 2
demo.*testaanroepen om de werking te controleren, 2
Resultaat
Houdt de verbinding met WordPress.com in stand
Controleert gebruikersnaam en wachtwoord in de body van het verzoek → schrijft en bewerkt berichten
De server opent zelf het verzendende adres om de link te controleren
Zonder login: Hello! Antwoord
Geen verwerking
Jetpack houdt de verbinding met WordPress.com via dit bestand in stand, dus als je het bestand blokkeert, valt de verbinding weg.
Externe publicatietools loggen in met de gebruikersnaam en het wachtwoord in de body van het verzoek en slaan het inlogscherm over.
Er gaat een pingback naar de xmlrpc.php van de site waarnaar het bericht linkt, en de ontvangende server opent zelf het verzendende adres om de link te controleren.
demo.sayHello is een testaanroep die controleert of XML-RPC werkt; hij antwoordt zonder login met het ene woord [Hello!].
Open je het adres in een browser, dan krijg je een 405 met de melding [XML-RPC server accepts POST requests only.].

2️⃣ xmlrpc.php-aanvallen in de toegangslog

Wachtwoordraden gaat niet via het inlogscherm, maar komt binnen via [xmlrpc.php]. In de toegangslog van een Nginx + Apache-server met meerdere WordPress-sites stonden op 14 oktober van 0:00 tot 20:00 uur 8.624 POST /xmlrpc.php-verzoeken van 72 IP-adressen, en 19 daarvan stuurden er precies 300.

Eén IP stuurde in 28 minuten, van 14:09 tot 14:37 uur, 300 verzoeken met tot het eind een vaste tussenpoos van 5 à 6 seconden. 8.524 verzoeken kwamen binnen met Jetpack of WordPress.com in de User-Agent, en hetzelfde IP wisselde meerdere waarden af die het echte Jetpack-formaat nabootsten, zoals [Jetpack by WordPress.com (Jetpack 13.0; WordPress 6.3)].

Tot 14:00 uur die dag stuurde de XML-RPC-uitschakeling van de beveiligingsplugin deze verzoeken met een 302 terug naar de homepage; vanaf 14:00 uur, na de blokkade in Nginx, eindigden ze met een 403. Een 302 betekent dat PHP voor elk verzoek draaide, ook al was de body 0 bytes; een 403 is een antwoord dat PHP nooit heeft geraakt.

🧭 Een xmlrpc.php-aanval in één regel van de toegangslog
Uitlegdiagram
🛡️ Serverstatus
Eén regel uit de toegangslog (Nginx access.log)
203.0.113.25IP[14/Oct/2026:14:09:04 +0900]Tijd"POST /xmlrpc.php HTTP/1.1"Verzoek302403Status0153Bytes"Jetpack by WordPress.com (Jetpack 13.0; WordPress 6.3)"User-Agent
PHP draait · 302 naar homeZonder PHP · standaard 403-pagina van Nginx
Heeft een beveiligingsplugin XML-RPC uitgeschakeld, dan wordt er een 302 gelogd die het verzoek terugstuurt naar de homepage. De body is 0 bytes, maar PHP draait om die 302 te maken.
Blokkeer je het in Nginx, dan worden een 403 en de standaardfoutpagina van 153 bytes gelogd, en draait PHP niet.
Verzoeken van hetzelfde IP
14:09:0414:37:20
300 in 28 minuten, om de 5–6 s
8.624 POST-verzoeken van 0:00 tot 20:0072 IP-adressen19 IP-adressen stuurden er elk 3008.524 met een nagebootste Jetpack/WordPress.com-UA

3️⃣ system.multicall en wachtwoordraden

Veel uitleg zegt dat je met [system.multicall] in één verzoek honderden wachtwoorden kunt testen, maar zodra een login binnen een verzoek één keer mislukt, controleert WordPress de wachtwoorden van de overige aanroepen niet meer. Alleen de eerste aanroep gaat door wp_authenticate; de rest krijgt zonder controle dezelfde fout terug: [Incorrect username or password.].

Omdat er voor elke aanroep toch een antwoord terugkomt, levert één verzoek met 100 verkeerde wachtwoorden binnen 0,12 seconden 100 fouten op in een antwoord van 23 KB. Staat het juiste wachtwoord verderop in hetzelfde verzoek, dan wordt het samen met de eerdere mislukking geweigerd; staat het vooraan, dan slaagt alleen die aanroep. Het wachtwoord wordt maar één keer vergeleken, maar het verwerken van de XML en het laden van WordPress gebeuren bij elk verzoek opnieuw, dus de serverbelasting van deze aanval komt niet van de logincontrole maar van het aantal verzoeken zelf.

4️⃣ 3 manieren om XML-RPC uit te schakelen en hun responscodes

Ook als je XML-RPC in een plugin uitschakelt, komen verzoeken aan [xmlrpc.php] tot in PHP. Met het filter actief stuurde ik een verzoek met 100 aanroepen en kreeg ik gewoon HTTP 200 terug met 100 fouten (24 KB). Afhankelijk van de laag die het verzoek weigert, zijn er drie methoden, elk met een andere responscode.

1. Uitschakelen in code met het filter xmlrpc_enabled

Zet in de functions.php van je thema één add_filter-regel die het filter [xmlrpc_enabled] false laat teruggeven. Aanroepen waarvoor een login nodig is, worden dan geweigerd met de fout [XML-RPC services are disabled on this site.] en HTTP 405, maar de testaanroep demo.sayHello, waarvoor geen login nodig is, antwoordt nog steeds met 200.

2. Uitschakelen in de plugininstellingen: Perfmatters · Hide My WP

Hierbij schakel je het uit met een Disable XML-RPC-instelling in een plugin zoals Perfmatters of Hide My WP. Hide My WP gebruikt hetzelfde filter als hierboven en geeft dus dezelfde antwoorden, maar Perfmatters beëindigt bovenop dat filter directe verzoeken aan [xmlrpc.php] met een 403 en verwijdert ook de pingback-header en de pingback-link; na het uitschakelen antwoorden GET en POST dus allebei met 403. Om die 403 te geven, draait WordPress echter nog tot aan de init-fase, waardoor het antwoord 0,13–0,15 seconden duurt, net zo lang als wanneer het openstaat, en de PHP-belasting blijft.

🔌 XML-RPC uitschakelen in de plugininstellingen
📍 Settings › Perfmatters › General › Core › Disable XML-RPC
Zet de schakelaar aan en klik op [Save Changes]; het bezoekersscherm hieronder verandert.
Beheerscherm
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
Vink het aan en klik op [Save Settings]; het bezoekersscherm hieronder verandert.
Beheerscherm
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)
Scherm van een uitgelogde bezoeker — verzoeken met de opgeslagen instellingen
405
XML-RPC server accepts POST requests only.
GET-verzoeken krijgen bij elke instelling een 405.
200
Hello!
Het is een testaanroep om de werking te controleren, dus hij antwoordt zonder login.
200
faultCode 403 · Incorrect username or password.
De wachtwoordcontrole wordt uitgevoerd. Dat blijft zo als je de login-URL wijzigt.
403
Geen body
Perfmatters beëindigt het in de init-fase met een 403. PHP draait wel.
403
Geen body
Perfmatters beëindigt het in de init-fase met een 403. PHP draait wel.
403
Geen body
Eindigt met een 403 zonder wachtwoordcontrole. PHP draait wel.
200
Hello!
Het werkt via het filter, dus aanroepen zonder login blijven antwoorden.
405
faultCode 405 · XML-RPC services are disabled on this site.
Alleen aanroepen waarvoor een login nodig is, worden geweigerd.

3. Blokkeren op de webserver: Nginx · Apache

Of het nu Nginx of Apache is, het verzoek wordt vóór PHP geweigerd, dus anders dan bij de pluginmethoden draait WordPress helemaal niet.

# Nginx — in het server-blok, boven de PHP-location
location = /xmlrpc.php {
    deny all;
}

Zet dit location-blok boven de PHP-location; Nginx weigert dan meteen elk verzoek dat precies overeenkomt met [xmlrpc.php]. Test na het toevoegen de configuratie en laad die opnieuw, anders wordt het niet toegepast.

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

Vanaf het herladen eindigen GET en POST met een 403 zonder PHP te bereiken; de body is de standaard 403-pagina van Nginx van 153 bytes en het antwoord duurt 0,02 seconden.

# Apache — .htaccess in de hoofdmap van de site (Apache 2.4)
<Files xmlrpc.php>
    Require all denied
</Files>

Op een server met alleen Apache zet je de Files-instructie hierboven in de .htaccess in de hoofdmap van de site; die geldt meteen, en de standaard 403-pagina van Apache (199 bytes) komt in dezelfde 0,02 seconden terug.

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

Het commando hierboven stuurt de testaanroep demo.sayHello via POST en controleert de responscode; na een blokkade op de webserver komt er 403 terug. Laat je de opties [-o /dev/null] en [-w] weg, dan zie je de body: komt er [Hello!] terug, dan staat het open. Een site die alleen met het filter is uitgeschakeld geeft hetzelfde antwoord, dus om de 405 te zien moet je ook een login-aanroep sturen.

5️⃣ Wanneer je het niet moet uitschakelen, en de alternatieven

Alles in één keer op de webserver blokkeren heeft het grootste effect, maar past niet bij sites die via Jetpack met WordPress.com zijn verbonden. Jetpack hangt af van de XML-RPC-verbinding, en bij hosting die XML-RPC standaard blokkeert, zoals WP Engine, moet je volgens de instructies van Jetpack een uitzondering openzetten voordat de verbinding werkt. Hetzelfde geldt voor sites die pingbacks willen ontvangen.

Zulke sites beperken het door alleen de IP-lijst toe te laten die Jetpack publiceert (jetpack.com/ips-v4.txt) en de rest te weigeren. Zet in het location-blok van Nginx een allow-regel per IP-bereik en eindig met deny all.

Kun je het niet volledig blokkeren, dan blijft er een limiet per minuut over voor verzoeken die niet zijn ingelogd. De instelling is dezelfde als het onderdeel over de Nginx-snelheidsbeperking in het artikel wp-admin beveiligen — omdat alleen verzoeken zonder login-cookie worden geteld, heeft het geen invloed op beheerwerk terwijl je bent ingelogd.

🔢 FAQ & aanbevolen content

Ook als je het verwijdert, kopieert de volgende update van de WordPress-kern het bestand uit het pakket gewoon terug, dus bij de volgende update is het er weer. In plaats van het bestand te verwijderen kun je dat adres beter op de webserver blokkeren of het met het filter uitschakelen; dat blijft ook na updates staan.

De REST API is een aparte ingang via het adres [wp-json] en blijft dus openstaan, ook als je XML-RPC uitschakelt. De blokeditor gebruikt deze ingang, dus schakel hem niet helemaal uit, maar blokkeer alleen verzoeken van uitgelogde bezoekers.

Ze controleren het niet, ze sturen gewoon. Bij WordPress staat dit bestand op elke site op hetzelfde pad, dus scanners veranderen alleen het domein en sturen POST-verzoeken. Een standaard-WordPress verraadt het adres van xmlrpc.php bovendien zelf, via de link [EditURI] in de head van de pagina en de header [X-Pingback] bij berichten die pingbacks accepteren.

🛡️ Aanbevolen content over WordPress-beveiliging 8 artikelen · 2 extern
🗂️ WordPress-beveiliging
📋 wp-admin beveiligen 📄 9 maatregelen tegen brute force 📄 Hide My WP 📄 Beveiligingsplugins: top 5
📄 XML-RPC uitschakelen 📄 REST API 📄 Pingbacks · trackbacks 📄 wp-config.php beveiligen
📡 Nanaco Japan: xmlrpc.php-aanvallen aanpakken 📡 サイトの主治医: xmlrpc.php uitschakelen en controleren
Geen zoekresultaten.

ℹ️ Affiliatemelding
De content van deze site bevat affiliatelinks. Koopt een bezoeker via een van deze links een product of dienst, dan ontvangt deze site een commissie van de verkoper. Het bedrag dat de koper betaalt (bij acties gaat het omlaag ↓) wordt daardoor niet hoger. De vermelde prijzen, kortingen en voorraad gelden op het moment van schrijven en kunnen afwijken; controleer ze daarom vóór je aankoop bij de verkoper. Producten worden gekozen en beoordeeld volgens onze eigen criteria, en commissies hebben geen invloed op de volgorde of de inhoud van de beoordelingen.