#786 closed defect (wontfix)
url decoding is senseless for proxy_pass
Reported by: | Owned by: | ||
---|---|---|---|
Priority: | minor | Milestone: | |
Component: | nginx-core | Version: | 1.8.x |
Keywords: | proxy_pass, url decoding | Cc: | |
uname -a: | FreeBSD Infra 9.3-RELEASE-p25 FreeBSD 9.3-RELEASE-p25 #0 r281084+d3a5bf7: Wed Sep 2 15:00:10 PDT 2015 root@build3.ixsystems.com:/tank/home/jkh/build/FN/objs/os-base/amd64/tank/home/jkh/build/FN/FreeBSD/src/sys/FREENAS.amd64 amd64 | ||
nginx -V: |
nginx version: nginx/1.8.0
built with OpenSSL 0.9.8za-freebsd 5 Jun 2014 TLS SNI support enabled configure arguments: --prefix=/usr/local/etc/nginx --with-cc-opt='-I /usr/local/include' --with-ld-opt='-L /usr/local/lib' --conf-path=/usr/local/etc/nginx/nginx.conf --sbin-path=/usr/local/sbin/nginx --pid-path=/var/run/nginx.pid --error-log-path=/var/log/nginx-error.log --user=www --group=www --with-file-aio --http-client-body-temp-path=/var/tmp/nginx/client_body_temp --http-fastcgi-temp-path=/var/tmp/nginx/fastcgi_temp --http-proxy-temp-path=/var/tmp/nginx/proxy_temp --http-scgi-temp-path=/var/tmp/nginx/scgi_temp --http-uwsgi-temp-path=/var/tmp/nginx/uwsgi_temp --http-log-path=/var/log/nginx-access.log --with-http_gzip_static_module --with-http_gunzip_module --with-http_stub_status_module --with-pcre --with-http_ssl_module |
Description
I understand that URLs such as http://server/some%2Fpath is translated to http://server/some/path for security reasons. NginX is responsible for protecting NginX resources.
When configuring a stop-search URI for reverse proxy access, like
location ^~ /publicAppName/ { proxy_pass http://internal.local/; #trailing / to drop /publicAppName/ proxy_redirect default; }
then flow is locked onto target -- it will go to the internal.local server. Whatever application is running there is not NginX' responsibility. Dropping the trailing slash in proxy_pass URL forwards the URI part as-is, which is fine, it is upp to internal.local server to deal with any issues.
It does not make sense not to forward as-is the remaining URI (without /publicAppName/) when there is a trailing slash in proxy_pass URL.
Today, url decoding is enforced in this situation, possibly to "protect" internal.local server. Problem is if internal.local is running an application that is dependant on encoded urls provided by 3rd party tools (e.g. sinopia and npm), then there is no way to front this with an application prefix using NginX. Internal.local does not need protection, dropping one shoe for this is for the better.
Change History (6)
comment:1 by , 9 years ago
comment:2 by , 9 years ago
And for anybody passing by, I have found two workarounds for the sinopia+npm usecase that may be helpful;
- Specifying every possibility;
location ^~ /sinopia/@scopea/ { proxy_pass http://sinopia.local:4873/@scopea%2F; proxy_redirect default; } location ^~ /sinopia/-/readme/@scopea/ { proxy_pass http://sinopia.local:4873/-/readme/@scopea%2F; proxy_redirect default; } location ^~ /sinopia/@scopeb/ { proxy_pass http://sinopia.local:4873/@scopeb%2F; proxy_redirect default; } location ^~ /sinopia/-/readme/@scopeb/ { proxy_pass http://sinopia.local:4873/-/readme/@scopeb%2F; proxy_redirect default; } ... ... repeat for every scopea, scopeb, ... ... location ^~ /sinopia/ { proxy_pass http://sinopia.local:4873/; proxy_redirect default; }
- Using variables, requiring resolver and disabling default proxy_redirect;
location ^~ /sinopia(.*)@(.*)/(.*) { resolver 192.168.3.1; proxy_pass http://sinopia.local:4873$1@$2%2F$3; proxy_redirect http://sinopia.local:4873/ /sinopia/ } location ^~ /sinopia/ { proxy_pass http://sinopia.local:4873/; proxy_redirect default; }
Neither is pretty but keeps the show going.
comment:3 by , 9 years ago
Resolution: | → wontfix |
---|---|
Status: | new → closed |
When nginx is instructed to modify URI by using an URI component in proxy_pass
to remove a location prefix, it will decode URI, remove matching location prefix, and encode modified URI. Decoding only a part of URI is hardly possible and not supported.
If you want to preserve URI exactly as it was sent by a client, use proxy_pass
without an URI compontent, that is:
proxy_pass http://backend;
If you really want to modify an URI and at the same time preserve some particular parts of URI exactly as they were sent by a client, you can use proxy_pass
with variables derived from the $request_uri
variable. That is, something like this can be used assuming all valid requests always start with "/foo/" unescaped:
location /foo/ { set $modified_uri "/some/invalid/uri"; if ($request_uri ~ ^/foo/(.*)$) { set $modified_uri $1; } proxy_pass http://backend$modified_uri; }
Note though that such approach is limited and won't work in some edge cases. E.g., it won't allow to properly handle internal redirects in nginx config, as well as various cases when some characters in the "/foo/" prefix are escaped.
comment:5 by , 7 years ago
For people who find this sooner than stack overflow: this solution seems best:
location /api/ { rewrite ^ $request_uri; rewrite ^/api/(.*) $1 break; return 400; proxy_pass http://127.0.0.1:82/$uri; }
See https://stackoverflow.com/questions/28684300/nginx-pass-proxy-subdirectory-without-url-decoding/37584637#37584637 for original author and details.
I'd be happy to provide working patch if there is a good chance of it reaching trunk in near time.