You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
92 lines
5.0 KiB
92 lines
5.0 KiB
8 years ago
|
---
|
||
|
title: nginx auth_request (1/3): Вводная
|
||
|
tags: nginx, software, devel, репост
|
||
|
---
|
||
|
У меня тут накопилось немного опыта работы с этим модулем, решил поделиться.
|
||
|
|
||
|
Прежде всего - что это? Это модуль, который разрешает или запрещает прохождение запроса в nginx на основе **подзапроса**.
|
||
|
Две основных схемы применения:
|
||
|
|
||
|
* с его помощью можно соорудить WAF (web-application firewall)
|
||
|
* ...и кастомный портал предварительной авторизации
|
||
|
|
||
|
...всё перечисленное - без модификации исходного сайта.
|
||
|
|
||
|
- [Вводная](/articles/2017/05/16/nginx-authreq-1/)
|
||
|
- [Многофакторная авторизация, NFA](/articles/2017/05/17/nginx-authreq-2/)
|
||
|
- [WAF, Web-Application firewall](/articles/2017/05/18/nginx-authreq-3/)
|
||
|
|
||
|
---
|
||
|
|
||
|
Выглядит это примерно так. Вот у нас есть типовой запрос, приходящий на некоторый вебсервер:
|
||
|
|
||
|
GET /files/83084_s.jpg HTTP/1.1
|
||
|
Host: example.com
|
||
|
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:52.0) Gecko/20100101 Firefox/52.0
|
||
|
Accept: */*
|
||
|
Accept-Language: ru-RU,ru;q=0.8,en-US;q=0.5,en;q=0.3
|
||
|
Accept-Encoding: gzip, deflate
|
||
|
Connection: keep-alive
|
||
|
|
||
|
nginx пересылает его сначала на указанный location, затем на основе ответа,
|
||
|
решает что делать - пустить дальше или выдать ошибку.
|
||
|
|
||
|
Общая схема запросов ([исходник](req-graph.msc)):
|
||
|
|
||
|
![](req-graph.png)
|
||
|
|
||
|
Authorizer - это отдельная internal локация nginx'а.
|
||
|
Там может быть или `proxy_pass` на внешний сервер, или вызов скриптов с этого же сервера.
|
||
|
|
||
|
Примерный конфиг nginx'а:
|
||
|
|
||
|
location / {
|
||
|
auth_request /auth;
|
||
|
proxy_pass http://site.example.com;
|
||
|
}
|
||
|
location = /auth {
|
||
|
internal;
|
||
|
proxy_pass http://127.0.0.1/check.pl;
|
||
|
proxy_pass_request_body off; # <- важно
|
||
|
proxy_set_header Content-Length "0"; # <- важно
|
||
|
proxy_set_header X-Original-URI $request_uri;
|
||
|
}
|
||
|
|
||
|
Обратите внимание на `Content-Length "0"`.
|
||
|
Нужно это затем, чтобы в пересылаемом POST запросе получатель не ждал данных.
|
||
|
|
||
|
Далее, допустим мы соорудили некий check.pl, который на основе пересланных запросов будет отвечать кодами 200/401/403/etc.
|
||
|
С 200/OK - всё ясно, запрос проходит дальше. В случае остальных, например 403 - в дефолте nginx покажет простенькую,
|
||
|
и совершенно неинформативную страничку "Access Denied".
|
||
|
Чтобы этого не было, нам нужно добавить в блок `location / {}` перехват этих кодов:
|
||
|
|
||
|
location / {
|
||
|
<...>
|
||
|
error_page 401 /auth.pl;
|
||
|
error_page 403 /auth.pl;
|
||
|
}
|
||
|
|
||
|
... где `/auth.pl` -- страница авторизации или сообщения об ошибке.
|
||
|
|
||
|
Здесь вырисовывается две проблемы: во-первых, нам нужно прописать локейшн и для `/auth.pl`,
|
||
|
во-вторых -- 401/403 коды могут использоваться и в самом сайте.
|
||
|
Первое бы хрен с ним, но второе -- реально проблема, если перехватывать **все** 403 с сайта,
|
||
|
мы можем использовать для этой ошибки только одну *глобальную* страницу на сайт.
|
||
|
|
||
|
Для обхода этого кейса, я написал [небольшой патч](authreq-302.patch),
|
||
|
который позволяет также использовать код 302, временный редирект.
|
||
|
Правда с включением в апстрим меня завернули, дескать это поломает
|
||
|
использование этого модуля как **одного из** факторов авторизации:
|
||
|
|
||
|
location / {
|
||
|
proxy_pass http://site.example.com;
|
||
|
auth_req /auth; # запрос должен быть авторизован через nginx authreq
|
||
|
allow 192.168.0.0/16; # ...ИЛИ идти из локальной сети
|
||
|
deny all;
|
||
|
satisfy any; # <- "или" - берётся отсюда
|
||
|
}
|
||
|
|
||
|
В принципе, надо - берите. Если таки забодаете апстрим - вообще респект и уважуха :-).
|
||
|
|
||
|
Далее покажу примеры реального использования для каждого случая.
|