[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