xmlrpc.php עדיין מגיב – חסימה ברמת השרת היא חובה

ביטול XML-RPC ב-WordPress לא מספיק כל עוד הקובץ עדיין מגיב. רק חסימה ברמת השרת באמת סוגרת.

בדיקה זו עוקבת אחרי xmlrpc: גם כשתוסף או mu-plugin מבטל את XML-RPC לוגית (filter xmlrpc_enabled), הקובץ xmlrpc.php עדיין נטען וה-PHP עדיין רץ. הבדיקה אומרת בפשטות: שלחתי בקשה לקובץ, וקיבלתי תגובת 200 או 405 – לא 403/404. כלומר, הקובץ עדיין נגיש.

למה זה משנה

קובץ שמחזיר 405 או 200 הוא קובץ שהשרת מסכים לטפל בו. זה אומר שגם אם WordPress פנימית מסרב להריץ method, הוא קודם מבצע בקשת HTTP מלאה: מתחיל PHP, טוען את ה-bootstrap של WordPress, מתחבר ל-DB, ואז דוחה את הבקשה. תוקף שמריץ שיטות הגברת התקפה עם 1,000 ניסיונות סיסמה גורם להפעלת PHP מלא 1,000 פעם. גם בלי הצלחה בפריצה, זה צריכת CPU מסיבית – effectively DoS על השרת. בנוסף, פגיעות RCE עתידית בקובץ xmlrpc.php עדיין תעבוד כי הקובץ נטען. חסימה ברמת השרת מבטלת את כל זה: השרת מחזיר 403 לפני שמגיעים ל-PHP בכלל.

איך לזהות

curl -I https://example.com/xmlrpc.php

תוצאה אחת מהשתיים:

  • חסום נכון: HTTP/1.1 403 Forbidden או HTTP/1.1 404 Not Found
  • פגיע: HTTP/1.1 200 OK או HTTP/1.1 405 Method Not Allowed

בדיקה עמוקה יותר עם POST:

curl -X POST -d '<methodCall><methodName>system.listMethods</methodName></methodCall>' \
     -w "Status: %{http_code}\n" \
     https://example.com/xmlrpc.php

תגובת 403 = חסום. תגובת XML עם רשימת methods, או "XML-RPC services are disabled" = הקובץ נטען (פגיע).

איך לתקן

Apache – הוסף ל-.htaccess בשורש האתר:

<Files xmlrpc.php>
    Require all denied
</Files>

Nginx – הוסף ב-server block (לא ב-htaccess כי Nginx לא קורא htaccess):

location = /xmlrpc.php {
    deny all;
    access_log off;
    log_not_found off;
}

access_log off ו-log_not_found off חשובים: בלעדיהם, ה-access.log מתמלא במהירות בניסיונות. עם השרת מחזיר 403 בלי לוג, התקיפה לא מותירה רושם.

LiteSpeed (כמו Apache לרוב, אבל גם דרך LSWS):

<Files xmlrpc.php>
    Require all denied
</Files>

Cloudflare (אם בשימוש לפני המקור): גש ל-Security > WAF > Custom rules. צור rule: (http.request.uri.path eq "/xmlrpc.php") > Action: Block. זה חוסם ב-edge לפני שהבקשה מגיעה לשרת.

אם תוסף ספציפי דורש XML-RPC (Jetpack בתצורה ישנה), התר רק IP-ים מורשים:

<Files xmlrpc.php>
    Require ip 192.0.64.0/18
    Require ip 76.74.255.0/24
</Files>

טעויות נפוצות

טעות ראשונה: לסמוך על "Disable XML-RPC" plugin. רובם רק מוסיפים filter PHP, לא חוסמים ברמת השרת. אחרי הפעלת התוסף, הקובץ עדיין מחזיר 200/405 ולא 403. בדוק תמיד עם curl. טעות שנייה: לחסום ב-.htaccess בשרת nginx. nginx לא קורא htaccess – אם זה השרת שלך, החוקים יושבים בלי השפעה. שאל את ספק האחסון מה השרת בפועל. טעות שלישית: לחסום בלי לטפל ב-WAF/CDN שלפני המקור. אם Cloudflare מעביר את הבקשה ל-origin ושם היא חסומה, זה תקין – אבל האידיאל הוא לחסום גם ב-edge כדי לחסוך bandwidth ו-CPU. טעות רביעית: לבדוק רק אחרי שינוי ולא אחרי 24 שעות. תוסף קאש כמו LiteSpeed Cache לפעמים שומר response של xmlrpc.php במטמון – ה-curl הראשון יראה 200 גם אחרי החסימה, עד שה-cache יפוג.

בדיקה לאחר תיקון

הרץ שוב את שני curl-ים מ"איך לזהות". שניהם חייבים להחזיר 403 (Apache/Cloudflare) או 444/404 (Nginx). אם אתה מקבל 200 או 405, החסימה לא נטענה. בדוק את ה-config: apachectl configtest או nginx -t, ואז systemctl reload apache2 או nginx -s reload. אחרי 5 דקות, חזור על הבדיקה. סיים בהרצת האודיט והוודא שגם xmlrpc וגם xmlrpc_reachable עוברים.

טיפ: אם XML-RPC חסום ויש לך Cloudflare, הוסף "Block xmlrpc.php" ל-WAF rules. זה חוסם 100% מהבקשות לפני שהן מגיעות לשרת – חיסכון משמעותי בעומס במהלך התקפת brute-force.