Вопрос или проблема
У меня проблема с фильтрацией запросов на основе таких параметров, как IP, Referer и/или User-Agent.
Что я хотел бы достичь, так это разрешить доступ к определенному URL на основе заголовка IP или Referer.
Что я пробовал, это в моем default.conf
на основе этого https://gist.github.com/bdmorin/e2a8574192718f03b58f и некоторых других темах здесь о вложенных if я создал следующее:
geo $allowedipaddr {
default 1;
10.10.17.10 0;
}
server {
(...)
location @proxy {
proxy_pass http://internalserver/
(...)
}
location ~* ^/rest(/([^/]+))?/V1/ {
valid_referers server_name domain.com/check;
set $referer "";
set $allowip "";
if ($invalid_referer) {
set $referer "N";
}
if ($allowedipaddr) {
set $allowip "N";
}
set $test "${allowip}${referer}";
if ($test = NN) {
return 403;
}
try_files "" @proxy;
}
После тестов это работает только тогда, когда заголовок referer присутствовал в запросе, оно не разрешало доступ иным способом, даже когда IP был в списке разрешенных. Когда referer был действительным, а IP нет – запрос не проходил. Когда referer был недействительным или отсутствующим, а IP был в порядке – запрос не проходил.
Я думал, что все if внутри location проверяются, но, как я правильно понимаю из других тем и документации, nginx находит первое ‘совпадение’ и прекращает проверять остальное.
Таким образом, я изменил подход и создал (как оказалось позже) то же самое решение, но другим способом:
location ~* ^/rest(/([^/]+))?/V1/(categories|guest-carts|integration|inventory|orders|products|products-render-info|stockItems|store|taxRates|taxRules)(/|$) {
if ($allowedipaddr){
return 403;
}
try_files "" @proxy;
}
location ~* ^/rest(/([^/]+))?/V1/ {
valid_referers server_name domain.com/check;
if ($invalid_referer) {
return 403;
}
try_files "" @proxy;
}
Я хотел создать большую область, где разрешены только запросы с referer, и меньшую область этой большой области, где разрешены IP-адреса. Но, как и ранее, nginx находит первое ‘совпадение’ и не проверяет остальное.
Я думал разместить location внутри location, но думаю, что это будет работать так же, но в меньше линий кода.
Так как я могу разрешить доступ к определенному URL, если заголовок Referer или IP допустимы?
Ответ или решение
Чтобы фильтровать запросы в NGINX на основе IP-адреса, Referer или User-Agent, необходимо учитывать особенности работы директив и порядок их применения. Ваша задача заключается в том, чтобы предоставить доступ к определённому URL, если Referer или IP-адрес являются допустимыми. Рассмотрим, как это можно реализовать с учётом предоставленных данных.
Определение IP-адресов
Для фильтрации по IP-адресам вы уже используете блок geo
, который правильно определяет IP-адреса, которым разрешён доступ. Но необходимым дополнением является корректное использование этой информации далее в конфигурации.
geo $allowedipaddr {
default 1;
10.10.17.10 0;
}
Написание конфигурации сервера
Существуют два основных подхода, с помощью которых можно управлять доступом на уровне location.
Конфигурация на уровне location
server {
location ~* ^/rest(/([^/]+))?/V1/ {
# Проверяем валидность Referer
valid_referers none blocked server_name domain.com/check;
set $access_granted 0; # Изначально доступ заблокирован
if ($allowedipaddr = 0) {
set $access_granted 1;
}
if ($http_referer ~* "(domain.com/check|server_name)") {
set $access_granted 1;
}
if ($access_granted = 0) {
return 403; # Отказ в доступе
}
# Осуществляем проксирование запроса
proxy_pass http://internalserver/;
}
}
Конфигурация через map (более гибкий способ)
Использование директивы map
предлагает более гибкий способ определения доступа.
map $http_referer $is_valid_referer {
"~^(https?://)?(www\.)?domain\.com/check$" 1;
default 0;
}
map $allowedipaddr $is_valid_ip {
0 1;
default 0;
}
server {
location ~* ^/rest(/([^/]+))?/V1/ {
set $access_granted 0; # Изначально доступ заблокирован
if ($is_valid_ip = 1) {
set $access_granted 1;
}
if ($is_valid_referer = 1) {
set $access_granted 1;
}
if ($access_granted = 0) {
return 403; # Отказ в доступе
}
proxy_pass http://internalserver/;
}
}
Объяснение
-
geo
иmap
Директивы: С помощью этих директив мы определяем переменные, которые используются в условных конструкциях для фильтрации IP и Referer.geo
помогает определить наличие IP в дозволенном списке, тогда какmap
может фильтровать значения заголовков более гибко. -
valid_referers
: Эта директива используется для проверки Referrer. Она определяет, какие значения заголовка Referer считаются допустимыми.
Заключение
Правильная реализация условных конструкций (if
), а также использование переменных позволяют управлять доступом более точно. Неправильный порядок выполнения или неверное использование могут приводить к тому, что NGINX пропускает проверки. Убедитесь, что установлены ожидаемые и корректные значения переменных, чтобы избежать нежелательной блокировки или разрешения.