secure_link + realip + if

Pavel pavel2000 на ngs.ru
Пн Авг 20 18:25:36 UTC 2018


Здравствуйте.

Спасибо за Nginx!

В процессе использования появился вопрос по совместному 
использованию
модулей ngx_http_secure_link_module и 
ngx_http_realip_module, с использованием
проверки доступа через if (Да, "if is evil", но есть ли 
другой способ?).

Ранее модуль ngx_http_secure_link_module использовался для 
проверки
доступа в самостоятельной конфигурации, без realip_module.
Теперь сервис переезжает за дополнительный прокси в целях 
защиты от DDOS,
и для получения реального айпи браузера добавился 
ngx_http_realip_module.

Проблема в следущем: если в одном локейшне используются 
два вышеуказанных
модуля + директива if, то переопределение remote_addr не 
происходит.
Если if не использовать - переопределение работает.


Тестовая конфигурация:

user www-data;
worker_processes  1;

error_log  /var/log/nginx/tst.error.log notice;
pid        /var/run/nginx.tst.pid;

events {
     worker_connections  1024;
     # multi_accept on;
}

http {
     include  /etc/nginx/mime.types;
     access_log /var/log/nginx/tst.access.log;


server {
     listen 127.0.0.1:80;
     server_name vhost;

     root /tmp;

     location / {
         set_real_ip_from 127.0.0.1/32;
         real_ip_header X-Forwarded-For;

         secure_link $arg_st;
         secure_link_md5 "${remote_addr}_$uri";
         if ($secure_link = "") {
             return 403;
         }

         add_header X-App-Secure-Uri $uri always;
         add_header X-App-Secure-St $arg_st always;
         add_header X-App-Secure-Addr $remote_addr always;
         add_header X-App-Secure-RealIP 
$realip_remote_addr always;
         add_header X-Forwarded-For $http_x_forwarded_for 
always;
     }
}

}

nginx -c /tmp/nginx.tst.cfg
kill `cat /var/run/nginx.tst.pid`


Тестовый файл:

echo "tst.txt" > /tmp/tst.txt


При закомментированном if имеем ожидаемый ответ с 
переопределением remote_addr, что видно по заголовку 
X-App-Secure-Addr в ответе:

# curl -v -H "Host: vhost" -H "X-Forwarded-For: 8.8.8.8" 
 http://127.0.0.1/tst.txt
*   Trying 127.0.0.1...
* TCP_NODELAY set
* Connected to 127.0.0.1 (127.0.0.1) port 80 (#0)
> GET /tst.txt HTTP/1.1
> Host: vhost
> User-Agent: curl/7.57.0
> Accept: */*
> X-Forwarded-For: 8.8.8.8
>
< HTTP/1.1 200 OK
< Server: nginx/1.10.3
< Date: Mon, 20 Aug 2018 17:51:31 GMT
< Content-Type: text/plain
< Content-Length: 8
< Last-Modified: Mon, 20 Aug 2018 17:47:59 GMT
< Connection: keep-alive
< ETag: "5b7afecf-8"
< X-App-Secure-Uri: /tst.txt
< X-App-Secure-Addr: 8.8.8.8
< X-App-Secure-RealIP: 127.0.0.1
< X-Forwarded-For: 8.8.8.8
< Accept-Ranges: bytes
<
tst.txt
* Connection #0 to host 127.0.0.1 left intact


Если разкомментировать if, то что-то ломается.
Судя по заголовкам ответа, переопределение значения 
remote_addr не происходит,
и в модуле secure_link также используется IP подключения, 
а не из заголовка X-Forwarded-For.
Модуль secure_link разрешает доступ, если подпись 
сформирована для 127.0.0.1

# echo -n "127.0.0.1_/tst.txt" | openssl md5 -binary | 
openssl base64 | tr +/ -_ | tr -d =
AEfp-bT-tHrEfZN8lwDJGQ

# curl -v -H "Host: vhost" -H "X-Forwarded-For: 8.8.8.8" 
 http://127.0.0.1/tst.txt?st=AEfp-bT-tHrEfZN8lwDJGQ
*   Trying 127.0.0.1...
* TCP_NODELAY set
* Connected to 127.0.0.1 (127.0.0.1) port 80 (#0)
> GET /tst.txt?st=AEfp-bT-tHrEfZN8lwDJGQ HTTP/1.1
> Host: vhost
> User-Agent: curl/7.57.0
> Accept: */*
> X-Forwarded-For: 8.8.8.8
>
< HTTP/1.1 200 OK
< Server: nginx/1.10.3
< Date: Mon, 20 Aug 2018 18:05:09 GMT
< Content-Type: text/plain
< Content-Length: 8
< Last-Modified: Mon, 20 Aug 2018 17:47:59 GMT
< Connection: keep-alive
< ETag: "5b7afecf-8"
< X-App-Secure-Uri: /tst.txt
< X-App-Secure-St: AEfp-bT-tHrEfZN8lwDJGQ
< X-App-Secure-Addr: 127.0.0.1
< X-App-Secure-RealIP: 127.0.0.1
< X-Forwarded-For: 8.8.8.8
< Accept-Ranges: bytes
<
tst.txt
* Connection #0 to host 127.0.0.1 left intact

Ожидалось, что доступ будет разрешаться для IP 8.8.8.8, 
значение которого
передается через X-Forwarded-For. Этого не происходит:


# echo -n "8.8.8.8_/tst.txt" | openssl md5 -binary | 
openssl base64 | tr +/ -_ | tr -d =
WEpfZcYFo9shAa3_pwtACw


# curl -v -H "Host: vhost" -H "X-Forwarded-For: 8.8.8.8" 
 http://127.0.0.1/tst.txt?st=WEpfZcYFo9shAa3_pwtACw
*   Trying 127.0.0.1...
* TCP_NODELAY set
* Connected to 127.0.0.1 (127.0.0.1) port 80 (#0)
> GET /tst.txt?st=WEpfZcYFo9shAa3_pwtACw HTTP/1.1
> Host: vhost
> User-Agent: curl/7.57.0
> Accept: */*
> X-Forwarded-For: 8.8.8.8
>
< HTTP/1.1 403 Forbidden
< Server: nginx/1.10.3
< Date: Mon, 20 Aug 2018 18:07:14 GMT
< Content-Type: text/html
< Content-Length: 169
< Connection: keep-alive
< X-App-Secure-Uri: /tst.txt
< X-App-Secure-St: WEpfZcYFo9shAa3_pwtACw
< X-App-Secure-Addr: 127.0.0.1
< X-App-Secure-RealIP: 127.0.0.1
< X-Forwarded-For: 8.8.8.8
<
<html>
<head><title>403 Forbidden</title></head>
<body bgcolor="white">
<center><h1>403 Forbidden</h1></center>
<hr><center>nginx/1.10.3</center>
</body>
</html>
* Connection #0 to host 127.0.0.1 left intact

Какие будут рекомендации?

Спасибо.


Подробная информация о списке рассылки nginx-ru