Loading...
X

Как в mod_rewrite блокировать по Referer, User Agent, URL, строке запроса, IP и в их комбинациях

В рамках борьбы с наплывом ботов на сайт (смотрите скриншот в шапке), пришлось освежить знания по 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], иначе это сломает логику всего набора правил.

Смотрите также:

А ботов, кстати, я заборол.

Рекомендуется вам:


2 observations on “Как в mod_rewrite блокировать по Referer, User Agent, URL, строке запроса, IP и в их комбинациях
  1. Владимир

    RewriteEngine   on

    RewriteCond %{REQUEST_URI}  "строка-запроса"

    RewriteRule ^.* -   [F,L]

    не работает почему то способ, даже если перейти с поиска нужная страница не откроется.

     
    Reply
    1. MiAl

      Приветствую!

      Я понимаю, в чём у вас дело. Вместо %{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}, раздел «Как фильтровать по строке запроса, идущей после знака вопроса».

       
      Reply

Leave Your Observation

Ваш адрес email не будет опубликован. Обязательные поля помечены *

wp-puzzle.com logo