Re: proxy cache key и fastcgi cache key

2014-01-12 Пенетрантность S.A.N
Для убедительности, приведу ещё такой пример.
Есть бекенд приложения, которое обслуживает множество хостов, всех этих
хостах fastcgi_pass одинаковы, роутинг внутри приложения осуществляется по
HTTP_HOST, дело в том, что использовать для роутинга SERVER_NAME, часто
невозможно по ряду причин.

Nginx, конфиг:

server {
 server_name example.com {

   location /private/ {
   internal;
   auth_basic Private ;
   auth_basic_user_file conf/htpasswd;
   ...
   }

fastcgi_pass 127.0.0.1:9000;
  }
}

server {
 server_name other.com {
  …
 fastcgi_pass 127.0.0.1:9000;
  }
}

Теперь делаем запрос

GET http://other.com/private/  HTTP/1.1
Host: example.com

Nginx, определяет вирт хост как other.com в котором нет директив для
location /private/ {internal; auth_basic}, но при этом Nginx передает
бекенду HTTP_HOST = example.com, бекенд проверяет HTTP_HOST и отдает контент
для example.com/private/.

Если вы не считаете это багом Nginx, тогда объясните мне, зачем указывать в
location директивы internal; auth_basic, если любой студент сможет их
обойти.

Данная уязвимость открыта для всех бекендов которые для роутинга использует
HTTP_HOST, а как правило это именно так, одна из основных причин, бекенду
нужно работать и в default_server.

Можно конечно сделать на бекенде, мапинг server_name и хостов, всегда на
каждом запросе проверять isset($map[SERVER_NAME][ HTTP_HOST])
Но зачем все это, если в конфиге Nginx и так уже созданы все эти связи и
Nginx на каждом запросе их и так всегда проверяет.
По этому я считаю, что эту уязвимость нужно закрыть на уровне Nginx.

Posted at Nginx Forum: 
http://forum.nginx.org/read.php?21,246086,246301#msg-246301

___
nginx-ru mailing list
nginx-ru@nginx.org
http://mailman.nginx.org/mailman/listinfo/nginx-ru

Re: proxy cache key и fastcgi cache key

2014-01-11 Пенетрантность Gena Makhomed

On 11.01.2014 1:51, Валентин Бартенев wrote:


с RFC то как раз все в порядке: network location of the URI
(authority) MUST be transmitted in a Host header field,
только вот nginx не соответствует этим требованиям...

http://tools.ietf.org/search/rfc2616#section-5.1.2



Если почитать внимательнее, то приведенные требования относятся к клиенту.
Понятно, что сервер в принципе не может влиять на то, что transmitted в
запросе.


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

В тот момент, когда nginx делает http запрос к удаленному
серверу он выступает в роли клиента. поэтому я и цитировал 5.1.2


С точки зрения удаленного сервера да.  И при этом поступает совершенно
корректно, а именно передает network location of the URI (authority)
в заголовки Host.


В том-то и дело, что в настройке по-умолчанию он этого не делает:

server { server_name example.com; proxy_pass http://127.0.0.1/; }

Хотя nginx и определил, что имя хоста example.com,
на backend в заголовке Host: запроса он отправляет
совсем другое значение, в данном случае: 127.0.0.1

Очень наивно отправлять в заголовке Host: 127.0.0.1
клиентского запроса к своему upstream`у и ожидиать,
что в ответ придет контент для хоста example.com

То же самое касается и работы по протоколу FastCGI.
nginx верно определил, что имя виртуального хоста good-site.com
но на backend отправил в запросе совсем другу инфу bad-site.com


например, если исходный запрос от клиента к nginx был

GET http://good-site.com/pub/WWW/TheProject.html HTTP/1.1
Host: bad-site.com

содержимое заголовка Host: согласно 5.2.1 должно игнорироваться,
адрес хоста в этом случае: good-site.com

а согласно требований 5.1.2 - network location of the URI (authority)
MUST be transmitted in a Host header field, то есть исходящий запрос
должен быть

GET /pub/WWW/TheProject.html HTTP/1.1
Host: good-site.com

nginx же в настройке по-умолчанию не соответсвует RFC,
и вместо требуемого значения пишет в заголовок Host:
значение переменной $proxy_host


Поздравляю. Это самое необычное толкование RFC 2616, которое я когда либо
встречал.

К счастью оно разбивается об определение терминов client и server из него же:

client
   A program that establishes connections for the purpose of sending
   requests.

server
   An application program that accepts connections in order to
   service requests by sending back responses. Any given program may
   be capable of being both a client and a server; our use of these
   terms refers only to the role being performed by the program for a
   particular connection, rather than to the program's capabilities
   in general. Likewise, any server may act as an origin server,
   proxy, gateway, or tunnel, switching behavior based on the nature
   of each request.

ключевой момент тут: refers only to the role being performed by the program
for a particular connection.


 Соединение между клиент-nginx и соединение nginx-upstream - это два
 разных соединения, и в каждом из них nginx играет исключительно одну
 единственную роль, применимую только к конкретному соединению.

Все верно. В particular connection между браузером и nginx
- nginx выступает в роли сервера, и поэтому там требования из 5.2
а в particular connection между nginx и backend`ом - nginx выступает
в роли клиента и поэтому здесь он обязан выполнять требования 5.1.2


В соединении клиент-nginx не играет роль клиента и клиентские требования
RFC 2616 в данном соединении к нему не применимы.


Клиентские требования из п.5.1.2 RFC 2616
применимы к nginx в своединении nginx-upstream

Внутри какого-то server { ... } - nginx определил,
имя виртуального хоста (authority) соответственно
именно это имя виртуального хоста он MUST передать
в заголовке Host: при запросе к upstream серверу.

Только таким способом, с помощью заголовка Host:
upstream сможет отличить один виртуальный сервер
от другого и дать своему клиенту верный ответ.

Это же очевидно, если кто-то хочет получить в ответ
страницу с сайта гугла, то в заголовке Host: своего
запроса он обязан отправить именно google.com.
А если отправить там microsoft.com - то ничего
работать не будет и так делать нельзя, см. 5.1.2

Тут у нас точно такая же ситуация,
только в роли клиента выступает nginx.


Теперь рассмотрим вариант связи с backend`ом по протоколу FastCGI,
но поскольку у нас большой и сложный сайт сделаем два фронтенда:

1) основной nginx frontend
2) nginx frontend на хосте backend`а
3) backend, работающий по протоколу FastCGI.

запрос от клиента проходит цепочку (1)-(2)-(3).
поскольку между (1) и (2) используется протокол http,
то согласно требований 5.1.2 и 5.2.1 на (2) запрос приходит
в виде

GET /pub/WWW/TheProject.html HTTP/1.1
Host: good-site.com

не смотря на то, что в исходном запросе
от клиента был игнорируемый заголовок Host: bad-site.com

а дальше - все просто. В соответствии с требованиями
спецификации протокола FastCGI - nginx записывает в переменную

Re: proxy cache key и fastcgi cache key

2014-01-11 Пенетрантность Gena Makhomed

On 11.01.2014 2:17, Валентин Бартенев wrote:


Подводя итог, не надо вырывать отдельные фразы из RFC и пытаться их
интерпретировать в свою пользу.

Когда nginx выступает в роли клиента, он пытается соблюдать соответствующие
требования спецификации и делает это неплохо.  Аналогично в роли сервера.

Что происходит между - зависит от настроек.

Спецификация на протокол HTTP, очевидно, не специфицирует настоек nginx'а,
и попытки её за уши к этому притянуть - бесполезны.


http://tools.ietf.org/search/rfc2616#section-5.2

5.2 The Resource Identified by a Request
...
   An origin server that does differentiate resources based on the host
   requested (sometimes referred to as virtual hosts or vanity host
   names) MUST use the following rules for determining the requested
   resource on an HTTP/1.1 request:

   1. If Request-URI is an absoluteURI, the host is part of the
 Request-URI. Any Host header field value in the request MUST be
 ignored.



Это требование RFC 2616 не выполняется.

Вместо того чтобы игнорировать Host header field value
nginx передает его на backend в качестве имени хоста.

Вместо требуемого RFC host is part of the Request-URI

и вот еще:

http://tools.ietf.org/search/rfc3875#section-3.1

3.1.  Server Responsibilities

   The server acts as an application gateway.  It receives the request
   from the client, selects a CGI script to handle the request, converts
   the client request to a CGI request, executes the script and converts
   the CGI response into a response for the client.

Вот это требование RFC 3875 не выполняется.

Вместо того, чтобы корректно сконвертировать запрос от клиента
в CGI запрос - nginx использует при формировании запроса к клиенту
то значение из заголовка Host:, которое согласно требований RFC 2616
он MUST проигнорировать и вместо него MUST использовать host part of the 
absolute Request-URI.


дополнительная информация:

http://tools.ietf.org/search/rfc2616#section-19.6.1.1

--
Best regards,
 Gena

___
nginx-ru mailing list
nginx-ru@nginx.org
http://mailman.nginx.org/mailman/listinfo/nginx-ru

Re: proxy cache key и fastcgi cache key

2014-01-10 Пенетрантность Валентин Бартенев
On Friday 10 January 2014 00:57:16 Gena Makhomed wrote:
 On 09.01.2014 21:03, S.A.N wrote:
  Вот наглядный пример:
  fastcgi_param   HTTP_HOST1  $http_host;
  fastcgi_param   HTTP_HOST2  $host;
  fastcgi_param   HTTP_HOST3  $server_name;
  
  Делаем, запрос
  GET http://site3.dev/ HTTP/1.1
  Host:~%#$^*()?@\!.'{}[]=+|
  
  На выходе получим
  _SERVER[HTTP_HOST1]: ~%#$^*()?@\!.'{}[]=+|
  _SERVER[HTTP_HOST2]: site3.dev
  _SERVER[HTTP_HOST3]: site2.dev
  
  Кому интересно почитать, подробней вот ссылка.
  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 переменные полученные из заголовков переданных клиентом.
И есть безопасная и специфицированная переменная SERVER_NAME.

Если кто-то в приложении использует данные полученные от клиента без 
надлежащей проверки, когда в любой книжке web-programming for dummies
написано по 5 раз, что не следует доверять этим данным, то что я могу
предложить?  Расстрел.

--
Валентин Бартенев
___
nginx-ru mailing list
nginx-ru@nginx.org
http://mailman.nginx.org/mailman/listinfo/nginx-ru

Re: proxy cache key и fastcgi cache key

2014-01-10 Пенетрантность Gena Makhomed

On 10.01.2014 13:45, Gena Makhomed wrote:


Кому интересно почитать, подробней вот ссылка.
http://habrahabr.ru/post/166855/


Хотя, есть и более простой вариант,
как на стороне nginx закрыть эту уязвимость с $http_host.

$host
in this order of precedence: host name from the request line, or host 
name from the “Host” request header field, or the server name matching a 
request


Eсли в request line оказывается одно значение $host,
а в “Host” request header field оказывается другое значение,
тогда просто возвращать 400 Bad Request, поскольку от нормального
клиента (браузера и т.п.) такой запрос никакогда придти не может.

Это формально правильный способ, но менее удобный для разработчиков,
потому что вполне может быть такой вариант, что это default server
и запрос придет вообще без заголовка Host: - тогда в HTTP_HOST
будет пусто и backend скорее всего нормально не отработает.

Поэтому мне больше нравится вариант в случае несоответствия
значений переменных $host и $http_host - в $http_host писать
значение $host. Тем более, что в случае запроса по ип-адресу
тогда в HTTP_HOST на backend уйдет значение из $server_name.
И любой современный код отработает на такой запрос нормально.

Это максимально надежный и максимально безглючный вариант.

А если backend - apache, в его SERVER_NAME может быть другое
значение, отличное от правильного значения $server_name из nginx.
И тут будут аналогичные проблемы, что и сейчас с $host и $http_host.

P.S.

Или сделать это поведение конфигурируемым, возвращать 400 ошибку,
или писать в $http_host значение из $host. По дефолту может быть
например, перезапись $http_host значением из $host, кому это не подходит 
- могут настроить возврат 400 ошибки или даже полностью

выключить какую-либо реакцию на эти попытки взлома веб-сервера
и пропускать их as is на backend, пусть он попробует защититься.

Есть такое мнение, что это вообще идеальный вариант решения проблемы.
Не могу даже придумать кому и почему может не понравиться такой вариант.

--
Best regards,
 Gena

___
nginx-ru mailing list
nginx-ru@nginx.org
http://mailman.nginx.org/mailman/listinfo/nginx-ru

Re: proxy cache key и fastcgi cache key

2014-01-10 Пенетрантность Валентин Бартенев
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_paramHTTP_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.

И 

Re: proxy cache key и fastcgi cache key

2014-01-10 Пенетрантность Валентин Бартенев
On Friday 10 January 2014 22:51:17 Gena Makhomed wrote:
 On 10.01.2014 15:07, Валентин Бартенев wrote:
 
  Кому интересно почитать, подробней вот ссылка.
  http://habrahabr.ru/post/166855/
 ...
  $host
  in this order of precedence: host name from the request line, or host
  name from the “Host” request header field, or the server name matching a
  request
 ...
  Единственный правильный способ: пойти в IETF с предложением исправить
  соответствующие RFC, которые в том числе оговаривают, что следует делать
  при получении нескольких заголовков Host, ну а потом уже сюда.
 
 с RFC то как раз все в порядке: network location of the URI
 (authority) MUST be transmitted in a Host header field,
 только вот nginx не соответствует этим требованиям...
 
 http://tools.ietf.org/search/rfc2616#section-5.1.2
[..]

Если почитать внимательнее, то приведенные требования относятся к клиенту.
Понятно, что сервер в принципе не может влиять на то, что transmitted в
запросе.

Что касается сервера, написано буквально секцией ниже:
http://tools.ietf.org/search/rfc2616#section-5.2

5.2 The Resource Identified by a Request

   The exact resource identified by an Internet request is determined by
   examining both the Request-URI and the Host header field.

   An origin server that does not allow resources to differ by the
   requested host MAY ignore the Host header field value when
   determining the resource identified by an HTTP/1.1 request. (But see
   section 19.6.1.1 for other requirements on Host support in HTTP/1.1.)

   An origin server that does differentiate resources based on the host
   requested (sometimes referred to as virtual hosts or vanity host
   names) MUST use the following rules for determining the requested
   resource on an HTTP/1.1 request:

   1. If Request-URI is an absoluteURI, the host is part of the
 Request-URI. Any Host header field value in the request MUST be
 ignored.

   2. If the Request-URI is not an absoluteURI, and the request includes
 a Host header field, the host is determined by the Host header
 field value.

   3. If the host as determined by rule 1 or 2 is not a valid host on
 the server, the response MUST be a 400 (Bad Request) error message.

   Recipients of an HTTP/1.0 request that lacks a Host header field MAY
   attempt to use heuristics (e.g., examination of the URI path for
   something unique to a particular host) in order to determine what
   exact resource is being requested.

Ровным счетом так nginx и поступает, если передан absoluteURI, то виртуальный
сервер определяется по нему, а заголовок Host игнорируется.

--
Валентин Бартенев
___
nginx-ru mailing list
nginx-ru@nginx.org
http://mailman.nginx.org/mailman/listinfo/nginx-ru

Re: proxy cache key и fastcgi cache key

2014-01-10 Пенетрантность Gena Makhomed

On 11.01.2014 0:17, Валентин Бартенев wrote:


Кому интересно почитать, подробней вот ссылка.
http://habrahabr.ru/post/166855/

...

$host
in this order of precedence: host name from the request line, or host
name from the “Host” request header field, or the server name matching a
request

...

Единственный правильный способ: пойти в IETF с предложением исправить
соответствующие RFC, которые в том числе оговаривают, что следует делать
при получении нескольких заголовков Host, ну а потом уже сюда.


с RFC то как раз все в порядке: network location of the URI
(authority) MUST be transmitted in a Host header field,
только вот nginx не соответствует этим требованиям...

http://tools.ietf.org/search/rfc2616#section-5.1.2

...

Если почитать внимательнее, то приведенные требования относятся к клиенту.
Понятно, что сервер в принципе не может влиять на то, что transmitted в
запросе.


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

В тот момент, когда nginx делает http запрос к удаленному
серверу он выступает в роли клиента. поэтому я и цитировал 5.1.2

а дальше, получив ответ от удаленного сервера он с этим ответом
делает разные интересные вещи, например, сканирует его на предмет
ssi-директив, или пропускает через свои sub/addition/и т.п. модули.
и то, что получится в результате - складывает в файл кеша на диске,
и после дополнительной цепочки преобразований - отправляет то,
что получилось в результате как ответ на запрос своего клиента.

например, если исходный запрос от клиента к nginx был

GET http://good-site.com/pub/WWW/TheProject.html HTTP/1.1
Host: bad-site.com

содержимое заголовка Host: согласно 5.2.1 должно игнорироваться,
адрес хоста в этом случае: good-site.com

а согласно требований 5.1.2 - network location of the URI (authority) 
MUST be transmitted in a Host header field, то есть исходящий запрос

должен быть

GET /pub/WWW/TheProject.html HTTP/1.1
Host: good-site.com

nginx же в настройке по-умолчанию не соответсвует RFC,
и вместо требуемого значения пишет в заголовок Host:
значение переменной $proxy_host

Теперь рассмотрим вариант связи с backend`ом по протоколу FastCGI,
но поскольку у нас большой и сложный сайт сделаем два фронтенда:

1) основной nginx frontend
2) nginx frontend на хосте backend`а
3) backend, работающий по протоколу FastCGI.

запрос от клиента проходит цепочку (1)-(2)-(3).
поскольку между (1) и (2) используется протокол http,
то согласно требований 5.1.2 и 5.2.1 на (2) запрос приходит
в виде

GET /pub/WWW/TheProject.html HTTP/1.1
Host: good-site.com

не смотря на то, что в исходном запросе
от клиента был игнорируемый заголовок Host: bad-site.com

а дальше - все просто. В соответствии с требованиями
спецификации протокола FastCGI - nginx записывает в переменную
HTTP_HOST значение good-site.com.

точнее, он ДОЛЖЕН так делать, согласно требований HTTP протокола
прямо из коробки, без какой-либо дополнительной настройки.

Эта схема работает одинаково вне зависимости от количества
промежуточных серверов между nginx frontend и backend.

точнее, ДОЛЖНА работать одинаково,
вне зависимости от количества промежуточных серверов.

если в случае отсутствия промежуточных серверов nginx ведет себя
не так, - то это BUG, ибо в случае, когда на nginx frontend
приходит запрос в виде absoluteURI, - тогда Any Host header
field value in the request MUST be ignored.
nginx этого по каким-то причинам не делает.

хотя согласно требований RFC - обе эти формы записи:

GET http://good-site.com/pub/WWW/TheProject.html HTTP/1.1

и

GET /pub/WWW/TheProject.html HTTP/1.1
Host: good-site.com

полностью эквивалентны между собой. и nginx имеет
полное право и даже обязанность трансформировать
запрос с absoluteURI в запрос с relativeURI
и network location of the URI (authority)
MUST be transmitted in a Host header field.

=


Что касается сервера, написано буквально секцией ниже:
http://tools.ietf.org/search/rfc2616#section-5.2

5.2 The Resource Identified by a Request

The exact resource identified by an Internet request is determined by
examining both the Request-URI and the Host header field.

An origin server that does not allow resources to differ by the
requested host MAY ignore the Host header field value when
determining the resource identified by an HTTP/1.1 request. (But see
section 19.6.1.1 for other requirements on Host support in HTTP/1.1.)

An origin server that does differentiate resources based on the host
requested (sometimes referred to as virtual hosts or vanity host
names) MUST use the following rules for determining the requested
resource on an HTTP/1.1 request:

1. If Request-URI is an absoluteURI, the host is part of the
  Request-URI. Any Host header field value in the request MUST be
  ignored.

2. If the Request-URI is not an absoluteURI, and the request includes
  a Host header field, the host is determined by the 

Re: proxy cache key и fastcgi cache key

2014-01-10 Пенетрантность Валентин Бартенев
On Friday 10 January 2014 19:40:07 S.A.N wrote:
  Ровным счетом так nginx и поступает, если передан absoluteURI, то
  виртуальный
  сервер определяется по нему, а заголовок Host игнорируется.
 
 Ровным счетом так же должен поступать и бекенд, игнорировать заголовок Host,
 если передан absoluteURI.
 Но дело в том что бекенд не получает, raw запрос с absoluteURI, именно по
 этой причине бекенду необходимо передать, то значения HTTP_HOST, которое
 использовал Nginx для определения вирт хоста.

Значение HTTP_HOST относится к FastCGI и определяется другим RFC, в котором
сказано:

   Meta-variables with names beginning with HTTP_ contain values read
   from the client request header fields, if the protocol used is HTTP.
   The HTTP header field name is converted to upper case, has all
   occurrences of - replaced with _ and has HTTP_ prepended to
   give the meta-variable name.  The header data can be presented as
   sent by the client, or can be rewritten in ways which do not change
   its semantics.

так что начиная уже с этой фразы и далее - вы не правы.


 В противном случаи возможны коллизии, приведу примеры.

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


 
 На одном хостинге, хостятся два конкурирующих электронных магазина,
 например: apple-shop.com и samsung-shop.com, в котором используется Nginx
 кеширования.
 Для каждого вирт хоста прописан proxy_cache_key $proxy_host$request_uri.
 
 Теперь делаем запрос
 GET http://apple-shop.com/ HTTP/1.1
 Host: samsung-shop.com
 
 В результате чего, ответ бекенда сохранится в кеше Nginx с ключом 
 samsung-shop.com/ но содержать внутри будет страницу apple-shop.com/. 
 На все последующие запросы samsung-shop.com будет отдаваться страница с
 товарами Apple, так как внутри кеш файла с ключом samsung-shop.com/ будет
 страница хоста apple-shop.com.

Не будет, если только в обоих случаях не указано:

 proxy_pass http://samsung-shop.com;

а если именно так и указано, то получаете ровно такое поведение, какое
было сконфигурировано, что же в этом странного?  Что настроили - то и 
получили.  Вы настраиваете HTTP сервер, что предполагает от вас хотя бы
минимальных знаний предмета и умения читать документацию.

Вы хотите пожаловаться на кольт 45-го калибра, что он позволят вам выстрелить
себе в ногу, да ещё разными способами?


 И так будут работать бекенды на любом языке программирования не только на
 РНР, те самые правильные программисты которых не расстреляли, будут в
 недоумения, что они сделали не так, вить все же сделано в точности как
 написано в официал документации Nginx :)

 1. В каком месте документации написано, что надо настраивать так, как было
указано вами выше?

 2. Как вообще всё вышеописанное вами относится к обсуждаемой в данной
подветке теме про http://habrahabr.ru/post/166855/ (которая вообще
не относится к кэшу и директивам proxy_cache_key/fastcgi_cache_key,
но уж так вышло, что была затронута)?

--
Валентин Бартенев
___
nginx-ru mailing list
nginx-ru@nginx.org
http://mailman.nginx.org/mailman/listinfo/nginx-ru

Re: proxy cache key и fastcgi cache key

2014-01-10 Пенетрантность S.A.N
 Коллизии возможны только в одном случае: программист не проверяет
 данные,
 получаемые от клиента, и такому программисту никаким костылями не
 поможешь.

Проверять на бекенде значения Host не рационально, если в конфигурации
server указан только один домен.
Если следовать вашей логике тогда, бекенд должен проверять не только Host,
но и IP коннекта чтобы убедится что это коннект от Nginx, так тоже никто не
делает потому что это не рационально, более эффективный способ настроить
фаирвол который закрывает извне доступ к портам бекенда.
Тоже самое с заголовком Host, в том же Apache директива UseCanonicalName On,
во многих дистрибутивах установлена по умолчанию или администраторы её
устанавливают самостоятельно.

Но если вы по прежнему считаете что проверка Host на бекенде, решает все
проблемы вы ошибаетесь, приведу пример.
Есть проект, в котором сайт имеет множество подоменов, каждый подомен
настроен в отдельном server{}.
Бекенд при получении запросов проверяет HTTP_HOST и в соответствии с его
значениям, выполняет разную логику и генерит разные страницы.
Каждый подомен настроен в отдельном server{} индивидуально и оптимизирован
под функционал каждого подомена.

Пример:

server
{
  server_name example.com
  …
  fastcgi_cache use_cache;
  ….
}

server
{
  server_name auth.example.com
  …
}

Как видите в первом вирт хосте есть Nginx кеширования, во втором его нет.

Теперь делаем запрос

GET http://auth.example.com/ HTTP/1.1
Host: example.com

Nginx, определяет вирт хост как auth.example.com в котором нет кешировании и
передает бекенду HTTP_HOST = example.com, бекенд проверяет HTTP_HOST и
генерит страницу для example.com.
Это позволяет устроить Ддос атаку на домен example.com потому что Nginx
будет пропускать все запросы к бекенду без кеширования, бекенд будет
генерить страницу для example.com, тратить свои ресурсы в расчете на то что
страница попадет в кеш Nginx, но этого не случится потому что Nginx выполнил
директивы из одного вирт хоста, но в бекенд передал другое значения Host и
проверка этого значения прошла на бекенде успешно что и требовалось хакерам
для Ддос атаки.

  Для каждого вирт хоста прописан proxy_cache_key
 $proxy_host$request_uri.
  
  Теперь делаем запрос
  GET http://apple-shop.com/ HTTP/1.1
  Host: samsung-shop.com
  
  В результате чего, ответ бекенда сохранится в кеше Nginx с ключом 
  samsung-shop.com/ но содержать внутри будет страницу
 apple-shop.com/. 
  На все последующие запросы samsung-shop.com будет отдаваться
 страница с
  товарами Apple, так как внутри кеш файла с ключом
 samsung-shop.com/ будет
  страница хоста apple-shop.com.
 
 Не будет, если только в обоих случаях не указано:

Т.е вы утверждаете, что значения переменой $proxy_host в данном запросе
будет = apple-shop.com, а не samsung-shop.com?
Сейчас проверить самостоятельно не могу, потому что везде у нас FastCGI.
Но если $proxy_host != $http_host, тогда я не вижу причин не сделать тоже
самое для FastCGI.


  1. В каком месте документации написано, что надо настраивать так, как
 было
 указано вами выше?

Вот ссылка на документацию.
http://nginx.org/ru/docs/http/ngx_http_proxy_module.html#proxy_cache_key
По умолчанию значение директивы близко к строке
proxy_cache_key $scheme$proxy_host$uri$is_args$args;

  2. Как вообще всё вышеописанное вами относится к обсуждаемой в данной
 подветке теме про http://habrahabr.ru/post/166855/ (которая вообще
 не относится к кэшу и директивам
 proxy_cache_key/fastcgi_cache_key,
 но уж так вышло, что была затронута)?

В данном примере, я пытался привести ситуацию где используется
proxy_cache_key (тема нашего треда) и так же запрос с absoluteURI чтобы
показать проблемы описаны в http://habrahabr.ru/post/166855/

В итого хочется сказать, что отсутствия в Nginx аналога UseCanonicalName On,
который есть в Apache, на руку только злоумышленникам, которые будут делать
запросы с absoluteURI и заголовком Host одновременно, в расчете на то что
Nginx выполнит директивы из одного вирт хоста, а бекенд будет выполнять
данный запрос в соответсвии с заголовком Host, который Nginx проигнорировал
в этом и заключается коллизия.

Posted at Nginx Forum: 
http://forum.nginx.org/read.php?21,246086,246274#msg-246274

___
nginx-ru mailing list
nginx-ru@nginx.org
http://mailman.nginx.org/mailman/listinfo/nginx-ru

Re: proxy cache key и fastcgi cache key

2014-01-10 Пенетрантность S.A.N
Хочу уточнить, я не предлагаю полную аналогию с UseCanonicalName, я имел
виду использовать значения переменной $host, при условии что host из
absoluteURI отличается от значения клиентского заголовка Host.

Posted at Nginx Forum: 
http://forum.nginx.org/read.php?21,246086,246275#msg-246275

___
nginx-ru mailing list
nginx-ru@nginx.org
http://mailman.nginx.org/mailman/listinfo/nginx-ru

Re: proxy cache key и fastcgi cache key

2014-01-09 Пенетрантность S.A.N
Gena Makhomed Wrote:
---
 возможно имеет смысл дефолтовые настройки сделать такими,
 чтобы они были безопасными по-умолчанию для всех пользователей?
 т.е. $host вместо $proxy_host ?

Поддержу данную мысль, это добавило бы безопасности дефолтного конфига
Nginx.
Вот наглядный пример:
fastcgi_param   HTTP_HOST1  $http_host;
fastcgi_param   HTTP_HOST2  $host;
fastcgi_param   HTTP_HOST3  $server_name;

Делаем, запрос
GET http://site3.dev/ HTTP/1.1
Host:~%#$^*()?@\!.'{}[]=+|

На выходе получим
_SERVER[HTTP_HOST1]: ~%#$^*()?@\!.'{}[]=+|
_SERVER[HTTP_HOST2]: site3.dev
_SERVER[HTTP_HOST3]: site2.dev

Кому интересно почитать, подробней вот ссылка.
http://habrahabr.ru/post/166855/

Как видите, корректное значения имеют только переменные $host и
$server_name, все что основывается на $http_host имеет потенциал уязвимость,
если бекенд доверяет этой переменой, лично я знаю несколько популярных РНР
фрейморков которые используют эту переменную без проверки и без
экранирования в SQL запросах.
 
Для вирт хостов $server_name нельзя использовать как HTTP_HOST, вот
переменную $host можно и считаю нужно использовать как HTTP_HOST.

Posted at Nginx Forum: 
http://forum.nginx.org/read.php?21,246086,246198#msg-246198

___
nginx-ru mailing list
nginx-ru@nginx.org
http://mailman.nginx.org/mailman/listinfo/nginx-ru