WordPress XML-RPC: 3 sposoby wyłączenia & jak rozpoznać ataki na xmlrpc.php | Wyjątek dla Jetpack

Informacja o linkach partnerskich v3.1
Informacja o linkach partnerskich v3.2 (wersja mobilna)

Jeśli w logach dostępu witryny na WordPressie widać setki żądań do xmlrpc.php z rzędu z tego samego IP, to zgadywanie haseł wymierzone w WordPress XML-RPC. Sklasyfikowano 8624 wpisy z jednego dnia logów dostępu serwera Nginx + Apache, na którym działa kilka witryn na WordPressie, samodzielnie zastosowano trzy sposoby wyłączenia, sprawdzając kody odpowiedzi, i zebrano, na której warstwie trzeba blokować, aby ograniczyć także uruchamianie PHP.

XML-RPC to protokół, który przez HTTP wymienia dokumenty XML, aby zdalnie wywoływać funkcje WordPressa; od WordPressa 3.5 w ustawieniach nie ma już przełącznika, więc działa włączony od razu po instalacji.

1️⃣ Do czego służy xmlrpc.php i kto z niego korzysta

Od pojawienia się REST API łatwo uznać [xmlrpc.php] za plik, którego nikt już nie używa, ale Jetpack wciąż łączy przez niego witrynę z WordPress.com. Oficjalna dokumentacja Jetpack wprost mówi, że zależy on od połączenia XML-RPC, a na hostingu, który domyślnie blokuje XML-RPC, samo połączenie Jetpack się nie udaje. To jak biuro, które nadal trzyma jeden numer faksu.

W WordPressie 7.1 ten plik przyjmuje 77 metod: 50 z rodziny wp, obsługujących wpisy, media i komentarze, 23 ze starych protokołów blogowych (MetaWeblog, MovableType, Blogger), 2 do pingbacków i 2 testowe metody demo.

Rodzina wp loguje się nazwą użytkownika i hasłem z treści żądania, więc nie przechodzi przez ekran logowania. Pisanie i edycja wpisów, przesyłanie mediów i zarządzanie komentarzami należą do tej rodziny, a 23 metody starych protokołów blogowych pozostawiono, aby wymieniać wpisy tak samo jak inne narzędzia blogowe.

demo.sayHello to wywołanie testowe wbudowane w XML-RPC WordPressa. Po wysłaniu zwraca tylko jedno słowo, [Hello!], a ponieważ nie wymaga logowania, służy do sprawdzania, czy XML-RPC działa. Jego para, demo.addTwoNumbers, dodaje dwie liczby i zwraca wynik.

Wszystkie odpowiadają tylko na treść XML wysłaną metodą POST; jeśli otworzysz adres w przeglądarce, wraca 405 z komunikatem [XML-RPC server accepts POST requests only.].

Pingbacki to też zadanie tego pliku. Po opublikowaniu wpisu pingback trafia do xmlrpc.php witryn, do których linkujesz w treści, a serwer odbiorcy sam otwiera adres nadawcy, by sprawdzić, czy link naprawdę istnieje.

🧭 Żądania do xmlrpc.php i ich obsługa
Zabezpieczenie wp-adminDiagram objaśniający
📨 Nadawca
↓
Wejście
xmlrpc.php
Przetwarza tylko treść XML wysłaną metodą POST
405 · XML-RPC server accepts POST requests only.
77 metod
wp.*wpisy · media · komentarze, 50
metaWeblog · mt · bloggerstare protokoły blogowe, 23
pingback.*pingbacki, 2
demo.*wywołania testowe do sprawdzenia działania, 2
Wynik
Utrzymuje połączenie z WordPress.com
Sprawdza nazwę użytkownika i hasło w treści żądania → tworzy i edytuje wpisy
Serwer sam otwiera adres nadawcy i sprawdza link
Bez logowania: Hello! Odpowiedź
Brak przetwarzania
Jetpack utrzymuje połączenie z WordPress.com przez ten plik, więc zablokowanie pliku zrywa połączenie.
Zewnętrzne narzędzia do publikacji logują się nazwą użytkownika i hasłem umieszczonymi w treści żądania, z pominięciem ekranu logowania.
Pingback trafia do xmlrpc.php witryny, do której linkuje wpis, a serwer odbiorcy sam otwiera adres nadawcy i sprawdza link.
demo.sayHello to wywołanie testowe sprawdzające, czy XML-RPC działa; bez logowania odpowiada jednym słowem: [Hello!].
Jeśli otworzysz adres w przeglądarce, wraca 405 z komunikatem [XML-RPC server accepts POST requests only.].

2️⃣ Ataki na xmlrpc.php w logach dostępu

Zgadywanie haseł nie przechodzi przez ekran logowania, tylko wchodzi przez [xmlrpc.php]. W logach dostępu serwera Nginx + Apache, na którym działa kilka witryn na WordPressie, 14 października od 0:00 do 20:00 zarejestrowano 8624 żądania POST /xmlrpc.php z 72 adresów IP, a 19 z nich wysłało dokładnie po 300.

Jedno IP wysłało 300 żądań w 28 minut, od 14:09 do 14:37, a odstęp 5–6 sekund był stały do końca. 8524 żądania przyszły z Jetpack lub WordPress.com w polu User-Agent, a to samo IP na zmianę używało kilku wartości naśladujących prawdziwy format Jetpack, np. [Jetpack by WordPress.com (Jetpack 13.0; WordPress 6.3)].

Tego dnia do 14:00 wyłączenie XML-RPC we wtyczce bezpieczeństwa odsyłało te żądania na stronę główną kodem 302, a po 14:00, po zablokowaniu w Nginx, kończyły się kodem 403. Kod 302 oznacza, że PHP uruchamiało się przy każdym żądaniu, choć treść miała 0 bajtów, a 403 to odpowiedź, która nie przeszła przez PHP.

🧭 Atak na xmlrpc.php w jednym wierszu logu dostępu
Diagram objaśniający
🛡️ Stan serwera
Jeden wiersz logu dostępu (Nginx access.log)
203.0.113.25IP[14/Oct/2026:14:09:04 +0900]Czas"POST /xmlrpc.php HTTP/1.1"Żądanie302403Stan0153Bajty"Jetpack by WordPress.com (Jetpack 13.0; WordPress 6.3)"User-Agent
PHP działa · 302 na stronę głównąBez PHP · domyślna strona 403 Nginx
Gdy wtyczka bezpieczeństwa wyłączy XML-RPC, w logu pojawia się 302 odsyłające żądanie na stronę główną. Treść ma 0 bajtów, ale PHP uruchamia się, by wygenerować to 302.
Po zablokowaniu w Nginx w logu pojawia się 403 i domyślna strona błędu o rozmiarze 153 bajtów, a PHP się nie uruchamia.
Żądania z tego samego IP
14:09:0414:37:20
300 w 28 minut, co 5–6 s
8624 żądania POST od 0:00 do 20:0072 adresy IP19 adresów IP wysłało po 3008524 z fałszywym UA Jetpack/WordPress.com

3️⃣ system.multicall i zgadywanie haseł

Wiele opisów mówi, że [system.multicall] pozwala sprawdzić setki haseł w jednym żądaniu, ale gdy w obrębie żądania logowanie raz się nie powiedzie, WordPress nie porównuje już haseł z pozostałych wywołań. Tylko pierwsze wywołanie przechodzi przez wp_authenticate, a kolejne bez sprawdzania dostają ten sam błąd: [Incorrect username or password.].

Ponieważ na każde wywołanie i tak wraca odpowiedź, jedno żądanie ze 100 błędnymi hasłami dostaje w 0,12 sekundy 100 błędów w odpowiedzi o rozmiarze 23 KB. Jeśli w tym samym żądaniu poprawne hasło stoi dalej, zostaje odrzucone razem z wcześniejszą porażką, a jeśli stoi na początku, udaje się tylko to wywołanie. Hasło porównuje się raz, ale analiza XML i ładowanie WordPressa powtarzają się przy każdym żądaniu, więc obciążenie serwera przy tym ataku wynika z samej liczby żądań, a nie ze sprawdzania logowania.

4️⃣ 3 sposoby wyłączenia XML-RPC i kody odpowiedzi

Nawet po wyłączeniu XML-RPC we wtyczce żądania do [xmlrpc.php] docierają do PHP. Przy włączonym filtrze żądanie ze 100 wywołaniami i tak zwróciło HTTP 200 i 100 błędów (24 KB). Zależnie od warstwy, która odrzuca żądanie, są trzy metody i każda daje inny kod odpowiedzi.

1. Wyłączenie w kodzie filtrem xmlrpc_enabled

Wystarczy dodać w functions.php motywu jedną linię add_filter, która ustawia filtr [xmlrpc_enabled] na false. Wywołania wymagające logowania są wtedy odrzucane z błędem [XML-RPC services are disabled on this site.] i HTTP 405, ale wywołanie testowe demo.sayHello, które nie wymaga logowania, nadal odpowiada kodem 200.

2. Wyłączenie w ustawieniach wtyczki: Perfmatters · Hide My WP

To metoda wyłączenia ustawieniem Disable XML-RPC we wtyczkach takich jak Perfmatters czy Hide My WP. Hide My WP działa tym samym filtrem co wyżej, więc odpowiedzi też są takie same, natomiast Perfmatters oprócz filtra kończy bezpośrednie żądania do [xmlrpc.php] kodem 403 i usuwa jeszcze nagłówek oraz link pingback, dlatego po wyłączeniu zarówno GET, jak i POST odpowiadają 403. Żeby jednak zwrócić to 403, WordPress uruchamia się aż do etapu init, więc odpowiedź trwa 0,13–0,15 sekundy, tyle samo co przy otwartym pliku, a obciążenie PHP zostaje.

📍 Settings › Perfmatters › General › Core › Disable XML-RPC
Włącz przełącznik i kliknij [Save Changes] – ekran odwiedzającego poniżej się zmieni.
Panel administracyjny
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
Zaznacz pole i kliknij [Save Settings] – ekran odwiedzającego poniżej się zmieni.
Panel administracyjny
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)
Ekran niezalogowanego odwiedzającego — żądania z zapisanymi ustawieniami
405
XML-RPC server accepts POST requests only.
Żądania GET dostają 405 przy każdym ustawieniu.
200
Hello!
To wywołanie testowe do sprawdzania działania, więc odpowiada bez logowania.
200
faultCode 403 · Incorrect username or password.
Porównanie hasła jest wykonywane. Zmiana adresu logowania niczego tu nie zmienia.
403
Brak treści
Perfmatters kończy je kodem 403 na etapie init. PHP się uruchamia.
403
Brak treści
Perfmatters kończy je kodem 403 na etapie init. PHP się uruchamia.
403
Brak treści
Kończy się kodem 403 bez porównania hasła. PHP się uruchamia.
200
Hello!
To metoda filtra, więc wywołania niewymagające logowania nadal odpowiadają.
405
faultCode 405 · XML-RPC services are disabled on this site.
Odrzucane są tylko wywołania wymagające logowania.

3. Blokada na serwerze WWW: Nginx · Apache

Zarówno Nginx, jak i Apache odrzucają żądanie przed PHP, więc w przeciwieństwie do metod z wtyczką WordPress w ogóle się nie uruchamia.

# Nginx — w bloku server, nad blokiem location obsługującym PHP
location = /xmlrpc.php {
    deny all;
}

Ten blok location umieszcza się nad blokiem location obsługującym PHP, a Nginx od razu odrzuca żądania dokładnie pasujące do [xmlrpc.php]. Po dodaniu trzeba sprawdzić konfigurację i ją przeładować, aby zaczęła działać.

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

Od przeładowania GET i POST kończą się kodem 403, nie docierając do PHP; treść odpowiedzi to domyślna strona 403 Nginx o rozmiarze 153 bajtów, a odpowiedź trwa 0,02 sekundy.

# Apache — .htaccess w katalogu głównym witryny (Apache 2.4)
<Files xmlrpc.php>
    Require all denied
</Files>

Na serwerze z samym Apache wystarczy dodać powyższą dyrektywę Files do .htaccess w katalogu głównym witryny, by działała od razu, a domyślna strona 403 Apache (199 bajtów) wraca w tych samych 0,02 sekundy.

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

Powyższe polecenie wysyła metodą POST wywołanie testowe demo.sayHello i sprawdza kod odpowiedzi; po zablokowaniu na serwerze WWW wraca 403. Jeśli wyślesz je bez opcji [-o /dev/null] i [-w], zobaczysz treść: [Hello!] oznacza, że plik jest otwarty. Witryna wyłączona tylko filtrem odpowiada tak samo, więc żeby zobaczyć 405, trzeba wysłać też wywołanie logowania.

5️⃣ Kiedy nie wyłączać i co zamiast tego

Całkowita blokada na serwerze WWW daje największy efekt, ale nie pasuje do witryn połączonych z WordPress.com przez Jetpack. Jetpack zależy od połączenia XML-RPC, a na hostingu, który domyślnie blokuje XML-RPC, jak WP Engine, połączenie działa dopiero po otwarciu wyjątku zgodnie z instrukcjami Jetpack. To samo dotyczy witryn, które chcą odbierać pingbacki.

Takie witryny zawężają dostęp, dopuszczając tylko listę IP publikowaną przez Jetpack (jetpack.com/ips-v4.txt) i odrzucając resztę. Wystarczy w bloku location Nginx dodać po jednej linii allow na każdy zakres IP i zakończyć poleceniem deny all.

Jeśli nie da się zablokować go całkowicie, pozostaje limit na minutę dla niezalogowanych żądań. Ustawienia są takie same jak w części o limicie żądań w Nginx w artykule Zabezpieczenie wp-admin — liczone są tylko żądania bez ciasteczka logowania, więc nie ma to wpływu na pracę zalogowanego administratora.

🔢 FAQ & polecane treści

Nawet po usunięciu aktualizacja rdzenia WordPressa skopiuje plik z pakietu z powrotem, więc wróci przy następnej aktualizacji. Zamiast usuwać plik, lepiej zablokować ten adres na serwerze WWW albo wyłączyć go filtrem – to zostaje także po aktualizacjach.

REST API to osobne wejście pod adresem [wp-json], więc pozostaje otwarte nawet po wyłączeniu XML-RPC. Edytor blokowy korzysta z tego wejścia, dlatego zamiast wyłączać je całkowicie, lepiej blokować tylko żądania niezalogowanych.

Nie sprawdzają, po prostu wysyłają. W WordPressie ten plik leży w każdej witrynie pod tą samą ścieżką, więc skanery zmieniają tylko domenę i wysyłają POST. Domyślny WordPress sam ujawnia adres xmlrpc.php przez link [EditURI] w sekcji head strony i nagłówek [X-Pingback] we wpisach przyjmujących pingbacki.

🛡️ Polecane treści o bezpieczeństwie WordPressa 8 artykułów · 2 zewnętrzne
🗂️ Bezpieczeństwo WordPressa
📋 Zabezpieczenie wp-admin 📄 9 sposobów na brute force 📄 Hide My WP 📄 5 najlepszych wtyczek bezpieczeństwa
📄 Wyłączenie XML-RPC 📄 REST API 📄 Pingbacki · trackbacki 📄 Bezpieczeństwo wp-config.php
📡 Nanaco Japan: jak radzić sobie z atakami na xmlrpc.php 📡 サイトの主治医: wyłączenie xmlrpc.php i sprawdzenie
Brak wyników wyszukiwania.

ℹ️ Informacja o linkach partnerskich
Treści tej witryny zawierają linki partnerskie. Jeśli odwiedzający kupi produkt lub usługę przez taki link, witryna otrzymuje od sprzedawcy prowizję. Kwota płacona przy tym przez kupującego (podczas promocji spada↓) nie wzrasta. Podane ceny, rabaty i dostępność odnoszą się do chwili pisania i mogą różnić się od stanu faktycznego, dlatego przed zakupem sprawdź je u sprzedawcy. Produkty wybieramy i oceniamy według własnych kryteriów, a prowizja nie wpływa ani na kolejność prezentacji, ani na treść ocen.