Безопасность сайта

Файл .htaccess против ботов и парсеров: рабочие правила

Готовый набор директив .htaccess для блокировки парсеров, скрейперов и сканеров. Что ловит, что ломает и как не отстрелить себе ноги.

обновлено 9 минут чтения 2 Дмитрий Акиндинов
Содержание
  1. Зачем вообще .htaccess против ботов
  2. Структура файла
  3. Защита служебных файлов
  4. Блокировка плохих User-Agent
  5. Блокировка плохих Referer
  6. Блокировка по IP и подсетям
  7. Геоблокировка через GeoIP
  8. Защита от хотлинка картинок
  9. Лимит на размер запроса
  10. Защита от SQL-инъекций в query string
  11. CMS-специфические правила
  12. Что делать с 500 Internal Server Error
  13. Логирование заблокированного
  14. Что не делать
  15. Чек-лист после установки
  16. Куда дальше
  17. Частые вопросы

.htaccess отбивает запрос до того, как он дойдёт до CMS, поэтому стоит дешевле любого плагина: ни PHP, ни базы, ни нагрузки. Им закрывают служебные файлы, блокируют назойливые юзер-агенты и подсети, режут хотлинк картинок и ограничивают размер запроса.

Файл .htaccess это первая линия обороны на shared-хостинге. До того как запрос попадёт в WordPress, Битрикс или OpenCart, его можно отбить парой строк в текстовом файле. Никакого PHP, никакой нагрузки на CPU, никаких плагинов, которые надо обновлять.

Я веду «золотой» .htaccess, который кладу на каждом новом клиентском проекте. За пять лет он отбил миллионы запросов от парсеров, скрейперов, ботов брутфорса и просто плохо написанных краулеров. Ниже разберу каждое правило: что оно делает, кого ловит, и где может сработать ложно.

Стена из правил .htaccess против ботов

Зачем вообще .htaccess против ботов

Стандартный shared на Apache умеет всё, что нужно для базовой защиты:

  • блокировать запросы по User-Agent;
  • блокировать запросы по Referer;
  • блокировать запросы по IP и подсетям;
  • блокировать запросы по содержимому query string;
  • ограничивать доступ к отдельным файлам и папкам;
  • настраивать редиректы и капчи;
  • логировать всё, что блокируется.

Главное преимущество: правила выполняются на уровне веб-сервера, до запуска PHP. Это значит, что заблокированный бот не нагружает CPU, не открывает соединение с базой, не получает шансов попасть в код CMS.

Главное ограничение: shared-хостинг разрешает не все директивы. Часть из того, что работает в полноценном Apache на VPS, на shared даст 500 Internal Server Error. Я отдельно отмечу такие места.

Структура файла

Я кладу .htaccess в корень сайта и держу его в порядке.

# 1. Базовые настройки
Options -Indexes
ServerSignature Off

# 2. Защита служебных файлов
<FilesMatch "(.git|.env|composer.json|composer.lock|wp-config.php|configuration.php|local.xml)$">
    Require all denied
</FilesMatch>

# 3. Блокировка плохих User-Agent
# (см. ниже)

# 4. Блокировка плохих Referer
# (см. ниже)

# 5. Блокировка по IP
# (см. ниже)

# 6. Защита от хотлинка
# (см. ниже)

# 7. CMS-специфические правила
# (для WordPress, Битрикса и пр.)

Дальше разберу каждый блок.

Защита служебных файлов

Первое, что я закрываю на любом сайте: всё, что может выдать чувствительную информацию.

<FilesMatch "(.git|.env|.svn|.bak|.old|.orig|composer.json|composer.lock|package.json|package-lock.json|wp-config.php|wp-config-sample.php|configuration.php|configuration.php.bak|local.xml|app.yaml|web.config|.htpasswd|.htaccess|readme.html|readme.txt|license.txt|debug.log|error_log|backup.zip|backup.tar.gz|backup.sql)$">
    Require all denied
</FilesMatch>

Это полная страховка от ситуации, когда вы случайно залили в репозиторий .env с паролями, или забыли удалить wp-config.php.bak после правки, или оставили backup.sql в корне после миграции. Боты регулярно сканируют такие имена.

Дополнительно закрываем доступ к Git и SVN-папкам:

RedirectMatch 404 /.git
RedirectMatch 404 /.svn

И к временным каталогам, которые иногда не должны быть публичными:

<DirectoryMatch ".*/(tmp|temp|backup|backups|cache|logs|priv|private)/.*">
    Require all denied
</DirectoryMatch>

DirectoryMatch на shared-хостинге работает не везде. Если получили 500, заменяйте на <FilesMatch> или просто кладите в каждую такую папку свой .htaccess с Require all denied.

Блокировка плохих User-Agent

Большинство автоматических парсеров не маскируется под нормальный браузер. Они ходят с явно ботовыми User-Agent, по которым их легко резать.

<IfModule mod_rewrite.c>
RewriteEngine On

RewriteCond %{HTTP_USER_AGENT} (ahrefs|semrush|mj12bot|dotbot|blexbot|seokicks|seznambot|baiduspider|petalbot) [NC,OR]
RewriteCond %{HTTP_USER_AGENT} (zoominfobot|sentibot|serpstatbot|sitebot|sogou|bytespider|amazonbot|gptbot|claudebot|youbot) [NC,OR]
RewriteCond %{HTTP_USER_AGENT} (libwww-perl|wget|curl|python-requests|java/|nikto|sqlmap|w3af|nessus|sf|httpclient) [NC,OR]
RewriteCond %{HTTP_USER_AGENT} (FAST-WebCrawler|larbin|mass download|nutch|teleport|siphon|webcopier|webreaper|webzip|wget.exe) [NC,OR]
RewriteCond %{HTTP_USER_AGENT} ^$ [OR]
RewriteCond %{HTTP_USER_AGENT} (^|s)(bot|spider|crawler|scraper)(s|$) [NC]
RewriteRule .* - [F,L]
</IfModule>

Что здесь:

  1. Первая группа SEO-парсеры: Ahrefs, Semrush, Majestic. Если вы не пользуетесь их сервисами, они вам и не нужны (а если пользуетесь, ходят они через свой вход и не парсят ваши страницы).
  2. Вторая группа AI-краулеры: GPTBot от OpenAI, ClaudeBot, YouBot, Amazonbot. Эти ходят чтобы скармливать ваш контент в обучающие данные. Решение блокировать или нет ваше; я обычно блокирую.
  3. Третья группа инструменты разработчиков и атакующих: curl, wget, python-requests, sqlmap, nikto. Если из вашей формы или из вашего кода никто не ходит на свой же сайт через curl, можно резать.
  4. Четвёртая группа старые парсеры и качалки целых сайтов: Teleport, WebCopier, WebReaper.
  5. Пятая строка пустой User-Agent. Нормальные браузеры всегда что-то отправляют.
  6. Шестая строка общие слова bot, spider, crawler, scraper в любом User-Agent. Это широкая, но эффективная сетка.

Что важно учесть:

  • Не блокируйте Googlebot, YandexBot, Bingbot. Они нужны для индексации. Они и так нормально себя ведут, ставьте User-agent: * правила в robots.txt вместо .htaccess.
  • Не блокируйте Slackbot, WhatsApp, TelegramBot. Они ходят за preview-картинкой при отправке ссылки. Если заблокируете, в Telegram ссылка на ваш сайт будет без картинки.
  • Не блокируйте PingdomBot, UptimeRobot, Yandex.Webmaster, если ими пользуетесь.

После выкатки правила обязательно проверьте логи: иногда случайно режется что-то нужное.

Блокировка плохих Referer

Многие парсеры приходят с конкретными referer от спамерских сайтов. Можно отбивать запросы оттуда:

<IfModule mod_rewrite.c>
RewriteCond %{HTTP_REFERER} (semalt|kambasoft|savetubevideo|buttons-for-website|share-buttons|free-share-buttons|7makemoneyonline) [NC,OR]
RewriteCond %{HTTP_REFERER} (best-seo-offer|forum69.info|guardlink|ranksonic|s.click.aliexpress|tracksvr) [NC]
RewriteRule .* - [F,L]
</IfModule>

Это спам-рефереры, которые в 2010-х накручивали статистику Google Analytics. Сейчас встречаются реже, но иногда всплывают.

Блокировка по IP и подсетям

Если в логах видно конкретный IP, который ломится по 500 раз в час, блокируем точечно:

<RequireAll>
    Require all granted
    Require not ip 1.2.3.4
    Require not ip 5.6.7.0/24
    Require not ip 10.20.30.0/16
</RequireAll>

Где брать список IP:

  • Свои логи awk '{print $1}' access.log | sort | uniq -c | sort -rn | head -50 показывает топ IP по числу запросов.
  • Готовые блок-листы: AbuseIPDB, Spamhaus, Blocklist.de.
  • Если хостинг это GeoIP-модуль, можно блокировать целые страны (см. ниже).

Я держу в начале .htaccess короткий список самых отвратительных IP последнего месяца. Раз в неделю ротирую.

Геоблокировка через GeoIP

Если хостинг поддерживает mod_geoip, можно резать целые страны:

<IfModule mod_geoip.c>
GeoIPEnable On
RewriteEngine On
RewriteCond %{ENV:GEOIP_COUNTRY_CODE} ^(CN|VN|PH|PK|IN|NG|KZ|UA)$
RewriteRule .* - [F,L]
</IfModule>

Внимание: это очень грубая мера. Если вы продаёте только в России, она резонна. Если хоть один клиент может зайти из Узбекистана или Казахстана, они получат 403 и не смогут заявку отправить.

Я применяю геоблокировку только на админку, на основной сайт никогда.

<Files "wp-login.php">
    <IfModule mod_geoip.c>
        Require env allow_country
        SetEnvIf GEOIP_COUNTRY_CODE ^RU$ allow_country=1
        SetEnvIf GEOIP_COUNTRY_CODE ^BY$ allow_country=1
    </IfModule>
</Files>
Стенки из бриков с правилами и улетающие боты

Защита от хотлинка картинок

Хотлинк это когда чужой сайт встраивает ваши изображения как <img src="https://saitfix.ru/uploads/photo.jpg">. Ваш хостинг отдаёт трафик, а пользы ноль.

<IfModule mod_rewrite.c>
RewriteEngine On
RewriteCond %{HTTP_REFERER} !^$
RewriteCond %{HTTP_REFERER} !^https?://(www.)?saitfix.ru [NC]
RewriteCond %{HTTP_REFERER} !^https?://(www.)?yandex. [NC]
RewriteCond %{HTTP_REFERER} !^https?://(www.)?google. [NC]
RewriteCond %{HTTP_REFERER} !^https?://(www.)?bing. [NC]
RewriteRule .(jpg|jpeg|png|gif|webp|avif|bmp|svg)$ - [F,NC,L]
</IfModule>

Логика: если запрос пришёл с непустого referer, и referer не наш домен и не поисковик, картинка не отдаётся. Пустой referer пропускаем (это прямой доступ или закрытый browser-режим).

Можно вместо запрета вернуть «защитную» картинку:

RewriteRule .(jpg|jpeg|png)$ /assets/no-hotlink.jpg [R,NC,L]

Где no-hotlink.jpg это маленькое изображение с надписью «эта картинка с saitfix.ru». На 99 процентов хотлинков это работает как реклама.

Лимит на размер запроса

Боты иногда атакуют большими POST-запросами, пытаясь нагрузить сайт.

LimitRequestBody 10485760

Это 10 МБ. Больше реальный человек редко загружает (исключение: загрузка фото в админку, тогда правило ставим только на публичные страницы).

Защита от SQL-инъекций в query string

Простые попытки SQL-инъекций можно резать на уровне .htaccess.

<IfModule mod_rewrite.c>
RewriteEngine On
RewriteCond %{QUERY_STRING} (UNION|SELECT|INSERT|DROP|UPDATE|DELETE|REPLACE|GRANT|LOAD_FILE|OUTFILE|INFORMATION_SCHEMA) [NC,OR]
RewriteCond %{QUERY_STRING} (<|%3C).*script.*(>|%3E) [NC,OR]
RewriteCond %{QUERY_STRING} (eval(|base64_decode|gzinflate|exec(|system() [NC]
RewriteRule .* - [F,L]
</IfModule>

Это отлавливает не все атаки (нормальный фреймворк давно использует prepared statements), но добавляет ещё один слой. Несрабатывания на нормальных URL: бывают на сайтах, где в query string есть слова типа select. На WordPress такого почти нет, на самописных сайтах надо тестировать.

CMS-специфические правила

WordPress

# Скрыть версии
<FilesMatch "readme.html|readme.txt|license.txt|wp-config.php.bak">
    Require all denied
</FilesMatch>

# Блокировать xmlrpc целиком
<Files "xmlrpc.php">
    Require all denied
</Files>

# Запретить выполнение PHP в uploads
<Directory "/wp-content/uploads/">
    php_flag engine off
    <FilesMatch ".(php|phtml|php5|php7|phar|pl|py|cgi)$">
        Require all denied
    </FilesMatch>
</Directory>

Последнее особенно важно: типичный сценарий взлома это закидывание PHP-шелла через дырку в плагине прямо в /wp-content/uploads/. Если в этой папке PHP не выполняется, шелл становится бесполезным куском текста.

Битрикс

# Запретить доступ к служебным
<FilesMatch "(.tools$|local.xml$|update_log.txt$|cron.log$|stop_redirect.log$)">
    Require all denied
</FilesMatch>

# Запретить выполнение PHP в /upload/
<Directory "/upload/">
    php_flag engine off
</Directory>

OpenCart

# Запретить config-файлы
<FilesMatch "(config.php$|admin/config.php$)">
    Require all denied
</FilesMatch>

# Запретить выполнение PHP в /image/cache/
<Directory "/image/cache/">
    php_flag engine off
</Directory>

Что делать с 500 Internal Server Error

Если после правки .htaccess сайт упал, не паникуем.

  1. Откатываем через FTP/SSH к предыдущей версии. Я всегда сохраняю .htaccess.bak перед изменениями.
  2. Проверяем в логах ошибок Apache (/var/log/apache2/error.log на VPS, у хостера обычно в панели), какая директива не сработала.
  3. Делим правила пополам и выкатываем по половинке, пока не найдём виновника.

Самые частые причины 500 на shared:

  • Options +FollowSymLinks запрещён у хостера.
  • <DirectoryMatch> не работает на уровне .htaccess.
  • RewriteOptions доступен только на сервере, не в .htaccess.
  • LimitRequestBody сильно ограничен у хостера.

При возникновении сомнений тестируйте на копии сайта, а не на боевом.

Сервер с табличкой правил и сторожевая сова

Логирование заблокированного

На VPS я пишу отдельный лог-файл для заблокированных запросов:

SetEnvIfNoCase User-Agent "(ahrefs|semrush|mj12bot)" blocked_ua=1
CustomLog /var/log/apache2/blocked.log combined env=blocked_ua

Раз в неделю смотрю файл, чтобы понимать, кто на меня ходил и кого мы режем. Иногда замечаю, что в правило попало что-то не то (например, новый легитимный краулер).

Что не делать

Несколько типичных ошибок, которые я регулярно вижу.

Не блокируйте всё подряд User-Agent. Если в сетку «bot» попадёт Googlebot, ваш сайт пропадёт из выдачи. Всегда тестируйте после правки.

Не блокируйте по странам без причины. Половина мобильного трафика в России идёт через CDN-провайдеров, у которых IP в самых разных странах.

Не пишите .htaccess на shared-хостинге без бэкапа. Один лишний символ это 500 на всём сайте.

Не используйте директивы уровня сервера в .htaccess. <VirtualHost>, <Location>, RewriteOptions InheritDown это для конфигурации Apache целиком, на shared они дают 500.

Не дублируйте правила. Если один и тот же бот блокируется и на уровне robots.txt, и в .htaccess, и в плагине безопасности, в логах путаница, отлаживать сложнее.

Чек-лист после установки

После того как раскатили новый .htaccess:

  1. Проверить главную страницу curl -sI https://saitfix.ru/ ожидаем 200.
  2. Проверить пару внутренних страниц.
  3. Проверить, что админка открывается.
  4. Проверить, что страница ошибки 404 не лежит.
  5. Проверить лог ошибок за час, что нет внезапного потока 500-х.
  6. Через сутки посмотреть, не упал ли трафик из Яндекса и Google в Метрике/Search Console.

Если всё ровно живём дальше. Если что-то отвалилось откатываемся, разбираемся, выкатываем по частям.

Куда дальше

Связанные материалы: Кэширование браузером через .htaccess, DDoS на маленький сайт без Cloudflare, Как ограничить число попыток входа в админку.

Если возиться с .htaccess вам не хочется, у меня готовый шаблон на основе пятилетнего опыта раскатывается как часть стандартного аудита безопасности на старте абонентского обслуживания. Заявка через форму на главной.

Частые вопросы

Как заблокировать бота через htaccess

Правилом по юзер-агенту или по IP. Юзер-агент подделывается легко, поэтому назойливых парсеров надёжнее блокировать по подсети, взяв адреса из лога доступа.

Каких ботов блокировать не надо

Поисковых и тех, кто приводит трафик: Яндекс, Google, Bing, а сегодня и краулеры языковых моделей. Заблокировав их, вы пропадаете из выдачи и из ответов ИИ.

Что закрыть в первую очередь

Служебные файлы: конфиги, дампы, резервные копии, файлы окружения, скрытые файлы. Их регулярно перебирают сканеры, и открытый дамп базы это готовая утечка паролей.

Как понять, кого блокировать

По логу доступа. Смотрите, какие адреса дают сотни запросов в час и по каким URL они ходят. Точечная блокировка одного IP работает лучше, чем широкие правила по маске.

Передайте техническую часть в надёжные руки.

Слежу за хостингом, бэкапами и обновлениями. Когда что-то пойдёт не так – звоните мне, не своему программисту, не в спортзал и не маме.

Короткие вопросы по теме

Все вопросы по теме "Безопасность сайта"

Заявка

Обсудим задачу

Напишите имя и телефон, выберите удобный канал. Перезвоню или напишу в течение часа в рабочее время.

Куда удобнее ответить?