NGINX unescapes %2f to a forward slash. How can I stop it?

11,080

Solution 1

More details on this issue are provided over at Nginx pass_proxy subdirectory without url decoding, which has a full solution if you're a proxy_pass user.

With fastcgi_pass, this could happen due to the default conf/fastcgi.conf in nginx, where the DOCUMENT_URI variable is set to http://nginx.org/r/$document_uri, which is equivalent to just http://nginx.org/r/$uri, which, in turn, is the normalised (decoded and unescaped), query-less and potentially rewritten version of http://nginx.org/r/$request_uri (which, in turn, could be accessed through REQUEST_URI instead):

  fastcgi_param  REQUEST_URI        $request_uri;
  fastcgi_param  DOCUMENT_URI       $document_uri;

In your case, however, you don't actually seem to specify DOCUMENT_URI at all, since http://nginx.org/r/fastcgi_param is not inherited from a prior level if used at the current level, so, it's possible that the decoded path comes out of your http://nginx.org/r/$fastcgi_path_info, which is supposed to be paired with http://nginx.org/r/fastcgi_split_path_info, which you omit from the provided configuration, so, the original question may appear to be inconsistent, as the exact paths between the provided requests and the sample configuration don't match, either.

Regardless, the best fix with fastcgi would depend on the application, and may be one of the following:

  • Not depend on paths not being decoded and cleaned up properly by nginx. This is probably the best fix security-wise, as you're basically asking nginx to not clean up stuff like /../, either (including all the escaped variations), which is certainly intended to protect you against a whole class of vulnerabilities in your backend.
  • Redesign the whole interface to use the query parameters within QUERY_STRING to ensure paths aren't mingled or decoded prematurely.
  • Use REQUEST_URI to get the original request URI without any normalisation or decoding taking place.
  • Pay closer attention to all instances of using $uri or $document_uri, and possibly $fastcgi_path_info as well, which would usually contain the decoded and normalised paths.
  • Use the rewrite tricks as outlined in the linked answer to place undecoded $request_uri back into $uri. Note that you also might have to strip out the query string manually if you go this route.

BTW, note that what you're doing in the first place is kind of playing with fire, because it's very easy to introduce security vulnerabilities if you don't fully understand what you're doing, and if someone one day does decide to take advantage of you relying on these encoded paths bypassing proper handling and scrutiny of nginx.

The fact that what you want to do works in Apache as-is is more of a bug than a feature — this works differently in nginx by design and in order to prevent a whole class of security vulnerabilities.

Solution 2

Try escaping "%" as "%25"

http://example.com/articles/foo%252fbar/view/
Share:
11,080
DaedalusFall
Author by

DaedalusFall

Coder seeks work, caffeine.

Updated on July 29, 2022

Comments

  • DaedalusFall
    DaedalusFall over 1 year

    Say I want to encode an article title in a URL and that contains a slash. If I URL encode the article title I get:

    http://example.com/articles/foo%2fbar/view/
    

    NGINX passes this to my FastCGI application as:

    http://example.com/articles/foo/bar/view/
    

    Which rather ruins the idea.

    I notice that if NGINX is serving a file, say /path/to/page.html, then it can be reached by either of the following two URLs:

    http://example.com/path/to/page.html
    http://example.com/path/to%2fpage.html
    

    However this is not the case for (for example) Apache.

    Is there any way to fix this behavior?

    I've tried the docs and Google with no luck.

    Thanks.

    UPDATE

    nginx config:

    worker_processes  1;
    pid ./nginx.pid;
    events {
        worker_connections  1024;
    }
    http {
        server_tokens off;
        server {
            listen 80;
            server_name localhost;
            location /mysite/{
                fastcgi_pass   unix: ./mysite.fcgi.socket;
    
                fastcgi_param SERVER_NAME $server_name;
                fastcgi_param SERVER_PORT $server_port;
                fastcgi_param SERVER_PROTOCOL $server_protocol;
                fastcgi_param SCRIPT_NAME "/mysite/";
                fastcgi_param PATH_INFO $fastcgi_path_info;
                fastcgi_param REQUEST_METHOD $request_method;
                fastcgi_param QUERY_STRING $query_string;
                fastcgi_param CONTENT_TYPE $content_type;
                fastcgi_param CONTENT_LENGTH $content_length;
                fastcgi_pass_header Authorization;
                fastcgi_intercept_errors off;
            }
        }
    
    }
    
  • DaedalusFall
    DaedalusFall over 12 years
    Not a bad idea (+1), though it feels like trying to fix the wrong bit. (Changing my escaping/unescaping rather than changing nginx's behaviour)
  • Dayo
    Dayo over 12 years
    Well, you can either implement this fairly straightforward change or set about trying to change the core code. Look at how the tide flows and work with it or try to change the tide. It is all about choices.
  • DaedalusFall
    DaedalusFall over 12 years
    :-) I was rather hoping that it would be a simple configuration file change. As it turns out I found that passing $uri for PATH_INFO works, but you have to strip stuff off the end in code, so this also seems like the wrong thing to fix. But like you say, tides... had I not already found $uri i'd probably implement your %252f idea.
  • Glenn Maynard
    Glenn Maynard almost 12 years
    This is a bad idea: it means you're introducing a bug in your code--double-escaping--in order to work around a bug in something else. That's going in the wrong direction.
  • Dayo
    Dayo almost 12 years
    Can't fathom how you can call double escaping a "bug". Anyway, it is alright to down vote and brand this as going in the wrong direction, the direction the author of Nginx himself recommends in such situations ... but I don't see any alternative solutions from you that you recommend the OP, or anyone else with this issue, implement to solve the issue while moving them in the "right direction".
  • mxcl
    mxcl over 10 years
    It's not a bug, it's a hack, but it's almost guaranteed to cause bugs in other code someone will write at some point. You can't encapsulate all access to a public web interface. But! It's apparently the best solution so you deserve a tick, which apparently you didn't get. Shame on @DaedalusFall.
  • GuiGS
    GuiGS over 10 years
    '%252f' don't work for me. It seems that nginx doesn't decode %25 as it does with %2f. So my application receives '%252f' and since it decodes once I end up getting '%2f' string.
  • koppor
    koppor almost 7 years