Как в 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%)
- Как защититься от спама через формы обратной связи (73.8%)
- Как блокировать доступ к сайту с конкретного сайта-букса или любого другого сайта с негативным трафиком (66.3%)
- Истории двух троллей (когда неудачно попытался троллить) (58.1%)
- Как исключить из индексации страницы с определёнными параметрами в URL и другие техники контроля индексации сайта поисковыми системами (54.2%)
- Лазерная коррекция зрения — 15 лет спустя (RANDOM - 50%)
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».
Здравствуйте хотел бы поблагодарить автора! замечательная статья без лишней "воды" все по сути.Но уменя возник вопрос:-)
Есть задача ограничить на сайт прямые заходы, но в тоже время сайт должен быть доступен для поисковых роботов сделал следующую конструкцию:
RewriteEngine on
RewriteCond %{HTTP_USER_AGENT} "(Googlebot)|(YandexBot)|(Mediapartners-Google)|(Google-Image)"
RewriteRule .* - [END]
RewriteCond %{HTTP:HTTPS} !=on [NC]
RewriteCond %{HTTP:X-Forwarded-Proto} ^http$
RewriteRule ^(.*)$ https://site.ru/$1 [R=301,L]
RewriteCond %{HTTP_REFERER} ^$
RewriteRule ^.* - [F,L]
Прямые заходы не возможны но и доступ для роботов почему то закрыт проверял через яндекс вебмастер выдает ошибку робот не может зайти, как исправить подскажите пожалуйста буду крайне вам признателен 🙂
Приветствую! Вот этого правила, если оно не поставлено в условие от других правил, достаточно, чтобы заблокировать роботов-обходчиков и многих пользователей:
Роботы обходчики приходят с пустым значением Referer.
В этой заметке я блокирую пользователей с пустым Referer, но только если одновременно они соответствуют и другим указанным правилам.
Алексей, Здравствуйте. Боты полезли из поисковиков. Есть ли возможность их блокировать? Или только по ip?
Заранее спасибо.
Приветствую! Существуют различные скрипты, которые блокируют ботов. Но мне такой подход не нравится, так как даже обычные пользователи вместо того, чтобы совершить простейшее действие, могут просто закрыть сайт — например, я сам так делаю.
То есть если пойдёте по такому пути, то нужно выбирать скрипт, который действует максимально прозрачно для пользователя, например, не требует от него ничего делать, кроме как подождать завершения проверки, либо показывает простую капчу только подозрительным пользователям, с высоким скорингом ботности. Вроде, у Cloudflare есть подобные функции. Что-то подробнее подсказать не могу, так как сам не пользуюсь.
Спасибо, Алексей. С Cloudflare проблемы с оплатой. Снять счетчики и бог с ними?
Алексей, Здравсвтуйте. Вот не спец и не могу сообразить. Если конечно это вообще возможно. Делаю блокировку по ip.
<IfModule mod_rewrite.c>
RewriteEngine on
RewriteCond %{REMOTE_ADDR} "213.87.139.96" [OR]
RewriteCond %{REMOTE_ADDR} "213.87.152.39"
RewriteRule ^.* - [F,L]
</IfModule>
Ошибка 403 и переход на мою страницу заглушку. Если человек нажмет на кнопку перейти на сайт то получается попадает снова на страницу заглушку. Если по прямому заходу и правилу:
<IfModule mod_rewrite.c>
RewriteEngine on
RewriteCond %{REMOTE_ADDR} "!18.24.43.18"
RewriteCond %{REMOTE_ADDR} "(2.56.138.[0-2])|(2.133.1[7-9])|(5.35.[01])"
RewriteCond %{HTTP_REFERER} ^$
RewriteCond %{HTTP_USER_AGENT} "Mobile"
# RewriteCond %{REQUEST_URI} "(tsvet-i-svet-v-interere)"
RewriteRule ^.* - [F,L]
</IfModule>
при попадании на страницу заглушку человек при нажатии на кнопку перейти на сайт спокойно переходит, бот нет, кнопка в скрипте. А возможно сделать так, что при блокировки по ip по первому правилу, человек смог перейти на сайт при нажатии на переход на сайт.
Спасибо Вам!!!
Как запретить в htaccess переход на сайт с определенной страницы рефера, а не всего домена?
RewriteCond %{HTTP_REFERER} https://site.ru/ [NC]
RewriteRule .* – [F]
здесь мой сервер отдает 403 на переход с любого урл домена site.ru , а мне нужно чтоб, например, с главной страницы site.ru нельзя было перейти, а с site.ru/category/post233 и других страниц этого домена - можно перейти Помогите с синтаксисом написания