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], иначе это сломает логику всего набора правил.

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

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


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


11 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
  2. Алексей

    Алексей, прошу прощения, здесь скобка вторая нужна? Заранее спасибо

    "((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]))"

     
    Reply
    1. MiAl

      Приветствую! Всё выражение помещено в скобки, поэтому если в начале стоит открывающая скобка, то ей должна соответствовать закрывающая, то есть нужна. Но, на самом деле, помещение выражение в скобки в данном случае ничего не меняет, то есть его можно записать и так:

      "(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])"

      Почему у меня в статье эти лишние скобки я уже не помню, возможно, тестировал отрицание всего выражения, может быть что-то ещё или банальная ошибка.

       
      Reply
  3. Алексей

    Алексей, здравствуйте. Посмортите пожалуйста, правильно написал:

    188.170.72.0 - 188.170.87.255

    (188.170.0[7-8])

     
    Reply
    1. MiAl

      Ноль лишний, правильно так: (188.170.[7-8]). Кстати, в данном случае ещё можно записать так: (188.170.[78]), то есть без дефиса, поскольку диапазона как такового нет, то можно перечислить символы.

       
      Reply
  4. dedlive

    Привет! А можно ли как-то блокировать определенные POST-запросы?
    Пример: отправил бот POST-запрос c полем name=alex.
    Тогда блокируем дальнейшую обработку.
    Меня непонятный бот замучил, который шлёт один и тот же POST с разных IP.
    Но поля заполнены одинаково.
    Захотел заблокировать его.

     
    Reply
    1. MiAl

      Приветствую! mod_rewrite не может работать с данными, передаваемыми методом POST.

      Если у вас сайт на WordPress, то в админке WordPress → Настройки → Обсуждение → Запрещённые ключевые слова комментариев можно заблокировать по любым словам.

      В качестве альтернативы используйте обработку данных POST в скриптах вашего сайта (с помощью PHP) — это простой способ, либо с помощью модуля Apache mod_security — это очень сложный способ.

      Возможно, у этого бота есть свои характерные признаки, например, User Agent. Чтобы попытаться их выявить, изучите логи Apache, нужные записи отфильтровывайте по строке «POST».

       
      Reply

Leave Your Observation

Ваш адрес email не будет опубликован.

wp-puzzle.com logo