changeset 1298:458e041fc902

msie_refresh should escape at least '"' to prevent XSS
author Igor Sysoev <igor@sysoev.ru>
date Fri, 13 Jul 2007 09:37:01 +0000
parents 4ec0bc95172b
children 1476d32c66a7
files src/core/ngx_string.c src/core/ngx_string.h src/http/ngx_http_special_response.c
diffstat 3 files changed, 43 insertions(+), 16 deletions(-) [+]
line wrap: on
line diff
--- a/src/core/ngx_string.c
+++ b/src/core/ngx_string.c
@@ -1039,18 +1039,30 @@ ngx_escape_uri(u_char *dst, u_char *src,
         0xffffffff  /* 1111 1111 1111 1111  1111 1111 1111 1111 */
     };
 
+                    /* " ", """, "'", %00-%1F, %7F-%FF */
 
-    switch (type) {
-    case NGX_ESCAPE_HTML:
-        escape = html;
-        break;
-    case NGX_ESCAPE_ARGS:
-        escape = args;
-        break;
-    default:
-        escape = uri;
-        break;
-    }
+    static uint32_t   refresh[] = {
+        0xffffffff, /* 1111 1111 1111 1111  1111 1111 1111 1111 */
+
+                    /* ?>=< ;:98 7654 3210  /.-, +*)( '&%$ #"!  */
+        0x00000085, /* 0000 0000 0000 0000  0000 0000 1000 0101 */
+
+                    /* _^]\ [ZYX WVUT SRQP  ONML KJIH GFED CBA@ */
+        0x00000000, /* 0000 0000 0000 0000  0000 0000 0000 0000 */
+
+                    /*  ~}| {zyx wvut srqp  onml kjih gfed cba` */
+        0x80000000, /* 1000 0000 0000 0000  0000 0000 0000 0000 */
+
+        0xffffffff, /* 1111 1111 1111 1111  1111 1111 1111 1111 */
+        0xffffffff, /* 1111 1111 1111 1111  1111 1111 1111 1111 */
+        0xffffffff, /* 1111 1111 1111 1111  1111 1111 1111 1111 */
+        0xffffffff  /* 1111 1111 1111 1111  1111 1111 1111 1111 */
+    };
+
+    static uint32_t  *map[] = { uri, args, html, refresh };
+
+
+    escape = map[type];
 
     if (dst == NULL) {
 
--- a/src/core/ngx_string.h
+++ b/src/core/ngx_string.h
@@ -142,6 +142,7 @@ u_char *ngx_utf_cpystrn(u_char *dst, u_c
 #define NGX_ESCAPE_URI       0
 #define NGX_ESCAPE_ARGS      1
 #define NGX_ESCAPE_HTML      2
+#define NGX_ESCAPE_REFRESH   3
 
 #define NGX_UNESCAPE_URI     1
 
--- a/src/http/ngx_http_special_response.c
+++ b/src/http/ngx_http_special_response.c
@@ -315,6 +315,7 @@ ngx_http_special_response_handler(ngx_ht
 {
     u_char                    *p;
     size_t                     msie_refresh;
+    uintptr_t                  escape;
     ngx_int_t                  rc;
     ngx_buf_t                 *b;
     ngx_str_t                 *uri, *location;
@@ -496,17 +497,19 @@ ngx_http_special_response_handler(ngx_ht
         r->headers_out.content_length = NULL;
     }
 
-    msie_refresh = 0;
-    location = NULL;
-
     if (clcf->msie_refresh
         && r->headers_in.msie
         && (error == NGX_HTTP_MOVED_PERMANENTLY
             || error == NGX_HTTP_MOVED_TEMPORARILY))
     {
+
         location = &r->headers_out.location->value;
+
+        escape = 2 * ngx_escape_uri(NULL, location->data, location->len,
+                                    NGX_ESCAPE_REFRESH);
+
         msie_refresh = sizeof(ngx_http_msie_refresh_head) - 1
-                       + location->len
+                       + escape + location->len
                        + sizeof(ngx_http_msie_refresh_tail) - 1;
 
         r->err_status = NGX_HTTP_OK;
@@ -514,6 +517,11 @@ ngx_http_special_response_handler(ngx_ht
         r->headers_out.content_length_n = msie_refresh;
         r->headers_out.location->hash = 0;
         r->headers_out.location = NULL;
+
+    } else {
+        location = NULL;
+        escape = 0;
+        msie_refresh = 0;
     }
 
     ngx_http_clear_accept_ranges(r);
@@ -595,7 +603,13 @@ ngx_http_special_response_handler(ngx_ht
         p = ngx_cpymem(b->pos, ngx_http_msie_refresh_head,
                        sizeof(ngx_http_msie_refresh_head) - 1);
 
-        p = ngx_cpymem(p, location->data, location->len);
+        if (escape == 0) {
+            p = ngx_cpymem(p, location->data, location->len);
+
+        } else {
+            p = (u_char *) ngx_escape_uri(p, location->data, location->len,
+                                          NGX_ESCAPE_REFRESH);
+        }
 
         b->last = ngx_cpymem(p, ngx_http_msie_refresh_tail,
                              sizeof(ngx_http_msie_refresh_tail) - 1);