r1299 merge:
msie_refresh should escape at least '"' to prevent XSS
diff --git a/src/core/ngx_string.c b/src/core/ngx_string.c
index 032ae4d..29dc39f 100644
--- a/src/core/ngx_string.c
+++ b/src/core/ngx_string.c
@@ -1039,18 +1039,30 @@
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) {
diff --git a/src/core/ngx_string.h b/src/core/ngx_string.h
index 18306d2..6b432d1 100644
--- a/src/core/ngx_string.h
+++ b/src/core/ngx_string.h
@@ -142,6 +142,7 @@
#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
diff --git a/src/http/ngx_http_special_response.c b/src/http/ngx_http_special_response.c
index bb72079..2598116 100644
--- a/src/http/ngx_http_special_response.c
+++ b/src/http/ngx_http_special_response.c
@@ -315,6 +315,7 @@
{
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 @@
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 @@
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 @@
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);