Безопасность WordPress: подводные камни типовых мер защиты
Один POST на xmlrpc.php может нести пачку попыток входа, и защита, привязанная к wp-login.php, её не увидит. Разбираем, где типовые меры WordPress дают ложное чувство безопасности и как это проверить по логам.

Один POST к xmlrpc.php выглядит в логе доступа как одна строка, а внутри может нести целую пачку попыток входа: метод system.multicall позволяет упаковать много вызовов в один запрос. Защита, которая считает неудачные входы только на wp-login.php, этого не увидит. Сайт при этом проходит все чек-листы. Ниже разобраны места, где типовые меры работают не так, как от них ждут, и способы проверить это на своём сервере. Материал написан для WordPress 6.x, Nginx и WP-CLI.
XML-RPC: старый протокол удалённых вызовов. Через единственный адрес xmlrpc.php к сайту обращаются внешние клиенты публикации и часть плагинов.
Главная поверхность атаки: сторонний код
Ядро WordPress обновляется быстро, а малые релизы безопасности по умолчанию ставятся автоматически. Основной риск лежит в плагинах и темах: у каждого свой автор, свой темп исправлений и своя вероятность оказаться заброшенным.
Отключённый плагин остаётся на диске
Деактивация убирает плагин из загрузки WordPress, но файлы остаются в wp-content/plugins. Если в плагине есть уязвимый файл, доступный по прямому URL, отключение его не прикрывает. Ненужный плагин и ненужную тему нужно удалять, а не выключать.
Автообновления: выигрыш и цена
С WordPress 5.5 автообновление включается для каждого плагина и темы отдельно. Выигрыш: исправление уязвимости приезжает без вас. Цена: обновление без проверки может сломать оформление заказа или вёрстку ночью, а о проблеме вы узнаете от клиента. Рабочий компромисс: автообновления для простых плагинов, а для платёжных модулей, WooCommerce и конструкторов страниц ручное обновление на копии сайта в день выхода релиза безопасности.
Меры, которые защищают меньше, чем кажется
У каждой популярной меры есть граница. Если её не знать, остаётся ощущение защиты без самой защиты.
| Мера | Что закрывает | Что остаётся открытым |
|---|---|---|
| Смена адреса wp-login.php плагином | Массовый перебор по стандартному адресу, шум в логах | XML-RPC, REST API, уже известные логины |
| Блокировка xmlrpc.php | Перебор через system.multicall | Форму входа и REST API |
| Лимит попыток входа или 2FA (плагины) | Подбор пароля | Уязвимости плагинов, для которых вход не нужен |
| DISALLOW_FILE_EDIT | Правку кода из встроенного редактора | Загрузку вредоносного плагина администратором |
| Запрет PHP в uploads | Запуск загруженного скрипта | Сам факт загрузки и код в плагинах и темах |
Скрыть дверь не значит запереть её: смена адреса входа убирает шум из логов, но не закрывает ни один другой вход.
XML-RPC: закрыть или оставить
Если вы не публикуете записи из внешних клиентов, закройте адрес на уровне веб-сервера, до PHP. Сначала проверьте, не нужен ли XML-RPC Jetpack или другим интеграциям: после блокировки они перестанут работать.
# Nginx, внутри блока server
location = /xmlrpc.php {
deny all;
}
После перезагрузки Nginx запрос к /xmlrpc.php должен вернуть 403.
Редактор файлов и установка кода
DISALLOW_FILE_EDIT скрывает редактор тем и плагинов в админке. Он не мешает администратору загрузить целый плагин. Константа DISALLOW_FILE_MODS жёстче: она блокирует установку и обновления через админку. Её часто включают и забывают, после чего сайт перестаёт получать патчи безопасности.
// WordPress 6.x. Добавьте выше строки с комментарием «That's all, stop editing!»
define( 'DISALLOW_FILE_EDIT', true );
// Блокирует и установку, и обновления через админку.
// Включайте, только если выкладываете код деплоем.
// define( 'DISALLOW_FILE_MODS', true );
PHP в каталоге загрузок
В uploads должны лежать картинки и документы, не скрипты. Запрет выполнения PHP там ломает типовой сценарий: загрузить файл-оболочку через дырявую форму и открыть его по URL.
# Nginx. Блок должен стоять выше общего обработчика .php
location ~* ^/wp-content/uploads/.*\.php$ {
deny all;
}
Логины на виду
Адрес вида /?author=1 перенаправляет на страницу автора, где в URL виден логин. REST API по умолчанию отдаёт список пользователей, у которых есть опубликованные записи. Полная блокировка REST для гостей ломает часть плагинов и фронтенд-функций, поэтому ограничивайте только маршрут пользователей. Подходящие фильтры описаны в Developer Resources на developer.wordpress.org.
Замеры: что и как мерить
Готовых цифр для вашего сайта у нас нет, и придумывать их нельзя. Зато есть четыре величины, которые снимаются за десять минут и дают базовую линию до любых изменений:
- нагрузка на вход: число POST на wp-login.php и xmlrpc.php за период лога;
- целостность файлов ядра и плагинов из каталога wordpress.org;
- состав администраторов: нет ли тех, кого вы не создавали;
- хвост обновлений: сколько плагинов ждут патча.
# Запускать из каталога сайта. Путь к логу зависит от вашей конфигурации
grep -c 'POST /wp-login.php' /var/log/nginx/access.log
grep -c 'POST /xmlrpc.php' /var/log/nginx/access.log
wp core verify-checksums
wp plugin verify-checksums --all
wp user list --role=administrator --fields=ID,user_login,user_email,user_registered
wp plugin list --update=available
Фиксируйте условия: за какой период лог, была ли ротация, на каком хостинге. Сравнивать цифры до и после правок имеет смысл только при одинаковом периоде.
Где подход ломается
- Порядок location в Nginx. Если общий обработчик .php стоит выше запрета для uploads, правило не сработает. Проверьте запросом к тестовому .php-файлу в uploads.
- verify-checksums для плагинов работает с каталогом wordpress.org. Платные плагины и самописный код команда проверить не может, их целостность нужно контролировать иначе.
- Резервные копии на том же сервере и под той же учётной записью. Тот, кто добрался до сайта, доберётся и до копий.
- Чистка после взлома без поиска входа. Удалили найденный файл, а дыра осталась: заражение вернётся.
- После инцидента смените пароли и ключи с солями в wp-config.php (AUTH_KEY и соседние). Это завершит все сессии, включая чужие.
Что делать дальше
- Снимите базовую линию командами выше и сохраните результат.
- Удалите неиспользуемые плагины и темы, а не отключайте.
- Решите по каждому плагину: автообновление или ручное на копии сайта.
- Раз в неделю смотрите число POST на wp-login.php и xmlrpc.php и список администраторов. Резкий рост любой из этих цифр — повод разбираться в тот же день.
- Проверьте восстановление из копии хотя бы раз: копия, которую не пробовали развернуть, остаётся предположением.
Логотип и фирменный стиль: Три концепции разного характера, палитра с обоснованием, проверка на читаемость в малом размере и в один цвет.
Спросить за 60 ₽Источники: Hardening WordPress, Advanced Administration Handbook, WP-CLI: wp core verify-checksums
Частые вопросы
Нужно ли закрывать xmlrpc.php?
Достаточно ли отключить плагин, если он больше не нужен?
А если у меня другая версия WordPress или нет WP-CLI?
После блокировки xmlrpc.php что-то перестало работать. Что делать?
Автообновления плагинов на проде: не сломают ли они сайт?
Достаточно ли после взлома удалить найденный вредоносный файл?
Материал носит информационный характер и подготовлен редакцией «Агентуры». Он не является офертой, рекламой или индивидуальной консультацией. Упомянутые продукты, компании и торговые знаки принадлежат их правообладателям. Перед принятием решений, влекущих юридические или финансовые последствия, обратитесь к профильному специалисту.