ПРОЕКТЫ 


  АРХИВ 


Apache-Talk @lexa.ru 

Inet-Admins @info.east.ru 

Filmscanners @halftone.co.uk 

Security-alerts @yandex-team.ru 

nginx-ru @sysoev.ru 


  СТАТЬИ 


  ПЕРСОНАЛЬНОЕ 


  ПРОГРАММЫ 



ПИШИТЕ
ПИСЬМА












     АРХИВ :: nginx-ru
Nginx-ru mailing list archive (nginx-ru@sysoev.ru)

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: X-Accel-Redirect и uri escape



Hello,

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

Поэтому предлагаю новую опцию safe_redirect on/off.
Если установлена в "on" в http, server или location, откуда
идет proxy_pass, путь в X-Accel-Redirect воспринимает
как escaped uri. По дефолту стоит в off и поведение
парсера не меняет.

On 11/25/13 15:55, Maxim Dounin wrote:
Hello!

On Mon, Nov 25, 2013 at 05:00:31AM +0300, Роман Шишнев wrote:

Hello,

Обнаружил несколько странное поведение nginx при обработке
X-Accel-Redirect от upstream:

При появлении знака "?" в имени файла в заголовке, uri обрезается до
этого знака, а все остальное складывается в аргументы. Попробовал
этот знак заменить на %3F, все стало ещё интереснее - в uri заменяются
на стороне nginx все символы "%" на "%25", в итоге выходит что-то вроде
"%253F" при передаче на следующий upstream.

Полагаю, если в имени файла встретится последовательность "\r\n", этот
файл вообще нельзя будет отправить в nginx с помощью X-Accel-Redirect.
В явном виде эта последовательность закончит uri в заголовке на себе,
а остаток имени будет следующим зоголовком, а в виде %0D%0A будет
превращена в %250D%250A.

В первом случае файл "aaa\r\nRefresh: 0;url=login" отправит клиента
по другому адресу, а во втором случае комбинацию никакой upstream не
разберет.

Вопрос как сейчас передавать в nginx с помощью X-Accel-Redirect
файлы в имени которых есть спец-символы?

Может стоит сделать отдельную опцию (что-нибудь в духе
safe_redirect on/off) при включении которой nginx не будет
дополнительно escape'ать uri в X-Accel-Redirect?

Сейчас nginx полагает, что в X-Accel-Redirect передаётся
незакодированный URI.  Есть мнение, что это неправильно (в
частности потому, что файл с "?" в имени отправить нельзя), и
надо изменить логику так, чтобы передавался закодированный URI.

Где-то тут про это есть чуть больше подробностей, а также ссылки
на предыдущие попытки решить проблему:

http://trac.nginx.org/nginx/ticket/316

diff -Nru a/src/http/ngx_http_core_module.c b/src/http/ngx_http_core_module.c
--- a/src/http/ngx_http_core_module.c   2013-11-19 15:25:25.000000000 +0400
+++ b/src/http/ngx_http_core_module.c   2013-11-25 18:49:09.253001176 +0400
@@ -746,6 +746,13 @@
       offsetof(ngx_http_core_loc_conf_t, resolver_timeout),
       NULL },
 
+    { ngx_string("safe_redirect"),
+      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
+      ngx_conf_set_flag_slot,
+      NGX_HTTP_LOC_CONF_OFFSET,
+      offsetof(ngx_http_core_loc_conf_t, safe_redirect),
+      NULL },
+
 #if (NGX_HTTP_GZIP)
 
     { ngx_string("gzip_vary"),
@@ -3622,6 +3629,7 @@
     clcf->server_tokens = NGX_CONF_UNSET;
     clcf->chunked_transfer_encoding = NGX_CONF_UNSET;
     clcf->etag = NGX_CONF_UNSET;
+    clcf->safe_redirect = NGX_CONF_UNSET;
     clcf->types_hash_max_size = NGX_CONF_UNSET_UINT;
     clcf->types_hash_bucket_size = NGX_CONF_UNSET_UINT;
 
@@ -3884,6 +3892,7 @@
     ngx_conf_merge_value(conf->chunked_transfer_encoding,
                               prev->chunked_transfer_encoding, 1);
     ngx_conf_merge_value(conf->etag, prev->etag, 1);
+    ngx_conf_merge_value(conf->safe_redirect, prev->safe_redirect, 0);
 
     ngx_conf_merge_ptr_value(conf->open_file_cache,
                               prev->open_file_cache, NULL);
diff -Nru a/src/http/ngx_http_core_module.h b/src/http/ngx_http_core_module.h
--- a/src/http/ngx_http_core_module.h   2013-11-19 15:25:25.000000000 +0400
+++ b/src/http/ngx_http_core_module.h   2013-11-25 18:42:39.634003407 +0400
@@ -407,6 +407,7 @@
     ngx_flag_t    server_tokens;           /* server_tokens */
     ngx_flag_t    chunked_transfer_encoding; /* chunked_transfer_encoding */
     ngx_flag_t    etag;                    /* etag */
+    ngx_flag_t    safe_redirect;           /* safe_redirect */
 
 #if (NGX_HTTP_GZIP)
     ngx_flag_t    gzip_vary;               /* gzip_vary */
diff -Nru a/src/http/ngx_http_upstream.c b/src/http/ngx_http_upstream.c
--- a/src/http/ngx_http_upstream.c      2013-11-19 15:25:25.000000000 +0400
+++ b/src/http/ngx_http_upstream.c      2013-11-25 20:19:44.019000094 +0400
@@ -1893,14 +1893,18 @@
 static ngx_int_t
 ngx_http_upstream_process_headers(ngx_http_request_t *r, ngx_http_upstream_t 
*u)
 {
+    u_char                         *dst, *src;
+    size_t                          len;
     ngx_str_t                      *uri, args;
     ngx_uint_t                      i, flags;
     ngx_list_part_t                *part;
     ngx_table_elt_t                *h;
     ngx_http_upstream_header_t     *hh;
     ngx_http_upstream_main_conf_t  *umcf;
+    ngx_http_core_loc_conf_t       *clcf;
 
     umcf = ngx_http_get_module_main_conf(r, ngx_http_upstream_module);
+    clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
 
     if (u->headers_in.x_accel_redirect
         && !(u->conf->ignore_headers & NGX_HTTP_UPSTREAM_IGN_XA_REDIRECT))
@@ -1938,9 +1942,27 @@
         ngx_str_null(&args);
         flags = NGX_HTTP_LOG_UNSAFE;
 
-        if (ngx_http_parse_unsafe_uri(r, uri, &args, &flags) != NGX_OK) {
-            ngx_http_finalize_request(r, NGX_HTTP_NOT_FOUND);
-            return NGX_DONE;
+        if (clcf->safe_redirect) {
+
+            dst = uri->data;
+            src = uri->data;
+
+            ngx_unescape_uri(&dst, &src, uri->len, NGX_UNESCAPE_URI);
+
+            len = (uri->data + uri->len) - src;
+            if (len) {
+                dst = ngx_movemem(dst, src, len);
+            }
+
+            uri->len = dst - uri->data;
+
+        } else {
+
+            if (ngx_http_parse_unsafe_uri(r, uri, &args, &flags) != NGX_OK) {
+                ngx_http_finalize_request(r, NGX_HTTP_NOT_FOUND);
+                return NGX_DONE;
+            }
+
         }
 
         if (r->method != NGX_HTTP_HEAD) {
_______________________________________________
nginx-ru mailing list
nginx-ru@xxxxxxxxx
http://mailman.nginx.org/mailman/listinfo/nginx-ru


 




Copyright © Lexa Software, 1996-2009.