Полностью отключать XML-RPC в WordPress удобно только до первого случая, когда он нужен для внешнего сервиса: мобильного клиента, старого интеграционного скрипта или удалённой публикации. В реальных проектах чаще требуется не «выключить всё», а ограничить доступ по IP: закрыть лишние запросы, но оставить белый список для доверенных источников.
Ниже — рабочий вариант для темы, плагина или mu-plugin: сначала разберём, как понять, что XML-RPC действительно используется, затем ограничим доступ по IP и проверим, что ничего лишнего не сломали.
Когда имеет смысл ограничивать XML-RPC, а не отключать его полностью
XML-RPC до сих пор встречается в интеграциях, которые не переведены на REST API. Если просто убрать его целиком, можно получить неочевидные ошибки в стороннем софте. Поэтому задача обычно выглядит так: разрешить запросы только с нескольких адресов, а всё остальное отклонять на уровне WordPress.
Такой подход полезен, если:
- есть старый клиент публикации или синхронизации;
- нужно оставить доступ для конкретного сервиса мониторинга или редакторского инструмента;
- вы хотите уменьшить поверхность атаки без полной поломки интеграций;
- на сервере нет удобной фильтрации на уровне nginx/Apache, и проще сделать это в WordPress.
Диагностика: кто вообще обращается к xmlrpc.php
Перед изменениями стоит понять, есть ли живые обращения к xmlrpc.php. Если их нет, возможно, проще отключить XML-RPC полностью. Если обращения есть, полезно увидеть источник и частоту.
Что смотреть в логах
На сервере проверьте access log веб-сервера. Ищите запросы к /xmlrpc.php и смотрите IP, user-agent и частоту. Если запросы идут пачками с разных адресов, это типичный шум брутфорса. Если обращения редкие и с одного адреса, это может быть реальная интеграция.
grep "xmlrpc.php" /var/log/nginx/access.log | tail -n 50Если логов на сервере нет или доступ к ним ограничен, можно временно добавить простой лог в WordPress через mu-plugin, но для продакшена лучше опираться на серверные логи.
Проверка текущего поведения
Откройте /xmlrpc.php в браузере или запросите его через curl. Если XML-RPC доступен, WordPress обычно отвечает сообщением о том, что это сервер XML-RPC, либо возвращает ошибку при POST-запросе без корректного тела. Это не доказательство безопасности, но помогает понять, что endpoint жив.
curl -i https://example.com/xmlrpc.phpПошаговое решение: блокируем XML-RPC для всех, кроме белого списка IP
Самый предсказуемый вариант — использовать фильтр xmlrpc_enabled. Он возвращает true или false и позволяет отключать XML-RPC выборочно. Ниже пример, который разрешает доступ только с указанных IP.
<?php
/**
* Plugin Name: XML-RPC IP Allowlist
* Description: Разрешает XML-RPC только с доверенных IP.
*/
add_filter('xmlrpc_enabled', function ($enabled) {
$allowed_ips = array(
'203.0.113.10',
'198.51.100.25',
);
$remote_ip = $_SERVER['REMOTE_ADDR'] ?? '';
if ($remote_ip && in_array($remote_ip, $allowed_ips, true)) {
return true;
}
return false;
});Этот вариант простой, но у него есть ограничение: он сработает уже внутри WordPress. То есть запрос сначала дойдёт до PHP. Если атака массовая, лучше дополнить блокировкой на уровне nginx, Cloudflare или другого reverse proxy.
Если нужен более жёсткий вариант
Можно не только выключать XML-RPC, но и отдавать 403 Forbidden для всех, кроме белого списка. Для этого удобнее использовать ранний хук init и проверять сам запрос к xmlrpc.php.
<?php
add_action('init', function () {
if (defined('XMLRPC_REQUEST') && XMLRPC_REQUEST) {
$allowed_ips = array(
'203.0.113.10',
'198.51.100.25',
);
$remote_ip = $_SERVER['REMOTE_ADDR'] ?? '';
if (!in_array($remote_ip, $allowed_ips, true)) {
status_header(403);
header('Content-Type: text/plain; charset=utf-8');
exit('XML-RPC access denied');
}
}
});Такой код лучше размещать в отдельном мини-плагине или mu-plugin, а не в functions.php активной темы. Тогда правило не пропадёт при смене темы.
Сравнение подходов: плагин, код или серверный уровень
| Подход | Плюсы | Минусы | Когда выбирать |
|---|---|---|---|
Код через xmlrpc_enabled | Быстро, прозрачно, легко поддерживать | Запрос доходит до PHP | Нужен белый список IP без сложной инфраструктуры |
| Блокировка в nginx/Apache | Режет трафик раньше WordPress | Нужен доступ к конфигу сервера | Есть много мусорных запросов и нужен жёсткий фильтр |
| Плагин безопасности | Удобно для админов без кода | Лишняя зависимость, иногда больше настроек, чем нужно | Нужен быстрый интерфейс и уже используется security-плагин |
Если у вас уже стоит плагин безопасности, проверьте, не отключает ли он XML-RPC сам. Дублировать одно и то же правило в нескольких местах — частая причина путаницы при отладке.
Как проверить, что ограничение сработало
После внедрения проверьте два сценария: доступ с разрешённого IP и отказ для всех остальных.
- С разрешённого адреса отправьте тестовый запрос к
xmlrpc.php. - С другого IP повторите тот же запрос.
- Проверьте, что WordPress не возвращает 200 OK для запрещённого адреса.
- Убедитесь, что сторонний сервис, которому вы оставили доступ, продолжает работать.
Для быстрой проверки можно использовать curl с сервера, который не входит в белый список. В ответ должен быть 403 или отказ на уровне сервера.
curl -i -X POST https://example.com/xmlrpc.php \
-H 'Content-Type: text/xml' \
--data '<?xml version="1.0"?><methodCall><methodName>system.listMethods</methodName></methodCall>'Если вы используете nginx, дополнительно проверьте access log: запросы к xmlrpc.php должны либо не доходить до PHP, либо завершаться отказом. Если видите 200 OK на запрещённом IP, значит правило не применилось или сработало не там, где ожидалось.
Частые ошибки и как их исправить
Белый список сравнивают с неправильным IP
На сайте за прокси или CDN в $_SERVER['REMOTE_ADDR'] может приходить не реальный клиент, а адрес промежуточного сервера. В таком случае правило будет работать не так, как задумано. Если у вас есть Cloudflare или другой reverse proxy, сначала убедитесь, что WordPress получает корректный исходный IP.
Правило кладут в functions.php
Это рабочий, но хрупкий вариант. При смене темы или обновлении кастомной темы защита исчезнет. Для таких задач лучше использовать mu-plugin или отдельный мини-плагин.
Одновременно включают несколько способов блокировки
Например, XML-RPC отключён в плагине безопасности, затем добавлен фильтр в теме и ещё правило в nginx. В итоге сложно понять, почему интеграция перестала работать. Сначала оставьте один способ, проверьте его, и только потом добавляйте дополнительный слой защиты.
Не проверяют зависимые сервисы
Самая неприятная ошибка — закрыть XML-RPC и заметить проблему уже после того, как редакторы или внешние сервисы перестали публиковать материалы. После изменения обязательно прогоните реальный сценарий: авторизацию, публикацию, синхронизацию или pingback, если он у вас ещё используется.
Практические советы по безопасности и производительности
Если XML-RPC вам не нужен вообще, серверная блокировка обычно лучше, чем фильтр в WordPress: меньше лишней нагрузки и меньше точек отказа. Но если нужен частичный доступ, не пытайтесь «разрешить всё и потом фильтровать внутри плагина» — это оставляет лишний шум в логах и даёт атакующему лишний шанс.
- Храните список IP в одном месте, а не размазывайте по теме и плагинам.
- После изменения конфигурации делайте тест с реального внешнего адреса, а не только с localhost.
- Если доступ нужен временно, оставляйте комментарий в коде с причиной и сроком.
- Проверяйте, не дублирует ли вашу логику security-плагин или WAF.
Если на сайте уже используется Clearfy Pro, имеет смысл сначала посмотреть, не закрывает ли он XML-RPC и другие лишние точки входа. Но даже в этом случае для точечного allowlist по IP часто удобнее оставить собственное правило, чтобы не зависеть от общей настройки плагина: https://wpshop.ru/plugins/clearfy.
Когда правило уже в продакшене, раз в несколько дней смотрите логи: если запрещённые запросы продолжаются, значит блокировка работает, и можно оценить, не пора ли перенести её на уровень сервера. Если же нужный сервис начал получать отказ, первым делом проверьте IP и наличие прокси между сервисом и сайтом.