Предотвращение взлома WordPress — это не продукт, который вы устанавливаете после взлома. Это рутинная работа, которую вы делаете до него, и практически вся она представляет собой реакцию на трафик, который уже бьет по вашему сайту прямо сейчас. Откройте свой лог доступа, и вы сможете в реальном времени наблюдать за первой стадией практически каждого взлома WordPress: бот подтверждает, что вы используете WordPress, сканирует ваши плагины и тестирует вход. Эта статья разбирает этот лог строка за строкой, а затем разбивает цепочку атак стадия за стадией с помощью конфигурации, которую вы уже контролируете.
Я отвечаю за безопасность WordPress в портфолио сайтов компании Squirrly, и самая полезная привычка, которую я приобрел, — это отношение к логу доступа как к прямой трансляции стадии разведки, а не как к криминалистическому артефакту, который я открываю только после того, как что-то пошло не так. Инструменты обнаружения говорят вам, что атака произошла. Лог говорит вам, что она происходит прямо сейчас — и это единственный момент, когда профилактика стоит дешево.
Трехэтапная цепочка и почему разрушать нужно именно первый этап
Автоматизированные атаки на WordPress почти всегда проходят по одной и той же схеме из трех этапов: разведка, эксплуатация и закрепление. Разведка — это запросы бота по предсказуемым путям для подтверждения WordPress и определения версий. Эксплуатация — это украденные учетные данные или неисправленная уязвимость. Закрепление — это бэкдор, который он оставляет, чтобы вернуться. Три этапа означают три места для разрыва цепочки, и самый дешевый разрыв — первый, потому что зондирование, не дающее никаких полезных результатов, никогда не переходит в эксплуатацию.
Причина, по которой профилактика превосходит стратегию «патчить быстрее»: окно эксплуатации сузилось. Согласно отчету Patchstack State of WordPress Security in 2026, среди активно эксплуатируемых уязвимостей 20% были атакованы в течение шести часов после публичного раскрытия, 45% — в течение 24 часов и 70% — в течение семи дней. Количество уязвимостей с высокой степенью эксплуатируемости выросло на 113% год к году. Вы не сможете вручную устанавливать патчи быстрее шестичасового окна для каждого используемого вами плагина. Вы можете сделать так, чтобы уязвимый элемент был изначально недоступен.
Читайте разведку в своем логе доступа
Начните с количественной оценки того, что уже сканирует вас. В комбинированных логах nginx путь запроса — это поле 7, поэтому следующая команда считает основные цели разведки по всему содержимому лога:
# Top probed WordPress paths
awk '{print $7}' /var/log/nginx/access.log \
| grep -Ei 'wp-login|xmlrpc|wp-admin|author=|wp-json/wp/v2/users|wp-content/plugins' \
| sort | uniq -c | sort -rn | head -20
Затем обратите внимание конкретно на давление на учетные данные. Неудачная попытка входа в WordPress — это запрос POST /wp-login.php , который возвращает 200 (форма рендерится заново); успешный вход возвращает 302 . Таким образом, самые активные исходные IP-адреса для POST-запросов с кодом 200 — это ваш брутфорс-трафик:
# Top IPs hammering the login form (failed attempts)
grep 'POST /wp-login.php' /var/log/nginx/access.log \
| awk '$9 == 200 {print $1}' \
| sort | uniq -c | sort -rn | head
На сайтах, за которыми я слежу, эти две команды регулярно фиксируют от сотен до тысяч обращений в день на сайте, который никто не атакует целенаправленно. Вот мысль, которую стоит усвоить: это не личное. WordPress работает примерно на 43% сайтов в Интернете (по данным W3Techs), что делает его крупнейшей поверхностью для автоматических атак в сети, а показатели Sophos/Hostinger оценивают количество взломываемых сайтов WordPress примерно в 13 000 в день. Боты сканируют сети по IP-адресам, а не по тому, стоит ли ваш контент кражи.
Этап первый: сделайте так, чтобы разведка ничего не возвращала
Этап разведки зависит от предсказуемости. Страница входа всегда находится по адресу /wp-login.php , админка — по адресу /wp-admin/ , имена пользователей утекают через /?author=1 и REST API. Измените эти значения по умолчанию на уровне перезаписи правил, и сканирование вернет 404 до загрузки PHP, поэтому сайт перестанет подтверждать себя в качестве цели.
Сначала берем самые низковисящие фрукты (простые победы с низким риском). Отклоните перечисление авторов и закройте список пользователей через REST:
# .htaccess — reject /?author=N enumeration
RewriteEngine On
RewriteCond %{QUERY_STRING} (^|&)author=([0-9]+) [NC]
RewriteRule ^ - [F]
// mu-plugin: drop the REST users endpoints for anonymous requests
add_filter('rest_endpoints', function ($endpoints) {
unset($endpoints['/wp/v2/users']);
unset($endpoints['/wp/v2/users/(?P<id>[\d]+)']);
return $endpoints;
});
Изменение путей входа — это наиболее эффективный удар по разведке, а также шаг, который с наибольшей вероятностью заблокирует вас самих, если вы ошибетесь. Делать это исключительно вручную означает поддерживать правила перезаписи плюс исправлять каждую захардкоженную ссылку (письма аутентификации, кэшированные страницы, некоторые плагины), поэтому большинство людей используют для этого плагин защиты страницы входа, а не управляют правилами перезаписи самостоятельно. Какой бы путь вы ни выбрали, оставьте старую сессию открытой и убедитесь, что новый URL работает, прежде чем закрывать вкладку. Здесь и возникает поднадоевшее возражение «разве это не просто безопасность за счет неясности?», и честный ответ звучит так: нет, ошибка 404 на уровне перезаписи означает, что код входа никогда не выполняется. Вы не прячете дверь, вы удаляете ее с карты, которую читают боты.
Этап второй: ломаем эксплуатацию учетных данных
Выжившая разведка ведет прямо к учетным данным, потому что именно там происходят реальные взломы. В отчете Verizon 2025 Data Breach Investigations Report отмечается, что 88% атак на базовые веб-приложения связаны с украденными учетными данными, а злоупотребление ими привело к 22% всех утечек. В WordPress это тот самый брутфорс и трафик подбора учетных данных, который обнаружила ваша вторая команда для логов.
Ограничьте частоту запросов (rate-limiting) для входа на уровне сервера, чтобы поток никогда не доходил до PHP. В nginx:
# http { } block
limit_req_zone $binary_remote_addr zone=wplogin:10m rate=20r/m;
# server { } block
location = /wp-login.php {
limit_req zone=wplogin burst=5 nodelay;
include fastcgi_params;
fastcgi_pass unix:/run/php/php-fpm.sock;
}
Затем отправляйте злостных нарушителей в бан с помощью fail2ban, чтобы они перестали вообще расходовать ресурсы:
# /etc/fail2ban/filter.d/wordpress-auth.conf
[Definition]
failregex = ^<HOST> .* "POST /wp-login\.php.*" 200
# /etc/fail2ban/jail.d/wordpress.conf
[wordpress-auth]
enabled = true
port = http,https
filter = wordpress-auth
logpath = /var/log/nginx/access.log
maxretry = 5
findtime = 600
bantime = 3600
Ограничение частоты запросов и баны снижают уровень шума. Что действительно нейтрализует украденный пароль, так это второй фактор, поэтому переведите реальных пользователей на входы не только по паролю. Ключ доступа (passkey / FIDO2/WebAuthn) привязывает криптографическую задачу к вашему домену, поэтому учетные данные, украденные фишингом на похожем сайте, нельзя использовать против вашего. TOTP — надежная альтернатива там, где ключи доступа пока недоступны. Цель проста: сделать правильный пароль недостаточным сам по себе, потому что 88% атак в данных DBIR делают ставку на то, что его достаточно.
Этап третий: усложняем закрепление и обнаруживаем то, что проскользнуло
Если эксплуатация все же удалась, злоумышленник захочет остаться. Две строки конфигурации убирают самые простые пути для закрепления:
// wp-config.php
define('DISALLOW_FILE_EDIT', true); // no theme/plugin editor in the dashboard
define('DISALLOW_FILE_MODS', true); // no plugin/theme install or update from the dashboard
Параметр DISALLOW_FILE_MODS также блокирует обновления из панели управления, поэтому используйте его там, где вы развертываете код через git или CI, а не кликая кнопку обновления. На сайтах, где это слишком строго, оставьте только DISALLOW_FILE_EDIT .
Каталог загрузок — классическое место для сброса бэкдоров. В нем никогда не должен выполняться PHP:
location ~* /wp-content/uploads/.*\.php$ { deny all; }
# wp-content/uploads/.htaccess
<FilesMatch "\.php$">
Require all denied
</FilesMatch>
А cron-задача, которая помечает PHP там, где его быть не должно, превращает закрепление в проблему, которую вы заметите через часы, а не через недели:
# Alert on unexpected PHP under uploads
find wp-content/uploads -name '*.php' -type f -printf '%p\n'
Это тот самый рубеж, где профилактика передает эстафету сканированию, и об этом стоит говорить честно.
Честный предел: профилактика — это не сканер
Все сказанное выше сокращает то, до чего может дотянуться злоумышленник. Ничто из этого не дезинфицирует сайт, который уже скомпрометирован, и ничто не ловит вредоносное ПО, поступающее по каналу, который вы не защитили, например, через сеанс легитимного администратора с утекшими данными или обновление из цепочки поставок. Это работа сканера вредоносных программ. Профилактика сохраняет чистый сайт чистым; сканирование — это страховочная сетка для того, что проскользнуло. Запускайте то и другое, делая упор на профилактику, и не путайте одно с другим.
Есть причина делать упор на профилактику, выходящая за рамки философии. Когда в 2025 году компания Patchstack проверила защиту распространенных средств защиты (внутренних WAF, Cloudflare, Imunify360, ModSecurity) от реальных эксплойтов WordPress, эти инструменты заблокировали лишь 12% атак на известные уязвимости, и этот показатель вырос до 26% при более широком тестировании. Показатель Hostinger/Sophos оценивает долю эксплойтов WordPress, обходящих стандартные файрволы хостинга, в 87.8%. Если ваш план звучит как «хостинг с этим справляется», данные говорят, что хостинг отлавливает около четверти. Самая дешевая четверть, которую стоит вернуть, — это то, что вы отсекли на этапе разведки, до того как что-либо запустилось.
Минимальная база профилактики
Если на этой неделе вы больше ничего не сделаете, сделайте эти пять шагов по порядку, проверяя результат после каждого:
- Отклоните перечисление авторов и закройте эндпоинты пользователей REST.
- Настройте ограничение частоты запросов для
/wp-login.phpна уровне сервера. - Добавьте fail2ban для борьбы с повторными нарушителями при входе.
- Переведите учетные записи администраторов на второй фактор (ключ доступа, затем TOTP).
- Запретите выполнение PHP в каталоге
wp-content/uploads/и отключите файловый редактор. Удивительно, но каждый раз, когда я делаю это для только что очищенного сайта, оказывается, что в этом мало что есть хитрого. Это полдня настройки против трафика, который уже был в логах. Отраслевые компиляции оценивают среднюю стоимость восстановления после взлома WordPress примерно в $14 500 с учетом простоев и потери позиций в поисковой выдаче. Потратить полдня дешевле.
Как выглядит ваш счетчик POST /wp-login.php прямо сейчас, если вы запустите ту вторую команду? Любопытно узнать, как выглядит обычный день в стеках других людей и что вы ограничиваете по частоте, а что баните сразу.
Комментарии (0)
Пока нет комментариев — будьте первым.