Задачки по фрилансу: Ограничение доступа пользователей к сайту на уровне Nginx

nginx limited acccess

Выпала одна интересная задачка по Nginx — нужно ограничить доступ к сайту для пользователей, чтобы они могли переходить только из поисковых систем. Переходы из мессенджеров, других сайтов и просто прямые заходы на сайт нужно было запретить, в свою очередь оставить для поисковых роботов возможность безпрепятственно индексировать сайт при любом раскладе (прямой заход, переход из других сайтов и т.д., т.е. работа без ограничений).

Сервер был на Ubuntu с Nginx в качестве веб-сервера, сайт работал на WordPress, в целом ничего нового. Реализация должна была быть на уровне веб-сервера, средствами nginx нужно было контролировать кто откуда пришел, пользователь это или поисковый бот и выдавать соответствующую директиву к последующим действиям — давать доступ к сайту или отправлять в заглушку.

Изменения вносились в nginx на уровне файла конфигурации сайта, вроде mysite.conf для одного целевого хоста.

Чтобы более корректно определять кто есть кто и откуда пришел, использовались параметры «$http_referer» и «$http_user_agent», регулярные выражения, стандартные списки агентов ботов, кастомная страничка ошибки, реврайт и для того, чтобы соблюдалось несколько условий — добавил маркеры в каждое из них, на выходе получилось условие длинной 12 строк кода (можно еще сократить немного).

Логика работы правил nginx была следующей:

  1. Если пользователь пришел на сайт напрямую или НЕ из поисковика — присваиваем ему маркер «a»
  2. Если это не поисковый бот, присваиваем маркер «b»
  3. Проверяем наличие маркеров, если оба присутствуют, значит это был юзер который перешел на прямую или с другого сайта к примеру, соответственно его мы отправляем в заглушку.

Теперь давайте рассмотрим правила в деталях.

Первое условие:

if ($http_referer ~* "^$|^((?!(google|yandex|bing|yahoo|mail|duckduckgo)\.[a-z]+).)*$") {
  set $marker a;
}

Что к чему? Тут все просто, мы просим nginx проверять каждого пользователя по рефереру откуда он пришел. По условию: «^$» выполняет проверку пустой реферер или нет — так определяются прямые заходы на сайт. Далее мы пытаемся определить с начала строки, что пользователь пришел НЕ из google, yandex и прочих поисковых систем (в регулярном выражении конструкция ?! значит нет) ну и их соответствующиее перечисление.

Смотрите так же   Переводим сайты WordPress на LEMP (Linux + Nginx + MySQL + php-fpm)

Перечислять я решил только домены, но не их окончания, окочания могут быть для разных сегментов интернета разные и по этому использовалось более универсальное решение вида «[a-z]+» которое подразумевает, что там будут маленькие буковки и их может быть мало или много (от 1 и до …много). Точка в конце говорит о том, что дальше может идти абсолютно все, что угодно. Чуть раньше есть еще одна точка — она экранируется символом «\» чтобы определялась корректно, как настоящая точка, а не все, что угодно.

Если это условие отрабатывает, значит мы назначаем переменной $marker значение «a» и идем дальше.

Второе условие:

Тут все куда проще и скромнее, нам нужно определить бот это или юзер по агенту, у ботов они стандартные, не меняются и по этому как пример для проверки были выбраны именно они (к тому же их меньше). Условие гласит о том, что если параметр «user-agent» не соответсвует маске для Google, Yandex и т.д. — значит это не бот.

if ($http_user_agent !~* "googlebot|yandex|yahoo|bing") {
set $marker "${marker}b";
}

Использование восклицательного знака в самом начале условия говорит о том, что проверяется несоответствие, звездочка — условие не строгое ну и далее соответственно идет перечисление доступных агентов поисковых роботов разных поисковых систем.

В случае, если это условие отрабатывает, то мы присваиваем второе значние нашей переменной $marker. Конструкция ${marker}b используется для того, чтобы данные из первой проверки не потерялись, то есть просто дополняем данными второго условия.

Ну и конечно же в конце всех этих валидаций, нам остается лишь проверить верность нашего условия простым сравнением:

if ($marker = ab) {
return 403;
}

Если значение переменной после всех выполненых манипуляций равняется значению «ab», значит все отработало корректно и мы определили пользователя, соответственно и факт того, что он перешел на сайт на прямую либо не из поисковой системы и требуется применить к нему специальные меры, отправить в заглушку сайта.

Смотрите так же   SlowHTTPTest manual (Install & Run)

Тут уже на усмотрение администратора, можно выставить код какой либо ошибки, к примеру 403 или же прописать редирект на кастомную страничку.

В моем случае полное решение выглядело следующим образом:

if ($http_referer ~* "^$|^((?!(google|yandex|bing|yahoo|mail|duckduckgo|website)\.[a-z]+).)*$") {
 set $bot a;
}

if ($http_user_agent !~* "googlebot|yandex|yahoo|bing") {
 set $bot "${bot}b";
}
if ($bot = ab) {
 rewrite ^/(.*)$ https://website.com/index.html permanent
}

Тут прописаны «website» — это сайт заказчика, чтобы юзеры могли перемещаться свободно внутри сайта.

Может быть интересно:

Добавьте комментарий