WordPress XML-RPC: Devre dışı bırakmanın 3 yolu & xmlrpc.php saldırılarını tespit etme | Jetpack istisnası

WordPress web sitenizin erişim günlüğünde aynı IP'den yüzlerce xmlrpc.php isteği art arda geliyorsa bu, WordPress XML-RPC'yi hedef alan bir şifre deneme saldırısıdır. Birden fazla WordPress sitesi çalıştıran Nginx + Apache yapısındaki bir sunucunun bir günlük erişim günlüğündeki 8.624 kaydı sınıflandırdım, devre dışı bırakmanın üç yolunu kendim uygulayıp yanıt kodlarını kontrol ettim ve PHP çalıştırmalarını da azaltmak için hangi katmanda engellemek gerektiğini derledim.
XML-RPC, HTTP üzerinden XML belgeleri alıp vererek WordPress işlevlerini uzaktan çağıran bir protokoldür; WordPress 3.5'ten beri ayarlar ekranında açıp kapatma seçeneği olmadığı için kurulumdan hemen sonra açık olarak çalışır.
1️⃣ xmlrpc.php'nin görevi ve kullanıldığı yerler
REST API çıktıktan sonra [xmlrpc.php] artık kullanılmayan bir dosya gibi görünse de Jetpack siteyi bugün hâlâ bu dosya üzerinden WordPress.com'a bağlar. Jetpack'in resmî belgeleri XML-RPC bağlantısına dayandığını açıkça belirtir; XML-RPC'yi varsayılan olarak engelleyen hostinglerde Jetpack bağlantısı hiç kurulamaz. Bugün bile ofiste bir faks numarasını tutmaya benzer.
WordPress 7.1 itibarıyla bu dosyanın kabul ettiği yöntem sayısı 77'dir: yazıları, ortamı ve yorumları yöneten wp ailesinden 50, eski blog protokollerinden (MetaWeblog, MovableType, Blogger) 23, pingback için 2 ve test amaçlı demo için 2.
wp ailesi istek gövdesindeki kullanıcı adı ve şifreyle giriş yaptığı için giriş ekranından geçmez. Yazı yazma ve düzenleme, ortam yükleme ve yorum yönetiminin hepsi bu ailededir; eski blog protokollerinin 23 yöntemi ise diğer blog araçlarıyla aynı şekilde yazı alıp vermek için korunmuştur.
demo.sayHello, WordPress XML-RPC'de bulunan bir test çağrısıdır. Gönderildiğinde yalnızca [Hello!] kelimesini döndürür; giriş gerektirmediği için XML-RPC'nin çalışıp çalışmadığını kontrol etmekte kullanılır. Eşi olan demo.addTwoNumbers iki sayıyı toplayıp sonucu döndürür.
Hepsi yalnızca POST ile gönderilen XML gövdesine yanıt verir; adresi tarayıcıda açarsanız [XML-RPC server accepts POST requests only.] iletisiyle birlikte 405 döner.
Pingback'ler de bu dosyanın işidir. Bir yazı yayımladığınızda metinde bağlantı verdiğiniz sitelerin xmlrpc.php dosyasına pingback gönderilir; alıcı sunucu gönderen adresi kendisi açarak bağlantının gerçekten var olup olmadığını kontrol eder.
2️⃣ Erişim günlüğünde xmlrpc.php saldırıları
Şifre deneme saldırıları giriş ekranından geçmeden [xmlrpc.php] üzerinden gelir. Birden fazla WordPress sitesi çalıştıran Nginx + Apache yapısındaki bir sunucunun 14 Ekim 00:00–20:00 arası erişim günlüğünde POST /xmlrpc.php isteği 8.624, IP sayısı 72'ydi; bunlardan 19 IP tam 300'er istek gönderdi.
Bir IP 14:09'dan 14:37'ye kadar 28 dakikada 300 istek gönderdi ve 5–6 saniyelik aralık sonuna kadar sabit kaldı. 8.524 istek User-Agent'ta Jetpack ya da WordPress.com yazarak geldi; aynı IP, [Jetpack by WordPress.com (Jetpack 13.0; WordPress 6.3)] gibi gerçek Jetpack biçimini taklit eden birkaç değeri dönüşümlü kullandı.
Aynı gün saat 14:00'e kadar güvenlik eklentisinin XML-RPC'yi kapatma ayarı bu istekleri 302 ile ana sayfaya geri yolladı; 14:00'ten sonra Nginx'te engellendiğinde ise 403 ile bitti. 302, gövde 0 bayt olsa bile her istekte PHP'nin çalıştığını gösterir; 403 ise PHP'den geçmemiş bir yanıttır.
3️⃣ system.multicall ve şifre deneme
[system.multicall] ile tek istekte yüzlerce şifrenin denendiğini söyleyen açıklamalar çoktur; ancak WordPress bir istek içinde giriş bir kez başarısız olursa kalan çağrıların şifrelerini karşılaştırmaz. Yalnızca ilk çağrı wp_authenticate'ten geçer, sonraki çağrılar kontrol edilmeden aynı hatayla, [Incorrect username or password.] ile yanıtlanır.
Her çağrı için yanıt yine de döndüğünden, 100 yanlış şifre taşıyan tek bir istek 0,12 saniyede 23 KB'lık bir yanıtla 100 hata alır. Aynı istekte doğru şifre sonra gelirse önceki çağrının başarısızlığı yüzünden o da reddedilir; başa konursa yalnızca o çağrı başarılı olur. Şifre karşılaştırması bir kez yapılır, ama XML ayrıştırma ve WordPress'in yüklenmesi her istekte tekrarlanır; bu yüzden bu saldırının sunucu yükü giriş kontrolünden değil, doğrudan istek sayısından kaynaklanır.
4️⃣ XML-RPC'yi devre dışı bırakmanın 3 yolu ve yanıt kodları
XML-RPC'yi eklentide kapatsanız da [xmlrpc.php] istekleri PHP'ye kadar gelir. Filtreyle kapalıyken 100 çağrılık bir istek gönderdiğimde yine HTTP 200 ile 100 hata (24 KB) döndü. İsteği hangi katmanın reddettiğine göre yöntem üçe ayrılır ve her birinin yanıt kodu farklıdır.
1. xmlrpc_enabled filtresiyle kodla kapatma
Temanın functions.php dosyasına [xmlrpc_enabled] filtresini false döndüren tek satırlık bir add_filter eklemeniz yeterlidir. Bu durumda giriş gerektiren çağrılar [XML-RPC services are disabled on this site.] hatası ve HTTP 405 ile reddedilir; ancak giriş gerektirmeyen test çağrısı demo.sayHello hâlâ 200 ile yanıt verir.
2. Eklenti ayarlarıyla kapatma: Perfmatters · Hide My WP
Perfmatters ve Hide My WP gibi eklentilerdeki Disable XML-RPC ayarıyla devre dışı bırakma yöntemidir. Hide My WP yukarıdakiyle aynı filtre yöntemini kullandığı için yanıtları da aynıdır; Perfmatters ise aynı filtreye ek olarak [xmlrpc.php]'ye gelen doğrudan istekleri 403 ile bitirir, pingback başlığını ve pingback bağlantısını da kaldırır; bu yüzden kapattıktan sonra GET de POST da 403 ile yanıtlanır. Ancak bu 403'ü vermek için WordPress init aşamasına kadar çalıştığından yanıt, açıkken olduğu gibi 0,13–0,15 saniye sürer ve PHP yükü kalır.
3. Web sunucusunda engelleme: Nginx · Apache
Nginx de Apache de isteği PHP'den önce reddettiği için eklenti yöntemlerinin aksine WordPress hiç çalışmaz.
# Nginx — server bloğu içinde, PHP işleyen location bloğunun üstüne
location = /xmlrpc.php {
deny all;
}Bu location bloğu PHP işleyen location bloğunun üstüne konur ve Nginx [xmlrpc.php] ile tam eşleşen istekleri hemen reddeder. Ekledikten sonra ayarın uygulanması için yapılandırmayı test edip yeniden yüklemeniz gerekir.
nginx -tnginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successfulsystemctl reload nginxYeniden yüklemeden sonra GET ve POST PHP'ye ulaşmadan 403 ile biter; yanıt gövdesi Nginx'in 153 baytlık varsayılan 403 sayfasıdır ve yanıt 0,02 saniye sürer.
# Apache — sitenin kök dizinindeki .htaccess (Apache 2.4)
<Files xmlrpc.php>
Require all denied
</Files>Yalnızca Apache kullanan sunucuda yukarıdaki Files yönergesini sitenin kök dizinindeki .htaccess dosyasına eklemeniz hemen etkili olur; Apache'nin varsayılan 403 sayfası (199 bayt) aynı 0,02 saniyede döner.
curl -s -o /dev/null -w '%{http_code}' -X POST https://example.com/xmlrpc.php -d '<methodCall><methodName>demo.sayHello</methodName></methodCall>'403Yukarıdaki komut test çağrısı demo.sayHello'yu POST ile gönderip yanıt kodunu kontrol eder; web sunucusunda engelledikten sonra 403 döner. [-o /dev/null] ve [-w] seçeneklerini çıkarıp gönderirseniz gövdeyi görürsünüz: [Hello!] gelirse açıktır. Yalnızca filtreyle kapatılan sitede de aynı yanıt geldiği için 405'i görmek için giriş çağrısı da göndermeniz gerekir.
5️⃣ Kapatılmaması gereken durumlar ve alternatifler
Web sunucusunda tamamen engellemek en büyük etkiyi sağlar, ancak Jetpack ile WordPress.com'a bağlı sitelere uymaz. Jetpack XML-RPC bağlantısına dayanır; WP Engine gibi XML-RPC'yi varsayılan olarak engelleyen hostinglerde bağlantının kurulması için Jetpack'in yönergelerine göre bir istisna açmanız gerekir. Pingback almak isteyen siteler için de durum aynıdır.
Bu tür siteler yalnızca Jetpack'in yayımladığı IP listesine (jetpack.com/ips-v4.txt) izin verip geri kalanını reddederek erişimi daraltır. Nginx'in location bloğuna her IP aralığı için bir allow satırı ekleyip sona deny all koymanız yeterlidir.
Tamamen engelleyemiyorsanız oturum açmamış isteklere dakika başına bir sınır koymak kalır. Ayar, wp-admin güvenliği yazısındaki Nginx hız sınırlama bölümüyle aynıdır; yalnızca giriş çerezi olmayan istekleri saydığı için oturum açmış yönetici işlerini etkilemez.
🔢 SSS & önerilen içerikler










ℹ️ Satış ortaklığı bildirimi
Bu sitenin içeriklerinde satış ortaklığı bağlantıları bulunur. Bir ziyaretçi bu bağlantılar üzerinden ürün veya hizmet satın alırsa bu site satıcıdan komisyon alır. Bu süreçte alıcının ödediği tutar (kampanya indirimlerinde tutar düşer↓) artmaz. Yayımlanan fiyat, indirim ve stok bilgileri yazının yazıldığı zamana aittir ve gerçek durumdan farklı olabilir; bu yüzden satın almadan önce son bilgiyi satıcıdan kontrol etmenizi rica ederiz. Ürünler kendi ölçütlerimize göre seçilir ve değerlendirilir; komisyon alınıp alınmaması tanıtım sırasını veya değerlendirme içeriğini etkilemez.