Перейти к содержимому
Сервер и .htaccess

Правила безопасности .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.

Вывод в терминале с сервера Apache: до правил PHP-файл в uploads выполняется, а содержимое папки выводится списком; после правил uploads/test.php, wp-config.php и папка uploads возвращают 403, а главная страница 200
Настоящие ответы Apache 2.4.58 и PHP 8.3.6 до и после добавления трёх правил выше, на созданных нами тестовых файлах. Полного WordPress на этом тестовом сервере не было.

Чего НЕ надо делать

Блокировать 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, оставьте три правила, которые важны, и выбросьте остальное.

FAQ

Вопросы

Как запретить выполнение PHP-файлов в папке uploads в WordPress?

Создайте файл .htaccess внутри wp-content/uploads с блоком FilesMatch, который ловит файлы .php, и директивой Require all denied. Папка uploads по умолчанию доступна для записи всем, поэтому запрет выполнения означает, что попавший туда вредоносный .php останется мёртвым файлом на диске, а не превратится в удалённое выполнение кода.

Нужно ли закрывать прямой доступ к wp-config.php?

Да, и это ничего не стоит. Добавьте блок Files для wp-config.php с Require all denied. Пока PHP работает, прямой запрос вернёт пустую страницу, но если PHP упадёт, будет неверно настроен при переносе или обработчик отключат, Apache отдаст файл как обычный текст и выложит наружу доступы к базе данных.

Почему сайт выдал ошибку 500 Internal Server Error сразу после правки .htaccess?

Почти всегда дело в смешанном синтаксисе Apache. Require all denied — это Apache 2.4, а Order Deny,Allow вместе с Deny from all — это 2.2, и сочетание обоих диалектов в одном файле ломает сайт в момент сохранения. Проверьте версию через apachectl -v или удалите последний добавленный блок и перезагрузите сервер.

Работает ли .htaccess на nginx?

Нет. .htaccess что-то значит только на Apache и на LiteSpeed, который тоже его читает. На nginx файл игнорируется полностью, поэтому он просто лежит, пока вы считаете себя защищённым. Сначала выполните curl -I для своего сайта и посмотрите заголовок Server:, а затем используйте блоки server или location.

Останавливает ли блокировка xmlrpc.php брутфорс-атаки на WordPress?

Нет. Подавляющее большинство брутфорса идёт обычными POST-запросами на wp-login.php, и блокировка xmlrpc.php тут ничего не даёт. Брутфорс побеждают ограничением частоты запросов, надёжными паролями и двухфакторной аутентификацией. Отключить XML-RPC всё же стоит, если вы не пользуетесь Jetpack, мобильным приложением и пингбэками, поскольку пингбэк можно использовать для DDoS-отражения.