
Как в mod_rewrite блокировать по Referer, User Agent, URL, строке запроса, IP и в их комбинациях
28.05.2021
В рамках борьбы с наплывом ботов на сайт (смотрите скриншот в шапке), пришлось освежить знания по mod_rewrite (смотрите «Полное руководство по mod_rewrite»). Ниже даны примеры правил mod_rewrite, которые позволяют выполнять определённые действия (например, блокировать) для пользователей, подпадающих под соответствие сразу большому количеству критериев — смотрите самый последний пример, чтобы понять, насколько mod_rewrite гибкий и мощный.
Смотрите также: Как бороться с ботами на сайте
Запрет доступа с пустым реферером (Referer)
Следующее правило запретит доступ всем запросом, в котором не установлен HTTP заголовок Referer (в логах Apache вместо строки Referer записывается "-"):
RewriteEngine on RewriteCond %{HTTP_REFERER} ^$ RewriteRule ^.* - [F,L]
Блокировка доступа по части пользовательского агента (User Agent)
При блокировке ботов по User Agent необязательно указывать полное имя — можно указать только часть строки User Agent для совпадения. Специальные символы и пробелы должны быть экранированы.
Например, следующее правило заблокирует доступ для всех пользователей, в чьей строке User Agent встречается «Android 10»:
RewriteEngine on RewriteCond %{HTTP_USER_AGENT} "Android\ 10" RewriteRule ^.* - [F,L]
Примеры заблокированных этим правилом User Agent:
- Mozilla/5.0 (Linux; Android 10; SM-G970F) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.66 Mobile Safari/537.36
- Mozilla/5.0 (Linux; Android 10; Redmi Note 7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.66 Mobile Safari/537.36
Как заблокировать доступ по точному совпадению User Agent
Если вам нужно заблокировать доступ к сайту определённым User Agent с точным совпадением имени, то используйте конструкцию с If (это не относится к mod_rewrite, но не стоит забывать о такой возможности):
<If "%{HTTP_USER_AGENT} == 'Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1)'"> Require all denied </If> <If "%{HTTP_USER_AGENT} == 'Mozilla/5.0 (Windows NT 10.0; WOW64; rv:45.0) Gecko/20100101 Firefox/45.0'"> Require all denied </If> <If "%{HTTP_USER_AGENT} == 'Mozilla/5.0 (Windows NT 6.1; rv:45.0) Gecko/20100101 Firefox/45.9.0'"> Require all denied </If>
If доступна начиная с Apache 2.4.
Запрет доступа к определённым страницам
Переменная %{REQUEST_URI} включает в себя всё, что идёт в запросе после имени хоста (но не включает то, что идёт после знака вопроса в URL), используя её можно фильтровать запросы по URL, строке запроса, именам файла или их частям. Например:
RewriteEngine on RewriteCond %{REQUEST_URI} "строка-запроса" RewriteRule ^.* - [F,L]
Не смотря на то, что в логах веб-сервера Apache некоторые символы, в том числе кириллица, отображается в URL кодировке, в данных правилах можно указывать кириллицу. Например, следующее правило заблокирует доступ к статье с URL https://site.ru/как-узнать-какой-файл-от/:
RewriteEngine on RewriteCond %{REQUEST_URI} "как-узнать-какой-файл-от" RewriteRule ^.* - [F,L]
При желании, можно указать сразу несколько URL (или их частей). Каждая строка для поиска должна быть помещена в круглые скобки, между собой строки в скобках должны быть разделены символом | (конвейер, труба), например:
RewriteEngine on RewriteCond %{REQUEST_URI} "(проигрыватель-windows)|(как-узнать-какой-файл-от)|(сколько-оперативной-памяти)|(как-в-windows-10-открывать)|(7-приложений-для)" RewriteRule ^.* - [F,L]
Поскольку %{REQUEST_URI} не включает то, что идёт после знака вопроса в URL, то для фильтрации по строке запроса, идущей после знака вопроса, используйте %{QUERY_STRING}.
Как фильтровать по строке запроса, идущей после знака вопроса
Переменная %{QUERY_STRING} содержит строку запроса, которая следует после символа ? (знак вопроса) текущего запроса к серверу.
Обратите внимание, что фильтруемое значение должно быть в URL кодировке. К примеру, следующее правило:
RewriteCond %{QUERY_STRING} "p=5373&%D0%B7%D0%B0%D0%B1%D0%BB%D0%BE%D0%BA%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D1%82%D1%8C" RewriteRule ^.* - [F,L]
Заблокирует доступ к странице https://suay.ru/?p=5373&заблокировать, но не запретит доступ к странице https://suay.ru/?p=5373.
Запрет доступа IP и диапазонам
С помощью mod_rewrite можно блокировать отдельные IP от доступа к сайту:
RewriteEngine on RewriteCond "%{REMOTE_ADDR}" "84.53.229.255" RewriteRule ^.* - [F,L]
Можно указать несколько IP адресов для блокировки:
RewriteEngine on RewriteCond "%{REMOTE_ADDR}" "84.53.229.255" [OR] RewriteCond "%{REMOTE_ADDR}" "123.45.67.89" [OR] RewriteCond "%{REMOTE_ADDR}" "122.33.44.55" RewriteRule ^.* - [F,L]
Также можно использовать и диапазоны, но нужно помнить, что в данном случае строки расцениваются как регулярные выражения, но тесть нотация CIDR (например, 94.25.168.0/21) не поддерживается.
Диапазоны должны быть указаны как регулярные выражения — это можно сделать с использованием наборов символов. Например, для блокировки следующих диапазонов
- 94.25.168.0/21 (диапазон 94.25.168.0 - 94.25.175.255)
- 83.220.236.0/22 (диапазон 83.220.236.0 - 83.220.239.255)
- 31.173.80.0/21 (диапазон 31.173.80.0 - 31.173.87.255)
- 213.87.160.0/22 (диапазон 213.87.160.0 - 213.87.163.255)
- 178.176.72.0/21 (диапазон 178.176.72.0 - 178.176.75.255)
будет работать правило:
RewriteEngine on RewriteCond "%{REMOTE_ADDR}" "(94\.25\.1[6-7]])|(83\.220\.23[6-9])|(31\.173\.8[0-7])|(213\.87\.16[0-3])|(178\.176\.7[2-5])" RewriteRule ^.* - [F,L]
Обратите внимание, что диапазон 94.25.168.0 — 94.25.175.255 нельзя записать как 94.25.1[68-75], это будет истолковано как строка «94.25.1», и набор символов, включающий в себя символ 6, диапазон 8-7 и символ 5. Из-за диапазона 8-7 данная запись вызовет ошибку на сервере.
Поэтому для записи 94.25.168.0 — 94.25.175.255 используется «94\.25\.1[6-7]». Да, эта запись не совсем точно передаёт исходный диапазон — для увеличения точности, можно усложнить регулярное выражение. Но в моём случае это временный hotfix, поэтому и так сойдёт.
Также обратите внимание, что последний октет 0-255 можно пропускать, поскольку для совпадения с регулярным выражением достаточно того, что совпадёт часть IP адреса.
Комбинирование правил контроля доступа
Задание: заблокировать пользователей, удовлетворяющих сразу ВСЕМ последующим критериями:
1. Пустой реферер
2. Пользовательский агент содержит строку «Android 10»
3. Доступ был сделан к странице, URL которой содержит любую из строк
- проигрыватель-windows
- как-узнать-какой-файл-от
- сколько-оперативной-памяти
- как-в-windows-10-открывать
- 7-приложений-для
4. Пользователь имеет IP адрес, принадлежащий любому из диапазонов:
- 94.25.168.0/21 (диапазон 94.25.168.0 - 94.25.175.255)
- 83.220.236.0/22 (диапазон 83.220.236.0 - 83.220.239.255)
- 31.173.80.0/21 (диапазон 31.173.80.0 - 31.173.87.255)
- 213.87.160.0/22 (диапазон 213.87.160.0 - 213.87.163.255)
- 178.176.72.0/21 (диапазон 178.176.72.0 - 178.176.75.255)
Следующий набор правил будет соответствовать указанной задаче:
RewriteEngine on RewriteCond "%{REMOTE_ADDR}" "(94.25.1[6-7]])|(83.220.23[6-9])|(31.173.8[0-7])|(213.87.16[0-3])|(178.176.7[2-5])" RewriteCond %{HTTP_REFERER} ^$ RewriteCond %{HTTP_USER_AGENT} "Android\ 10" RewriteCond %{REQUEST_URI} "(проигрыватель-windows)|(как-узнать-какой-файл-от)|(сколько-оперативной-памяти)|(как-в-windows-10-открывать)|(7-приложений-для)" RewriteRule ^.* - [F,L]
Обратите внимание, что правила, которые связаны логическим ИЛИ, должны быть собраны в одно большое правило. То есть ни с одним из правил нельзя использовать флаг [OR], иначе это сломает логику всего набора правил.
Смотрите также:
- Обработка строки параметров URI в mod_rewrite
- Блокировка доступа поисковым системам с помощью mod_rewrite
А ботов, кстати, я заборол.
Связанные статьи:
- Как бороться с ботами на сайте (100%)
- Как защититься от спама через формы обратной связи (74.2%)
- Как блокировать доступ к сайту с конкретного сайта-букса или любого другого сайта с негативным трафиком (66.7%)
- Истории двух троллей (когда неудачно попытался троллить) (58%)
- Как исключить из индексации страницы с определёнными параметрами в URL и другие техники контроля индексации сайта поисковыми системами (54.7%)
- Приглашение в новую Search Console beta (RANDOM - 0.3%)
RewriteEngine on
RewriteCond %{REQUEST_URI} "строка-запроса"
RewriteRule ^.* - [F,L]
не работает почему то способ, даже если перейти с поиска нужная страница не откроется.
Приветствую!
Я понимаю, в чём у вас дело. Вместо %{REQUEST_URI} вам нужно использовать %{QUERY_STRING} и строка, по которой идёт блокировка, должна быть в URL кодировке.
Переменная %{REQUEST_URI} содержит часть URL от начала запроса, до вопросительного знака. Например в запросе это выделенная часть: https://site.ru/заблокировать/. А в запросе https://suay.ru/?p=5373&заблокировать в %{REQUEST_URI} будет только «/».
В переменной %{QUERY_STRING} в запросе https://suay.ru/?p=5373&заблокировать будет выделенная часть. А в запросе https://site.ru/заблокировать/ в этой переменной будет пусто.
О тонкой разнице между двумя запросами request и query я писал здесь.
Добавил в статью блок, посвящённый %{REQUEST_URI}, раздел «Как фильтровать по строке запроса, идущей после знака вопроса».
Спасибо большое, помогли!!!
Алексей, прошу прощения, здесь скобка вторая нужна? Заранее спасибо
"((94.25.1[6-7]])|(83.220.23[6-9])|(31.173.8[0-7])|(213.87.16[0-3])|(178.176.7[2-5]))"
Приветствую! Всё выражение помещено в скобки, поэтому если в начале стоит открывающая скобка, то ей должна соответствовать закрывающая, то есть нужна. Но, на самом деле, помещение выражение в скобки в данном случае ничего не меняет, то есть его можно записать и так:
"(94.25.1[6-7]])|(83.220.23[6-9])|(31.173.8[0-7])|(213.87.16[0-3])|(178.176.7[2-5])"
Почему у меня в статье эти лишние скобки я уже не помню, возможно, тестировал отрицание всего выражения, может быть что-то ещё или банальная ошибка.
Спасибо, Алексей за ответ
Алексей, здравствуйте. Посмортите пожалуйста, правильно написал:
188.170.72.0 - 188.170.87.255
(188.170.0[7-8])
Ноль лишний, правильно так: (188.170.[7-8]). Кстати, в данном случае ещё можно записать так: (188.170.[78]), то есть без дефиса, поскольку диапазона как такового нет, то можно перечислить символы.
Чтоб я делал без Вас! Спасибо большое
Привет! А можно ли как-то блокировать определенные POST-запросы?
Пример: отправил бот POST-запрос c полем name=alex.
Тогда блокируем дальнейшую обработку.
Меня непонятный бот замучил, который шлёт один и тот же POST с разных IP.
Но поля заполнены одинаково.
Захотел заблокировать его.
Приветствую! mod_rewrite не может работать с данными, передаваемыми методом POST.
Если у вас сайт на WordPress, то в админке WordPress → Настройки → Обсуждение → Запрещённые ключевые слова комментариев можно заблокировать по любым словам.
В качестве альтернативы используйте обработку данных POST в скриптах вашего сайта (с помощью PHP) — это простой способ, либо с помощью модуля Apache mod_security — это очень сложный способ.
Возможно, у этого бота есть свои характерные признаки, например, User Agent. Чтобы попытаться их выявить, изучите логи Apache, нужные записи отфильтровывайте по строке «POST».