Nginx-ru mailing list archive (nginx-ru@sysoev.ru)
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: proxy cache key и fastcgi cache key
On Friday 10 January 2014 13:45:27 Gena Makhomed wrote:
> On 10.01.2014 12:24, Валентин Бартенев wrote:
> >>> Кому интересно почитать, подробней вот ссылка.
> >>> http://habrahabr.ru/post/166855/
> >>>
> >>> Как видите, корректное значения имеют только переменные $host и
> >>> $server_name, все что основывается на $http_host имеет потенциал
> >>> уязвимость, если бекенд доверяет этой переменой, лично я знаю несколько
> >>> популярных РНР фрейморков которые используют эту переменную без проверки
> >>> и без экранирования в SQL запросах.
> >>
> >> и пофиксить эту проблему можно в исходниках nginx таким образом,
> >> что если вдруг в переменных $host и $http_host оказываются разные
> >> значения, чтобы nginx в $http_host записывал значение из $host.
> >>
> >> тогда после установки следующего обновления nginx эта уязвимость
> >> в backend`ах автоматически пофиксится у всех пользователей nginx.
> >>
> >> причем без какой-либо необходимости пользователям править
> >> файлы fastcgi.conf / fastcgi_params и все производные от них.
> >
> > Так, между делом, хочу напомнить, что на CGI есть спецификация,
> > описывающая
> > все переменные окружения, которые сервер должен передавать приложению.
> > И в ней вполне черным по белому сказано, что все переменные HTTP_* это
> > protocol specific переменные полученные из заголовков переданных клиентом.
>
> fastcgi_param HTTP_HOST1 $http_host;
> fastcgi_param HTTP_HOST2 $host;
> fastcgi_param HTTP_HOST3 $server_name;
>
> Делаем запрос:
> GET http://site3.dev/phpinfo.php HTTP/1.1
> Host:~%#$^&*()<>?@\!."'{}[]=+|
>
> На выходе получим
> _SERVER["HTTP_HOST1"]: ~%#$^&*()<>?@\!."'{}[]=+|
> _SERVER["HTTP_HOST2"]: site3.dev
> _SERVER["HTTP_HOST3"]: site2.dev
>
> В переменной $host правильное значение,
> в переменной $http_host все что угодно.
Что значит "правильное"? С точки зрения спецификации,
правильное значение HTTP_HOST1 - это значение из заголовка
Host1 (с учетом оговоренных преобразований) и никак иначе
не надо трактовать переменные HTTP_* они имеют вполне
специфическое назначение - а именно получить raw-данные из
запроса.
И если обратить внимание, то в конфигурации вообще нигде не указывается
fastcgi_param HTTP_HOST $http_host;
nginx, как и положено, автоматически преобразует заголовки в HTTP_*
переменные.
Если заголовка Host в запросе вообще не будет, то и переменной HTTP_HOST
быть также не должно.
> А ведь именно на основании значения переменной $host
> nginx и принимает решение в какой server направить запрос
> на обработку. Но к FastCGI уходит не $host, с которым
> работал nginx принимая решение, а fake-значение из $http_host
Если мы говорим про переменную HTTP_HOST, так и должно быть.
> Они то protocol specific, но раз запрос клиента попал в server
> где в server_name прописано site3.dev - клиент искренне полагает,
Клиент?
> что надлежащую проверку уже провел nginx, ведь в конфиге пользователь
> прописал:
>
> server {
> listen 80 default_server;
> return 444;
> }
>
> B значит все другие значения HTTP_HOST, которые не соответствуют
> нормальным значениям server_name должны попадать в этот server-заглушку.
Значит из чего? Из того, что кто-то так полагает? Неправильно полагает.
> Поэтому валидировать еще раз то, что и так уже провалидировал nginx
> никакого смысла нет. С точки зрения обычных пользователей, коих 99.999%.
Обычных пользователей? Может быть, но приложения пишут, минуточку, не
обычные пользователи, а программисты, что предполагает наличие каких-то
профессиональных навыков, нет? Если программист использует какую-то
переменную не понимая её назначения, то едва ли ему можно чем-то помочь,
проблемы у него возникнут не только с HTTP_HOST, а и в 1000 других мест.
> Я и сам так считал до недавнего времени, доверяя документации nginx:
>
> http://nginx.org/en/docs/http/request_processing.html
>
> http://nginx.org/en/docs/http/server_names.html
>
> http://nginx.org/en/docs/http/ngx_http_core_module.html#server_name
Где в документации что-то написано о:
> B значит все другие значения HTTP_HOST, которые не соответствуют
> нормальным значениям server_name должны попадать в этот server-заглушку
?
>
> > И есть безопасная и специфицированная переменная SERVER_NAME.
>
> она есть такая только для FastCGI,
Она есть такая во всех CGI-подобных протоколах.
> а для proxy_pass на апач - все не так просто, если погуглить
> server_name http_host site:bugs.php.net
Поэтому умолчания для proxy_* и fastcgi_* отличаются.
> тем более, что в SERVER_NAME со стороны веб-сервера
> будет приезжать каноническое имя сервера, а это обычно hostname.
> и для всех виртуальных хостов будет одинаковое значение SERVER_NAME.
Виртуальный хост с точки зрения конфигурации nginx - это одна секция
блока server. Если пользователь руководствуется другой идеологией,
то должен соответствующим образом исправить конфигурацию.
> путаницы с этим хватает: https://stackoverflow.com/questions/1459739/
>
> Поэтому те кто пишут на php не могут доверять значению SERVER_NAME,
> и у них остается единственный вариант - только переменная HTTP_HOST.
И если они используют переменную HTTP_HOST, то они её должны соответствующим
образом проверять. Почему те, кто пишут на других языках, это понимают, а
"те кто пишут на php" - это такая особая категория, им нужно особое
снисхождение и сочувствие?
> > Если кто-то в приложении использует данные полученные от клиента без
> > надлежащей проверки, когда в любой книжке "web-programming for dummies"
> > написано по 5 раз, что не следует доверять этим данным, то что я могу
> > предложить? Расстрел.
>
> Они проверяют и валидируют значение HTTP_HOST средствами nginx,
> так как это прописано в документации к nginx, и рекомендовано
> разработчиками nginx. Зачем два раза проверять одно и то же?
Где? Цитату из документации, где прописано, что HTTP_HOST валидируется?
> Как будто мало разработчикам проблем с самим php
> и его глюками, например, cgi.fix_pathinfo 1 по умолчанию:
> http://habrahabr.ru/post/100961/#comment_3125990
>
> Так теперь еще и с nginx при использовании php-fpm
> эти глюки. А ведь php-fpm это наверное основной уже
> способ как использовать php и nginx.
Следование спецификации это сейчас глюком называется? Чем в этом отношении
отличается любой другой сервер? Вы хотите сказать, что в случае того же
mod_fastcgi в HTTP_HOST будет что-то другое?
Даже в документации по PHP написано:
http://www.php.net/manual/en/reserved.variables.server.php
'HTTP_HOST'
Contents of the Host: header from the current request, if there is one.
Где тут что-то про валидацию сервером?
> Попробую иначе спросить: что может поломать предложенный
> мной выше fix, который будет закрывать эту уязвимость в backend`ах,
> которые доверяют значению переменной HTTP_HOST полученной от nginx?
Все нормальные приложения, которые рассчитывают получить в HTTP_HOST сырое
значение из заголовка и далее использовать его соответствующим образом.
Допустим ваше приложение занимается выявлением распространенных атак и
превентивно блокирует злоумышленников. Или задача вашего приложения выводить
или логгировать заголовки клиента.
Пример одного из самых распространенных приложений: phpinfo.php - начинает
отображать _неверное_ значение HTTP_HOST.
> "Самый эффективный способ защиты ? явно определить HTTP_HOST на стороне
> веб сервера." - цитата из статьи http://habrahabr.ru/post/166855/
Защиты от чего? От кривых рук и дилетантов защиты не существует в принципе.
> Сейчас же nginx по-умолчанию отправляет на backend
> значения $proxy_host и $http_host вместо ожидаемого там $host.
>
> Если глюк с $proxy_host очевиден, то глюк с $http_host совсем нет.
>
> Способы решения проблемы:
>
> 1. Расстрелять всех, кто пишет кривой код. - Нереально.
>
> 2. Исправить все глюки и весь кривой код. - Нереально.
>
> 3. Всем вручную добавить fix в fastcgi_param HTTP_HOST $host;
>
> 4. Добавить этот fix в дефолтовые конфиги nginx.
>
> 5. Исправить это один раз в коде nginx и забыть про проблему.
И создать другую, на мой взгляд ещё большую проблему на века.
Оригинальная проблема не исправляется "фиксом" в конфигурацию.
Ибо оригинальная проблема, как было выше указано - кривой код,
который сломается сразу в другой конфигурации и/или на другом
сервере.
Предлагать исправить переменную HTTP_HOST, это то же самое,
что предлагать сразу исправить переменную $http_host на основании
того, что кто-то там что-то полагает.
Да, кстати, а почему действительно предложение исправить HTTP_HOST,
а не $http_host?
Уверен, найдется не одна конфигурация, где люди используют значение
$http_host в директиве alias например. Может и их нужно защитить?
Чем они хуже особой категории "те кто пишут на php"?
--
Валентин Бартенев
_______________________________________________
nginx-ru mailing list
nginx-ru@xxxxxxxxx
http://mailman.nginx.org/mailman/listinfo/nginx-ru
|