Opened 11 days ago

Closed 11 days ago

#1930 closed defect (invalid)

Space in URL %20 is decoded space causing an invalid URL

Reported by: cawoodm@… Owned by:
Priority: minor Milestone:
Component: documentation Version: 1.17.x
Keywords: Cc:
uname -a: Windows 10 64-bit
nginx -V: nginx version: nginx/1.17.8
built by cl 16.00.40219.01 for 80x86
built with OpenSSL 1.1.1d 10 Sep 2019
TLS SNI support enabled
configure arguments: --with-cc=cl --builddir=objs.msvc8 --with-debug --prefix= --conf-path=conf/nginx.conf --pid-path=logs/nginx.pid --http-log-path=logs/access.log --error-log-path=logs/error.log --sbin-path=nginx.exe --http-client-body-temp-path=temp/client_body_temp --http-proxy-temp-path=temp/proxy_temp --http-fastcgi-temp-path=temp/fastcgi_temp --http-scgi-temp-path=temp/scgi_temp --http-uwsgi-temp-path=temp/uwsgi_temp --with-cc-opt=-DFD_SETSIZE=1024 --with-pcre=objs.msvc8/lib/pcre-8.43 --with-zlib=objs.msvc8/lib/zlib-1.2.11 --with-http_v2_module --with-http_realip_module --with-http_addition_module --with-http_sub_module --with-http_dav_module --with-http_stub_status_module --with-http_flv_module --with-http_mp4_module --with-http_gunzip_module --with-http_gzip_static_module --with-http_auth_request_module --with-http_random_index_module --with-http_secure_link_module --with-http_slice_module --with-mail --with-stream --with-openssl=objs.msvc8/lib/openssl-1.1.1d --with-openssl-opt='no-asm no-tests -D_WIN32_WINNT=0x0501' --with-http_ssl_module --with-mail_ssl_module --with-stream_ssl_module

Description

We are seeing nginx 1.15 and the latest 1.17.8 wrongly decoding %20 to " " (space) in URLs before forwarding them upstream. Some upstreams do not accept this and cause a 400. Nginx should not IMHO be unencoding URLs!

Consider the following Nginx running on 8080 with fiddler running as the upstream server on port 8888 to view traffic:

location ~ "^/yo/(.*)" {
  proxy_pass http://127.0.0.1:8888/$1$is_args$args;
}

Next we hit NginX with:

GET http://localhost:8080/yo/foo%20bar

Fiddler (upstream) shows the incoming request as:

GET /foo bar

Correct would be

GET /foo%20bar

The following workaround is available:

location ~ "^/yo/(.*)" {
  set $allowspace1 $1;
  proxy_pass http://127.0.0.1:8888/$allowspace1$is_args$args;

Change History (1)

comment:1 by Maxim Dounin, 11 days ago

Resolution: invalid
Status: newclosed

In your configuration snippet:

location ~ "^/yo/(.*)" {
  proxy_pass http://127.0.0.1:8888/$1$is_args$args;
}

you are using $1$is_args$args, where $1 comes from unescaped URI as matched by the location. Given that proxy_pass expects properly escaped URI and uses it as is, this results in arbitrary invalid requests being generated.

If you are not prepared to deal with it and do not want to correctly escape all the variables used, consider using proxy_pass without variables instead. The same configuration can be correctly rewritten as:

location /yo/ {
    proxy_pass http://127.0.0.1:8888/;
}

Note the trailing / in proxy_pass. Alternatively, you can use proxy_pass without a URI and rewrite, though in this particular case using proxy_pass with a URI is much cleaner solution. See proxy_pass docs for additional examples.

(Note well that the "workaround" you've mentioned is rather a bug, see #348.)

Note: See TracTickets for help on using tickets.