Перейти к содержимому
WebShield Docs

WordPress заваливают подбором паролей

Как отсечь подбор паролей к wp-login.php и xmlrpc.php и сканирование плагинов до того, как запросы дойдут до PHP, и закрыть сервер от прямых обращений.

Подбор паролей к wp-login.php и xmlrpc.php и сканирование плагинов нагружают сервер и при установленном плагине безопасности: плагин работает внутри WordPress, и к моменту отказа запрос уже запустил PHP.

Решение — отсекать такой трафик до сервера. Сайт подключается через WebShield, мусорные запросы останавливаются у нас, а сервер закрывается от прямых обращений.

Что получится: сайт работает через WebShield; сканеры, подбор паролей и инъекции останавливаются у нас, а до сервера доходят посетители. Прямой доступ к серверу в обход защиты закрыт. Понадобится: доступ к регистратору домена и к серверу — к конфигу веб-сервера или хотя бы к wp-config.php. Время: около часа, плюс ожидание смены NS.

Личный кабинет → Домены → Добавить домен, введите example.com. Оставьте импорт записей включённым и сверьте найденный список с текущей зоной. Особенно внимательно — почту: MX, SPF, DKIM, DMARC. Не нашлась запись — добавьте вручную, прежде чем менять NS.

Потом у регистратора замените NS на наши:

nsbox.webshield.pro
nshub.webshield.pro

Пока смена расходится по сети, всё работает по-старому. Когда статус домена станет Делегирован, переходите дальше. Подробности и перенос через AXFR — в справке Передача управления доменом.

DNS переносить нельзя или не хочется? Сайт подключается и записями у вашего провайдера — см. Подключение без смены NS, дальше всё так же.

  1. DNS → у записей example.com и www включите Прокси.
  2. Хосты → для каждого из двух имён включите Обязателен SSL и Перенаправлять HTTP на HTTPS. Сертификат мы выпустим сами за пару минут.

Ваш сервер при этом остаётся как есть и продолжает отвечать на 443-м порту: к нему мы тоже ходим по HTTPS, и сертификат, который на нём уже стоит, подойдёт.

Проверка:

Terminal window
curl -sI https://example.com/ | grep -i '^server'

Ответ server: WebShield.Pro значит, что запрос прошёл через нас.

С этого момента без всяких настроек работают сигнатуры против SQL-инъекций, XSS и обхода путей, отсев известных сканеров, ограничение частоты на формах входа, админке и xmlrpc.php, а адреса, которые настойчиво сканируют сайт, уходят в бан на всех наших узлах.

3. Верните WordPress настоящие адреса посетителей

Заголовок раздела «3. Верните WordPress настоящие адреса посетителей»

Теперь к серверу приходят наши узлы, и WordPress видит их адреса вместо адресов посетителей. Комментарии, журналы и плагины безопасности начнут путаться. Хуже всего с ограничителями попыток входа: заблокировав «нарушителя», такой плагин заблокирует наш узел — а вместе с ним всех, кто через него ходит.

Настоящий адрес мы передаём в заголовке X-Real-IP. Верить ему можно, только если запрос действительно пришёл от нас, иначе подделать адрес сможет кто угодно. Поэтому сначала возьмите секрет хоста: Хосты → хост → Доступ только через WebShield → Значение. Затем добавьте в wp-config.php перед строкой /* That's all, stop editing! */:

// Адрес посетителя от WebShield — только для запросов, пришедших через нас.
if (isset($_SERVER['HTTP_X_WEBSHIELD_ORIGIN_TOKEN'], $_SERVER['HTTP_X_REAL_IP'])
&& hash_equals('wso_ВАШ_ТОКЕН', $_SERVER['HTTP_X_WEBSHIELD_ORIGIN_TOKEN'])) {
$_SERVER['REMOTE_ADDR'] = $_SERVER['HTTP_X_REAL_IP'];
}

У example.com и www секреты разные. Если www только переадресует на основное имя, хватит секрета основного.

Адрес сервера никуда не делся: он остался в старых DNS-записях, в архивах и в базах сканеров. Кто его знает, обращается к сайту напрямую — мимо всего, что вы только что настроили. Поэтому сервер должен отвечать только запросам с тем же секретом.

Для nginx в блоке server вашего сайта:

if ($http_x_webshield_origin_token != "wso_ВАШ_ТОКЕН") { return 403; }

Для Apache — в начале .htaccess в корне WordPress:

<If "%{HTTP:X-WebShield-Origin-Token} != 'wso_ВАШ_ТОКЕН'">
Require all denied
</If>

Правку делайте в веб-сервере, а не в PHP: обновление WordPress её не затрёт, и отказ не будет стоить запуска PHP. Перед этим убедитесь, что сайт открывается через нас (шаг 2), и держите под рукой SSH или панель хостинга. Подробнее, в том числе для других серверов и с автобаном через fail2ban, — в руководстве Атакуют напрямую по IP сервера.

Проверка:

Terminal window
# Напрямую — ожидаем 403.
curl -sk -o /dev/null -w '%{http_code}\n' https://АДРЕС_СЕРВЕРА/ -H 'Host: example.com'
# Через нас — 200.
curl -s -o /dev/null -w '%{http_code}\n' https://example.com/

xmlrpc.php — старый интерфейс для удалённой публикации; им пользуются, например, Jetpack и некоторые мобильные приложения. Метод system.multicall позволяет одним запросом проверить много паролей. Если вы им не пользуетесь, закройте его на сервере:

location = /xmlrpc.php { return 403; }
<Files "xmlrpc.php">
Require all denied
</Files>

6. Включите проверку браузера — когда понадобится

Заголовок раздела «6. Включите проверку браузера — когда понадобится»

Всё, что выше, работает незаметно для посетителей. Если атака продолжается — ботнет подбирает пароли с тысяч адресов, и каждый адрес стучится редко, — включите на хосте Защита от ботов → Проверка браузера. Посетитель увидит экран проверки на секунду, а боты дальше не пройдут. Известных поисковых роботов проверка не задерживает.

Проверка останавливает и полезных роботов вашего же сайта. Перед включением добавьте в Исключения проверок на странице хоста:

  • /wp-cron.php — WordPress сам запускает фоновые задачи запросом к своему же адресу, и без исключения не выйдут отложенные записи и не отправятся письма;
  • адрес уведомлений платёжной системы — его подскажут настройки платёжного плагина. Адрес вида /?wc-api=… исключить нельзя (это корень сайта); включите в плагине адрес вида /wc-api/…;
  • /wp-json/ — если с сайтом работают мобильное приложение или внешние сервисы через REST API.

На исключённых путях сигнатуры, лимиты и баны продолжают действовать — снимается только экран проверки.

  • В Статистике на вкладке Защита растут «Атак отражено» и «IP заблокировано».
  • В логе сервера пропали запросы к wp-login.php с сотен адресов и запросы к несуществующим плагинам.
  • Нагрузка на процессор снизилась.
Симптом Причина и решение
Сайт отвечает 502 Сервер не отвечает нам на 443-м порту. Проверьте, что HTTPS на нём работает, или выключите Перенаправлять HTTP на HTTPS, чтобы мы ходили к нему по HTTP.
Бесконечная переадресация В WordPress адрес сайта начинается с http://, а мы переадресуем на HTTPS. В Настройки → Общие укажите адреса с https://.
После шага 4 сайт отвечает 403 всем Токен в конфиге не совпадает с кабинетом или вставлен от другого хоста. Сверьте значение.
Плагин безопасности заблокировал всех Шаг 3 не сделан или сделан после того, как плагин успел забанить адрес нашего узла. Добавьте код и очистите список блокировок плагина.
Не выходят запланированные записи Включена проверка браузера, а /wp-cron.php не в исключениях.
Не проходят оплаты Уведомления платёжной системы упираются в проверку браузера. Добавьте их адрес в исключения.