【问题标题】:NGINX unescapes %2f to a forward slash. How can I stop it?NGINX 将 %2f 转义为正斜杠。我怎样才能阻止它?
【发布时间】:2020-01-22 19:18:59
【问题描述】:

假设我想在 URL 中编码一个包含斜杠的文章标题。如果我对文章标题进行 URL 编码,我会得到:

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

NGINX 将其传递给我的 FastCGI 应用程序:

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

这反而破坏了这个想法。

我注意到,如果 NGINX 正在提供一个文件,比如 /path/to/page.html,那么可以通过以下两个 URL 之一访问它:

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

但是(例如)Apache 并非如此。

有没有办法解决这个问题?

我已经尝试过文档和 Google,但没有成功。

谢谢。

更新

nginx 配置:

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;
        }
    }

}

【问题讨论】:

标签: url escaping nginx


【解决方案1】:

尝试将“%”转义为“%25”

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

【讨论】:

  • 不错的主意 (+1),尽管感觉像是在尝试修复错误的位。 (改变我的转义/取消转义而不是改变 nginx 的行为)
  • 好吧,您可以实现这个相当简单的更改,也可以着手尝试更改核心代码。看看潮流如何流动并与之合作或尝试改变潮流。一切都是关于选择。
  • 这是个坏主意:这意味着您在代码中引入了一个错误——双重转义——以解决其他问题中的错误。这是错误的方向。
  • 这不是一个错误,它是一个 hack,但几乎可以保证在某些时候有人会编写的其他代码中导致错误。您不能封装对公共 Web 界面的所有访问。但!这显然是最好的解决方案,所以你值得一试,显然你没有得到。 @DaedalusFall 感到羞耻。
【解决方案2】:

Nginx pass_proxy subdirectory without url decoding 提供了有关此问题的更多详细信息,如果您是 proxy_pass 用户,它会提供完整的解决方案。

使用 fastcgi_pass,这可能是由于 nginx 中的默认 conf/fastcgi.conf,其中 DOCUMENT_URI 变量设置为 http://nginx.org/r/$document_uri,即相当于http://nginx.org/r/$uri,而后者又是http://nginx.org/r/$request_uri 的规范化(解码和未转义)、无查询和可能重写的版本(反过来,可以通过REQUEST_URI 访问):

  fastcgi_param  REQUEST_URI        $request_uri;
  fastcgi_param  DOCUMENT_URI       $document_uri;

但是,在您的情况下,您实际上似乎根本没有指定DOCUMENT_URI,因为如果在当前级别使用http://nginx.org/r/fastcgi_param,则不会从先前级别继承,因此,解码路径可能来自在您的http://nginx.org/r/$fastcgi_path_info 之外,它应该与您从提供的配置中省略的http://nginx.org/r/fastcgi_split_path_info 配对,因此,原始问题可能看起来不一致,因为提供的请求和示例配置之间的确切路径不也不匹配。

无论如何,fastcgi 的最佳修复将取决于应用程序,并且可能是以下之一:

  • 不依赖于未被 nginx 正确解码和清理的路径。这可能是安全方面最好的解决方法,因为您基本上是在要求 nginx 不清理像 /../ 这样的东西(包括所有转义的变体),这当然是为了保护您免受你的后端。
  • 重新设计整个界面以使用QUERY_STRING 中的查询参数,以确保路径不会混合或过早解码。
  • 使用 REQUEST_URI 获取原始请求 URI,无需进行任何规范化或解码。
  • 密切注意使用$uri$document_uri 的所有实例,可能还有$fastcgi_path_info,它们通常包含解码和规范化的路径。
  • 使用linked answer 中概述的重写技巧将未解码的$request_uri 放回$uri。请注意,如果您走这条路,您可能还必须手动删除查询字符串。

顺便说一句,请注意,您所做的首先是在玩火,因为如果您不完全了解自己在做什么,并且如果有一天有人这样做,那么很容易引入安全漏洞决定利用您依赖这些编码路径绕过对 nginx 的正确处理和审查。

事实上,您想要在 Apache 中按原样工作的事实与其说是一项功能,不如说是一个错误 — 这在 nginx 中的工作方式在设计上有所不同,并且是为了防止一整类安全漏洞。

【讨论】:

    【解决方案3】:

    如果您使用 URL 查询参数,您不会有任何问题。 当您可以控制您的服务器路由时,您可以选择:

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

    而且 nginx 不会接触 %2f

    【讨论】:

      【解决方案4】:

      我的 nginx + uWSGI + flask 堆栈也有同样的问题。 我通过在 nginx 配置中引入重写规则来解决它:

      location @app {
          rewrite ./ $request_uri break;
          include uwsgi_params;
          uwsgi_pass unix:/tmp/uwsgi.sock;
      }
      

      更新:这似乎破坏了查询参数,所以我不得不这样做:

      location @app {
          set $plain_uri $request_uri ;
          if ( $plain_uri ~ (.*)\?.* ) {
              set $plain_uri $1 ;
          }
          rewrite .* $plain_uri break;
          include uwsgi_params;
          uwsgi_pass unix:/tmp/uwsgi.sock;
      }
      

      这个问题是原来编码的 URL 又被编码了,所以我总共需要取消编码 4 次。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2014-09-08
        • 1970-01-01
        • 2015-01-27
        • 1970-01-01
        • 1970-01-01
        • 2023-04-10
        • 2021-06-21
        • 2019-09-02
        相关资源
        最近更新 更多