Всё началось с письма. Ну прямо как у Гарри Поттера.
С той разницей, что письма были электронные и приносила их не сова. В феврале 2015 года плагин защиты сообщил: мой сайт пытаются взломать перебором паролей, бот раз за разом пробует войти под логином admin. Я, как дядя Вернон, письмо удалил. Через пару часов пришло второе, за неделю — целая пачка.
Тогда я закрыл всё, до чего дотянулся, и написал этот пост. В 2026 году я перепроверил каждый совет на свежем WordPress 7.1. Половина рецептов устарела. А главная дыра никуда не делась: WordPress до сих пор сам подсказывает ботам ваш логин, причём в четырёх местах.
Как вообще ломают вход
Бот открывает страницу входа /wp-login.php и пробует пары «логин + пароль» из своего списка: admin и 123456, admin и qwerty, и так тысячами. Это и есть брутфорс — перебор «грубой силой».
Чтобы войти, боту нужно угадать обе половинки. Если логин он уже знает, работы вдвое меньше: остаётся подобрать только пароль. Поэтому первый шаг — не пароль, а логин.
Шаг 1: WordPress выдаёт ваш логин — спрячьте его
Я поставил чистый WordPress 7.1.3, завёл администратора с логином superadmin и поискал, где этот логин виден постороннему. Нашлось четыре места:
- Список авторов. Адрес
ваш-сайт.ru/wp-json/wp/v2/usersоткрывается без входа и показывает полеslug— ярлык пользователя. По умолчанию ярлык совпадает с логином:"slug": "superadmin". - Архив автора.
ваш-сайт.ru/?author=1перенаправляет на/author/superadmin/. Боты просто перебирают номера 1, 2, 3… - Сообщение об ошибке входа. На неверный пароль WordPress отвечает: «Введённый вами пароль пользователя superadmin неверен». А на несуществующий логин — «Имя пользователя nosuchuser не зарегистрировано». То есть сам подтверждает, угадан логин или нет.
- Восстановление пароля. Форма «Забыли пароль?» на чужой логин отвечает «Учётной записи с данным именем не существует», а на настоящий — по-другому. Об этом я писал ещё в обновлении 2015 года: боты научились подбирать логин через эту форму.
Проверьте свой сайт прямо сейчас: откройте ваш-сайт.ru/wp-json/wp/v2/users. Если в slug стоит ваш логин — его знает каждый.
Как спрятать. Ярлык можно сделать любым, логин от этого не меняется. В админке такого поля нет, зато есть команда WP-CLI (это программа для управления WordPress из командной строки):
wp user update 1 --user_nicename=doktor-lexium --display_name="Доктор Лексиум"
Здесь 1 — номер пользователя (виден в адресе, когда открываете его профиль), doktor-lexium — новый ярлык. После команды и список авторов, и архив показывают doktor-lexium, а логин нигде не светится. На lexium ярлык тоже давно не совпадает с логином — проверил, прежде чем писать этот раздел.
Заодно проверьте «Отображаемое имя» в профиле (Пользователи → Профиль → «Отображать как»). Оно показывается под каждой записью и тоже не должно совпадать с логином:
Сообщения об ошибке сделаем одинаковыми для любого логина. Создайте файл wp-content/mu-plugins/login-errors.php (папки mu-plugins может не быть — создайте; плагины из неё работают всегда, их не нужно включать):
<?php
// Одинаковый ответ на неверный логин и неверный пароль
add_filter( 'login_errors', function () {
return '<strong>Ошибка:</strong> неверное имя пользователя или пароль.';
} );
Проверил: и на верный логин с неверным паролем, и на выдуманный логин, и в форме восстановления пароля теперь один и тот же ответ. Бот больше не узнает, угадал ли он логин.
Шаг 2: пароль, который не угадать
Логин admin бот пробует первым, поэтому, если он у вас есть, создайте нового администратора с другим логином, войдите под ним и удалите старого (WordPress предложит передать записи новому пользователю — соглашайтесь).
Пароль — длинный и случайный, 16 символов и больше. Запоминать его не нужно: храните в менеджере паролей. Такой пароль перебором не подобрать, сколько бы попыток ни было.
Шаг 3: ограничьте число попыток
Даже длинный пароль лучше не давать перебирать бесконечно. Плагин ограничения попыток после нескольких ошибок закрывает вход на время. Я проверил Limit Login Attempts Reloaded — у него больше миллиона установок, и он обновлялся в сентябре 2026 года. С настройками по умолчанию после трёх неверных паролей четвёртая попытка получает «Too many failed login attempts. Please try again in 20 minutes». Пока блокировка действует, не пускает даже с верным паролем — то, что нужно.
Сам я пользуюсь WP Cerber, он делает то же самое и многое другое. Но учтите: в каталоге плагинов WordPress его нет с 2022 года, ставится он с сайта разработчика.
Плагины из моего рецепта 2015 года сегодня ставить не стоит: Login Security Solution не обновлялся с 2017 года, а SI CAPTCHA Anti-Spam из каталога пропал совсем.
Шаг 4: закройте xmlrpc.php
Кроме формы входа у WordPress есть второй вход — файл xmlrpc.php. Через него когда-то работали мобильные приложения и программы для публикации. Боты его любят, потому что он принимает логин и пароль без всякой формы.
Хорошая новость: самый опасный трюк — сотни паролей в одном запросе через system.multicall — в современном WordPress не работает. Я проверил: после первого неверного пароля остальные попытки в том же запросе отклоняются, даже верная. Но по одной попытке на запрос перебирать по-прежнему можно.
Если вы не публикуете записи из сторонних программ, закройте файл целиком. В .htaccess в корне сайта, над строкой # BEGIN WordPress:
<Files xmlrpc.php>
Require all denied
</Files>
После этого xmlrpc.php отвечает 403 — доступ запрещён. Если программе нужен доступ к сайту, лучше дать ей пароль приложения (Пользователи → Профиль → «Пароли приложений»): он работает через REST API, отдельно от вашего основного пароля, и его можно отозвать в любой момент.
Шаг 5: пустите к форме входа только себя
Самая надёжная мера: бот вообще не видит форму входа.
Если IP постоянный (домашний интернет со статическим адресом, свой сервер) — разрешите вход только с него. В .htaccess в корне сайта:
<Files wp-login.php>
Require ip 203.0.113.10
</Files>
Вместо 203.0.113.10 — ваш адрес. Несколько адресов пишутся через пробел. Проверил: с чужого IP форма входа отвечает 403, а при попытке открыть /wp-admin/ WordPress отправляет на ту же закрытую форму. Сайт при этом работает как обычно.
Если IP меняется (мобильный интернет, ноутбук в поездках), поставьте на форму входа второй пароль — его спросит браузер ещё до WordPress. Сначала создайте файл с паролем, лучше в папке выше сайта, чтобы его нельзя было скачать:
htpasswd -nbB gate "второй-пароль" > /путь/выше/сайта/.htpasswd-wp
gate — имя для входа, -B — надёжное шифрование пароля. Потом в .htaccess:
<Files wp-login.php>
AuthType Basic
AuthName "Вход только для своих"
AuthUserFile /путь/выше/сайта/.htpasswd-wp
Require valid-user
</Files>
Без пароля и с неверным паролем сервер отвечает 401, с верным пускает к обычной форме входа. Полный путь к папке сайта подскажет панель хостинга или команда pwd по SSH.
Грабли №1: старый синтаксис .htaccess
В 2015 году я писал правила так:
order deny,allow
deny from all
allow from 213.180.193.11
Это синтаксис старого Apache 2.2. В Apache 2.4 он работает, только пока на сервере включён модуль совместимости mod_access_compat. Отключат модуль при обновлении — и защита превратится в ошибку сервера. Новый вариант короче и понятнее: Require ip 213.180.193.11 или Require all denied. Все правила в этом посте написаны уже так.
Грабли №2: закрыли всю папку wp-admin
Тогда же я закрывал по IP всю папку wp-admin. Но в ней лежит admin-ajax.php, через который многие темы и плагины работают для обычных посетителей: формы, подгрузка записей, корзины. Закроете папку — у посетителей тихо сломаются кнопки. На тестовом сайте admin-ajax.php сразу стал отвечать 403.
Если хотите закрыть папку целиком, оставьте этот файл открытым. Файл .htaccess внутри папки wp-admin:
Require ip 203.0.113.10
<Files admin-ajax.php>
Require all granted
</Files>
Проверил: админка с чужого IP закрыта, а admin-ajax.php отвечает самому WordPress, как и должен. Но чаще всего хватает закрытого wp-login.php из шага 5: без входа в админку и так не попасть.
Грабли №3: проверял защиту со своего же адреса
Это случилось уже при подготовке обновления. Открываю форму входа на lexium — она открывается, хотя должна пускать только мои адреса. А сервис «узнать свой IP» показывает адрес, которого в списке нет. Паника: защита не работает!
Оказалось, работает. Мой интернет до lexium ходит через другой маршрут, и сайт видит меня с адреса, который в списке как раз есть. Запрос к той же форме с самого сервера хостинга — с чужого адреса — получил честный 403.
Урок: проверяйте закрытый вход с адреса, которого точно нет в списке. Например, с телефона через мобильный интернет, выключив Wi-Fi.
Грабли №4: пароль на xmlrpc.php для приложения
В 2015 году я ставил на xmlrpc.php второй пароль, чтобы им могло пользоваться мобильное приложение WordPress, а боты — нет. В 2017 году приложение перестало поддерживать такой пароль, и рецепт умер. Сегодня для программ есть пароли приложений из шага 4, а xmlrpc.php проще закрыть совсем.
Что ещё можно сделать
Двухфакторный вход. После пароля WordPress спрашивает ещё код из приложения на телефоне. Даже если пароль утёк, без телефона не войти. Для этого есть плагин Two Factor в каталоге WordPress. В этот раз я его не проверял, но это следующий шаг, если на сайте несколько авторов или пароль где-то мог засветиться.
Проверка от хостинга. На Beget форму входа lexium вдобавок прикрывает проверка от ботов: без JavaScript вместо формы приходит пустая страница, которая ставит cookie и перезагружается. Простые боты на этом спотыкаются.
Итог
В 2015 году я закрывал вход от ботов вслепую: каптча, переименования, пароль на xmlrpc.php для приложения. Каждый раз через пару часов приходило новое письмо. Сейчас понятно, с чего начинать: сначала WordPress перестаёт подсказывать логин, потом длинный пароль и ограничение попыток, а для спокойствия — вход только для своих.
Главный урок шире WordPress: проверяйте защиту глазами чужого человека. С собственного адреса, с сохранённым паролем, после входа в админку всё выглядит закрытым — даже когда открыто, и наоборот.
Если после правок .htaccess сайт перестал открываться — уберите новые строки через файловый менеджер хостинга, сайт сразу оживёт. А вопросы пишите в комментарии, разберёмся.