allow/deny and return

Gena Makhomed gmm at csdoc.com
Thu Oct 17 12:55:17 UTC 2013


On 17.10.2013 2:18, Maxim Dounin wrote:

>> тогда "allow/deny vs return" перестанет быть такой уж острой проблемой.
>> сейчас код "error_page 456 @default; return 456;" использовать нельзя,
>> потому что он отрабатывает до access-проверок и админка будет без защиты
>
> Повторяю: не перестанет.  Если есть проблема - нужно её решать, а
> не придумывать альтернативы.  Потому что так или иначе _будут_
> люди, которые пишут return, rewrite, и т.п. неправильно.  И от
> добавления нового механизма - их не станет меньше.  Лучшее, на что
> приходится расчитывать, это что их станет меньше в процентах от
> общего числа пользователей - но и это не гарантировано.  Наоборот,
> есть неслабая вероятность, что их станет больше, потому что
> пользователи окончательно запутаются в существующих механизмах.

Понятно. А как решать-то? "Выполнять сначала access-проверки,
и только потом директивы модуля rewrite - ни разу не вариант"

я предлагаю вариант решения проблем с allow/deny and return:

location /closed {
   allow 10.1.1.1;
   deny all;
   handler @secret;
}

location @secret {
   return 200 "secret\n";
}

то есть, nginx можно будет сконфигурировать тем способом, как это надо.
надо чтобы rewrite работал до access - будет, надо чтобы access работал
до rewrite - это тоже можно будет легко получить. разве это не решение?

нельзя просто так взять и переставить порядок отработки access/rewrite,
потому что если поменять их местами, тогда сломаются конфигурации вида:

if ($evil) {
     return 444;
}

set $file ".htpasswd";
auth_basic_user_file /path/to/$file;

кроме решения проблем с порядком срабатывания модулей rewrite/access
эта же новая директива позволит справиться с проблемой дублирования
одинаковых фрагментов конфига внутри разных location`ов. других путей,
как избежать дублирования фрагментов конфига на сегодня не существует.

"Не надо умножать сущности без необходимости"

это да. но если более простых способов решения проблем не существует,
то может быть все-таки есть необходимость добавить новую директиву?

сущности, кстати, не умножаются, потому что content handler`ы
и named location`ы в nginx и так уже давно есть. просто добавляется 
возможность их явного указания и конфигурирования без дубликатов.

я не настаиваю, что это будет самое идеальное решение,
но лучших вариантов решения проблем пока что не видел.

вообще ничего с этими проблемами не делать и оставить все как есть,
- это тоже вариант, но разве это лучше, чем добавить директиву handler?

>>> Игорь тут уже как-то попробовал решать проблемы модуля rewrite с
>>> помощью добавления директивы try_files.  Стало только хуже, т.к.
>>> старые проблемы никуда не делись, а новых добавилось - в
>>> количестве.
>>
>> а какие проблемы появились из-за добавления директивы try_files ?
>
> Вот тут небольшая подборка плохого:
>
> http://trac.nginx.org/nginx/ticket/97
>
> И это не говоря о всяких мелочах вроде "try_files не работает
> из-за if'а", которые традиционно относятся к проблемам if'а, и
> развлечениях людей, которым доставляет отсутствие наследования
> try_files.

разве было бы лучше, если бы директивы
try_files в nginx вообще не было бы?

и любой конфиг, который сейчас пишется
с try_files можно легко написать без try_files?

то есть самым лучшим варианом было бы "ничего не менять",
или каким наилучшим способом можно было бы решить проблемы,
которые сейчас, пусть и не идеально, решает директива try_files?

>> ведь изменения там были минимальными:
>>
>> location / {
>>      try_files $uri $uri/ @drupal;
>> }
>>
>> - это просто синтаксический сахар для
>>
>> location / {
>>      error_page 404 = @drupal;
>>      log_not_found off;
>> }
>
> Хороший пример конфига, в котором try_files - использовать, вообще
> говоря, не надо.  Хотя писать и проще.
>
> Вариант с error_page 404 - атомарен, в то время как в варианте с
> try_files - race condition.  Между проверкой существования файла и
> его реальным открытием в модуле static для возврата клиенту - файл
> может быть удалён, и клиенту вернут 404.  Не говоря уже про лишний
> syscall.

если используется модуль static - да, можно выкрутиться и с error_page,
но если вместо static другой content handler - придется как минимум,
использовать if, который работает после access. и здесь тоже будет
и "лишний syscall" и "race condition" и еще уйма других проблем,
из-за неочевидного порядка срабатывания модулей access/rewrite
и глюков работы директивы if, - http://wiki.nginx.org/IfIsEvil

как можно решить все проблемы с if ? судя по wiki способ только один:
"Looks like the only correct fix would be to disable non-rewrite 
directives inside if completely. It would break many configuration out 
there though, so wasn't done yet."

добавление новой директивы try_files не имеет недостатка
"would break many configuration out there though" и это было
меньшее зло, чем "ничего не делать и оставить все как есть".

по крайней мере, лучшего варианта решения
этих проблем никто не предложил пока что.

>> допустим, нет у нас директивы try_files. каким образом тогда можно
>> сделать с помощью nginx защищенную basic auth и allow/deny админку,
>> в которой статика будет отправляться клиентам напрямую, существующие
>> на диске файлы с расширением .php будут обрабатываться другим способом,
>> а запросы которым не соответствует файл на диске - третьим способом ?
>>
>> было бы очень интересно посмотреть на вариант решения без try_files.
>
> Я бы делал как-то так (с точностью до проверки существования
> php-файлов на диске, дополнить при необходимости):
>
>      location /admin/ {
>          allow ...
>          deny ...
>          auth_basic ...
>
>          error_page 404 = /admin/404;
>          log_not_found off;
>
>          location = /admin/404 {
>              ...
>          }
>
>          location ~ \.php$ {
>              fastcgi_pass ...
>              ...
>          }
>      }
>

location ~ \.php$ {
     if (-e $uri) {
         fastcgi_pass ...
         ...
     }
     fastcgi_pass ...
     ...
}

так? но этот способ ведь не рекомендуется, потому что IfIsEvil.

и при попадании в location /admin/404 $uri будет меняться,
так что невозможно будет понять какой был исходный запрос.

> Впрочем, вариантов - масса, написать allow/deny/auth_basic никто
> не запрещает больше, чем в одном location'е.

потом такой конфиг будет трудно поддерживать,
потому что и менять allow/deny/auth_basic надо будет везде.

дублирование конфига - это просто меньшее зло, если выбирать
между "дублировать конфиг" и "это сделать вообще невозможно".

если можно то же самое получить без дублирования конфига -
такое новое решение будет лучшим и более удобным в работе.

вот location /admin/ пока что не рабочая, а ведь еще точно такой же
конфиг надо будет написать и для публичной части сайта в location /

> И совершенно не обязательно "обходиться без использования if".

а разве тут можно обойтись использованием if, так чтобы внутри
директивы if использовались только директивы из модуля rewrite ?

разве что только используя error_page 418 = @other; return 418;
что тоже не рекомендуется, потому что выглядит как ugly hack...

то есть без использования try_files даже такую простую задачу решить
вообще нельзя без использования опасных и не-рекомендуемых вариантов.

> Речь, впрочем, не об этом.  Речь о том, что try_files, который
> делался как попытка "решить" проблемы if'а, вытеснив его из
> конфигов, ни разу его не вытеснил.  Наоборот, к существовавшим
> ранее проблемам - добавились новые, в том числе - связанные с
> работой try_files со всё тем же if'ом.

а разве есть лучший вариант решения проблем с if ?
"ничего не делать" - этот вариант хуже чем try_files

и try_files и handler уменьшают количество случаев,
когда необходимо использовать "опасные" варианты if.

-- 
Best regards,
  Gena



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