Перейти до вмісту
Сервер та .htaccess

Правила безпеки .htaccess для WordPress, які справді допомагають

Більшість того, що продають як безпеку .htaccess для WordPress, — це вода. Правил, які реально змінюють вашу поверхню атаки, небагато — ось як відрізнити одні від інших

Опубліковано

Більшість того, що продають як «безпеку .htaccess для WordPress», — це вода. Правил, які реально змінюють вашу поверхню атаки, небагато: заблокувати виконання PHP усередині wp-content/uploads, заборонити прямий доступ до wp-config.php та вимкнути індексацію каталогів. Популярні поради — блокувати xmlrpc.php, «щоб зупинити брутфорс», приховувати версію WordPress, вставляти список із 200 рядків user-agent-ів «поганих ботів» — коливаються від сумнівних до чистого театру. Нижче — що є чим і чому.

Спершу з’ясуємо одну річ: .htaccess узагалі щось робить лише на Apache (і на LiteSpeed, який теж його читає). На nginx він повністю ігнорується — файл просто лежить собі, а ви вважаєте, що захищені. Якщо ваш хостинг працює на nginx, ніщо з цього не застосовується, і вам потрібні блоки server/location замість цього. Перевірте командою curl -I https://yoursite.com і подивіться на заголовок Server:, перш ніж витрачати годину на редагування файлу, який сервер ніколи не читає.

Правило, яке справді має значення: жодного PHP у /uploads

Ось те, що варто зробити. wp-content/uploads за задумом доступний для запису всім — кожне завантаження медіафайлу, кожен плагін, що зберігає файл, пишуть саме туди. Якщо зловмисник зможе покласти .php-файл у цей каталог (через вразливий обробник завантажень, поле зображення, яке не перевіряє MIME-тип, чи скомпрометований плагін), то різниця між дрібною прикрістю і повною компрометацією з віддаленим виконанням коду полягає лише в тому, чи виконає сервер цей файл на запит. Заборонивши виконання, ви перетворюєте завантажений payload на просто інертний файл, що лежить на диску.

Додайте це у 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 містить дані доступу до бази даних і auth-солі. Поки 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 нічого з цим не робить. Брутфорс перемагають обмеженням частоти запитів, надійними паролями та 2FA — а не вбиванням одного endpoint-а. Є законна причина вимкнути XML-RPC: його функцію pingback можна зловживати для DDoS-рефлексії, тож якщо ви не використовуєте Jetpack, мобільний застосунок чи pingback-и, закриття його зменшує поверхню атаки. Тільки не переконуйте себе, що це ваш захист від брутфорсу, бо це не так.

Приховувати версію WordPress / прибирати тег генератора. Видалення readme.html і тега <meta name="generator"> створює відчуття посилення захисту. Зловмисник визначить вашу версію за query-рядками підключених ресурсів, розміткою блокового редактора та десятком інших ознак за лічені секунди. Ви нічого не приховуєте — ви лише створюєте собі ілюзію діяльності.

Величезні чорні списки user-agent-ів і реферерів «поганих ботів». User-agent — це один-єдиний HTTP-заголовок, який легко підробити. Ці списки застарівають того ж дня, коли ви їх вставили, вони не блокують нічого компетентного, а Apache обчислює кожен regex на кожен запит — ви платите реальний податок на продуктивність за нульову безпеку. Пропустіть їх.

Блокувати wp-login.php за IP. Чудово працює, поки ваш провайдер не змінить адресу і ви не заблокуєте самі себе від власної адмінки. Життєздатно лише зі справді статичним IP.

Редиректи проти перебору авторів (?author=1). Правило перезапису для .htaccess, яке для цього вставляють, саме по собі неповне — REST-endpoint /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-відбиття.