Правила безопасности .htaccess для WordPress, которые реально работают
Почти всё, что продают под видом безопасности .htaccess для WordPress, — это вода. Правила, которые действительно уменьшают поверхность атаки, короткие — разберём, где что
Опубликовано
Почти всё, что продают под видом «безопасности .htaccess для WordPress», — это вода. Правила, которые действительно уменьшают поверхность атаки, короткие: запретить выполнение PHP внутри wp-content/uploads, закрыть прямой доступ к wp-config.php и отключить листинг каталогов. Популярные советы — блокировать xmlrpc.php «чтобы остановить брутфорс», прятать версию WordPress, вставлять список из 200 строк с юзер-агентами вредных ботов — варьируются от малополезных до чистого спектакля. Ниже разберём, где что и почему.
Сначала уточним одну вещь: .htaccess вообще что-то делает только на Apache (и на LiteSpeed, который тоже его читает). На nginx он полностью игнорируется — файл просто лежит, а вы думаете, что защищены. Если ваш хостинг работает на nginx, ничего из этого не применимо, и вам нужны блоки server/location. Проверьте через curl -I https://yoursite.com и посмотрите на заголовок Server:, прежде чем тратить час на редактирование файла, который сервер никогда не читает.
Правило, которое реально важно: никакого PHP в /uploads
Вот это стоит сделать. wp-content/uploads по умолчанию доступна для записи всем — каждая загрузка медиафайла, каждый плагин, сохраняющий файл, пишет туда. Если злоумышленник сумеет положить .php-файл в эту папку (через уязвимый обработчик загрузок, поле изображения, не проверяющее MIME-тип, или скомпрометированный плагин), то разница между мелкой неприятностью и полной компрометацией с удалённым выполнением кода — в том, будет ли сервер выполнять этот файл при запросе. Запретите выполнение — и загруженная нагрузка останется просто мёртвым файлом на диске.
Поместите это в wp-content/uploads/.htaccess (создайте файл, если его нет):
<FilesMatch "\.php$">
Require all denied
</FilesMatch>
Это синтаксис Apache 2.4. На более старой версии 2.2 эквивалент — Order Deny,Allow / Deny from all. Смешивание двух диалектов в одном файле — самая частая причина внезапной ошибки 500 Internal Server Error после «усиления безопасности»: если весь сайт падает в момент сохранения, почти всегда причина именно в этом. Проверьте свою версию командой apachectl -v.
Защитите wp-config.php
wp-config.php хранит учётные данные базы данных и ключи и соли безопасности WordPress. Пока PHP работает, прямой запрос к этому файлу возвращает пустую страницу — PHP выполняет файл, а не выводит его. Риск — в сценарии сбоя: если PHP когда-нибудь упадёт, будет неправильно настроен во время миграции или обработчик окажется отключён, Apache отдаст файл как обычный текст и выложит пароль от вашей БД любому желающему. Запрет доступа — дешёвая страховка от неудачных пяти минут:
<Files wp-config.php>
Require all denied
</Files>
Отключите листинг каталогов
Если кто-то заходит в папку без index.php, а у Apache включён Options +Indexes, он выводит её содержимое — каждый резервный файл, каждый забытый SQL-дамп. Отключите это для всего сайта:
Options -Indexes
Низкая критичность, но реальная, и это ничего не стоит.
Вот честный базовый список. Собрать эти правила — вместе с правильным синтаксисом для 2.4 или 2.2, чтобы не уронить сайт в 500, — можно с помощью генератора .htaccess для WordPress, а не копируя из форумного поста, написанного под неправильную версию Apache.
Чего НЕ надо делать
Блокировать xmlrpc.php «для защиты от брутфорса». Вот главный миф, который все повторяют, и в такой формулировке он неверен. Да, метод system.multicall из XML-RPC исторически позволял злоумышленнику упаковать множество попыток входа в один запрос — реальное усиление. Но подавляюще распространённый вектор брутфорса — это обычные POST-запросы к wp-login.php, и блокировка xmlrpc.php не даёт ничего против этого. Брутфорс побеждается ограничением частоты запросов, сильными паролями и двухфакторной аутентификацией, а не уничтожением одной точки входа. Есть законная причина отключить XML-RPC: его функцию pingback можно использовать для DDoS-отражения, так что если вы не пользуетесь Jetpack, мобильным приложением или пингбэками, закрытие XML-RPC уменьшает поверхность атаки. Просто не убеждайте себя, что это ваша защита от брутфорса, — потому что это не так.
Прятать версию WordPress / убирать тег generator. Удаление readme.html и тега <meta name="generator"> ощущается как усиление защиты. Злоумышленник за секунды определит вашу версию по строкам запроса в подключённых ресурсах, разметке блочного редактора и десятку других признаков. Вы ничего не прячете — вы просто создаёте себе иллюзию занятости.
Огромные чёрные списки вредных ботов по юзер-агентам и рефереру. Юзер-агент — это один подделываемый HTTP-заголовок. Такие списки устаревают в тот же день, когда вы их вставили, они не блокируют никого компетентного, а Apache вычисляет каждое регулярное выражение при каждом запросе — вы платите реальный налог на производительность за нулевую безопасность. Пропустите их.
Привязка wp-login.php к IP. Отлично работает, пока провайдер не сменит вам адрес и вы не заблокируете сами себе доступ к своей же админке. Реально только с по-настоящему статическим IP.
Редиректы против перечисления авторов (?author=1). Правило rewrite для .htaccess, которое люди вставляют для этого, само по себе неполно — REST-эндпоинт /wp-json/wp/v2/users всё равно выдаёт список имён пользователей. Блокировать один путь, оставляя открытым другой, — спектакль.
Всё ещё не получается?
Если правило роняет сайт в 500 — это синтаксис: уберите последний добавленный блок и перезагрузите, это сразу локализует проблему. Если правило будто ничего не делает — убедитесь, что вы действительно на Apache и что для каталога включён AllowOverride (многие управляемые хостинги его ограничивают). Соберите файл из заведомо рабочего шаблона с помощью генератора .htaccess, оставьте три правила, которые важны, и выбросьте остальное.