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

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

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


Билеты на автобусы, паромы и поезда, в том числе стыковочные маршруты:

Авиабилеты на международные и местные направления по минимальным ценам:

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


Buy Me a Coffee

18 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
  5. Виталий

    Здравствуйте хотел бы поблагодарить автора! замечательная статья без лишней "воды" все по сути.Но уменя возник вопрос:-)

    Есть задача ограничить на сайт прямые заходы, но в тоже время сайт должен быть доступен для поисковых роботов сделал следующую конструкцию:

    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]

    Прямые заходы не возможны но и доступ для роботов почему то закрыт проверял через яндекс вебмастер выдает ошибку робот не может зайти, как исправить подскажите пожалуйста буду крайне вам признателен 🙂

     
    Reply
    1. MiAl

      Приветствую! Вот этого правила, если оно не поставлено в условие от других правил, достаточно, чтобы заблокировать роботов-обходчиков и многих пользователей:

      RewriteCond %{HTTP_REFERER} ^$
      RewriteRule ^.* - [F,L]

      Роботы обходчики приходят с пустым значением Referer.

      В этой заметке я блокирую пользователей с пустым Referer, но только если одновременно они соответствуют и другим указанным правилам.

       
      Reply
  6. Алексей

    Алексей, Здравствуйте. Боты полезли из поисковиков. Есть ли возможность их блокировать? Или только по ip?

    Заранее спасибо.

     
    Reply
    1. MiAl

      Приветствую! Существуют различные скрипты, которые блокируют ботов. Но мне такой подход не нравится, так как даже обычные пользователи вместо того, чтобы совершить простейшее действие, могут просто закрыть сайт — например, я сам так делаю.

      То есть если пойдёте по такому пути, то нужно выбирать скрипт, который действует максимально прозрачно для пользователя, например, не требует от него ничего делать, кроме как подождать завершения проверки, либо показывает простую капчу только подозрительным пользователям, с высоким скорингом ботности. Вроде, у Cloudflare есть подобные функции. Что-то подробнее подсказать не могу, так как сам не пользуюсь.

       
      Reply
  7. Алексей

    Алексей, Здравсвтуйте. Вот не спец и не могу сообразить. Если конечно это вообще возможно. Делаю блокировку по 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 по первому правилу, человек смог перейти на сайт при нажатии на переход на сайт.

    Спасибо Вам!!!

     
    Reply
  8. Николай

    Как запретить в htaccess переход на сайт с определенной страницы рефера, а не всего домена?

    RewriteCond %{HTTP_REFERER} https://site.ru/ [NC]

    RewriteRule .* – [F]

    здесь мой сервер отдает 403 на переход с любого урл домена site.ru , а мне нужно чтоб, например, с главной страницы site.ru нельзя было перейти, а с site.ru/category/post233 и других страниц этого домена - можно перейти Помогите с синтаксисом написания

     
    Reply

Leave an observation to MiAl Cancel observation

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

wp-puzzle.com logo