[nginx] Teach ngx_http_parse_unsafe_uri() how to unescape URIs.

Ruslan Ermilov ru at nginx.com
Mon Dec 23 14:12:44 UTC 2013


details:   http://hg.nginx.org/nginx/rev/74bfa803a5aa
branches:  
changeset: 5491:74bfa803a5aa
user:      Ruslan Ermilov <ru at nginx.com>
date:      Mon Dec 23 18:12:00 2013 +0400
description:
Teach ngx_http_parse_unsafe_uri() how to unescape URIs.

This fixes handling of escaped URIs in X-Accel-Redirect (ticket #316),
SSI (ticket #240), and DAV.

diffstat:

 src/http/modules/ngx_http_ssi_filter_module.c |  14 ------
 src/http/ngx_http_parse.c                     |  63 +++++++++++++++++++++++++-
 2 files changed, 60 insertions(+), 17 deletions(-)

diffs (128 lines):

diff -r b141a7627ac6 -r 74bfa803a5aa src/http/modules/ngx_http_ssi_filter_module.c
--- a/src/http/modules/ngx_http_ssi_filter_module.c	Mon Dec 23 18:11:56 2013 +0400
+++ b/src/http/modules/ngx_http_ssi_filter_module.c	Mon Dec 23 18:12:00 2013 +0400
@@ -1982,8 +1982,6 @@ static ngx_int_t
 ngx_http_ssi_include(ngx_http_request_t *r, ngx_http_ssi_ctx_t *ctx,
     ngx_str_t **params)
 {
-    u_char                      *dst, *src;
-    size_t                       len;
     ngx_int_t                    rc, key;
     ngx_str_t                   *uri, *file, *wait, *set, *stub, args;
     ngx_buf_t                   *b;
@@ -2054,18 +2052,6 @@ ngx_http_ssi_include(ngx_http_request_t 
         return rc;
     }
 
-    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;
-
     ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                    "ssi include: \"%V\"", uri);
 
diff -r b141a7627ac6 -r 74bfa803a5aa src/http/ngx_http_parse.c
--- a/src/http/ngx_http_parse.c	Mon Dec 23 18:11:56 2013 +0400
+++ b/src/http/ngx_http_parse.c	Mon Dec 23 18:12:00 2013 +0400
@@ -1780,11 +1780,13 @@ ngx_int_t
 ngx_http_parse_unsafe_uri(ngx_http_request_t *r, ngx_str_t *uri,
     ngx_str_t *args, ngx_uint_t *flags)
 {
-    u_char  ch, *p;
-    size_t  len;
+    u_char      ch, *p, *src, *dst;
+    size_t      len;
+    ngx_uint_t  quoted;
 
     len = uri->len;
     p = uri->data;
+    quoted = 0;
 
     if (len == 0 || p[0] == '?') {
         goto unsafe;
@@ -1800,6 +1802,11 @@ ngx_http_parse_unsafe_uri(ngx_http_reque
 
         ch = *p++;
 
+        if (ch == '%') {
+            quoted = 1;
+            continue;
+        }
+
         if (usual[ch >> 5] & (1 << (ch & 0x1f))) {
             continue;
         }
@@ -1809,7 +1816,7 @@ ngx_http_parse_unsafe_uri(ngx_http_reque
             args->data = p;
             uri->len -= len;
 
-            return NGX_OK;
+            break;
         }
 
         if (ch == '\0') {
@@ -1828,6 +1835,56 @@ ngx_http_parse_unsafe_uri(ngx_http_reque
         }
     }
 
+    if (quoted) {
+        ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+                       "escaped URI: \"%V\"", uri);
+
+        src = uri->data;
+
+        dst = ngx_pnalloc(r->pool, uri->len);
+        if (dst == NULL) {
+            return NGX_ERROR;
+        }
+
+        uri->data = dst;
+
+        ngx_unescape_uri(&dst, &src, uri->len, 0);
+
+        uri->len = dst - uri->data;
+
+        ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+                       "unescaped URI: \"%V\"", uri);
+
+        len = uri->len;
+        p = uri->data;
+
+        if (p[0] == '.' && len > 1 && p[1] == '.'
+            && (len == 2 || ngx_path_separator(p[2])))
+        {
+            goto unsafe;
+        }
+
+        for ( /* void */ ; len; len--) {
+
+            ch = *p++;
+
+            if (ch == '\0') {
+                goto unsafe;
+            }
+
+            if (ngx_path_separator(ch) && len > 2) {
+
+                /* detect "/../" and "/.." */
+
+                if (p[0] == '.' && p[1] == '.'
+                    && (len == 3 || ngx_path_separator(p[2])))
+                {
+                    goto unsafe;
+                }
+            }
+        }
+    }
+
     return NGX_OK;
 
 unsafe:



More information about the nginx-devel mailing list