假设我想在 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 的情况并非如此。
有什么办法可以解决这个问题吗?
我尝试过文档和谷歌,但没有成功。
谢谢。
更新
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;
}
}
}
尝试将“%”转义为“%25”
http://example.com/articles/foo%252fbar/view/
有关此问题的更多详细信息,请参阅 Nginx pass_proxy 子目录,无需 url 解码,如果您是
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
的最佳修复将取决于应用程序,并且可能是以下其中之一:
/../
这样的东西(包括所有转义的变体),这当然是为了保护你免受一整类漏洞的侵害。你的后端。QUERY_STRING
中的查询参数,以确保路径不会过早混合或解码。REQUEST_URI
获取原始请求 URI,无需进行任何标准化或解码。$uri
或 $document_uri
的所有实例,也可能使用 $fastcgi_path_info
,它们通常包含解码和标准化路径。$request_uri
放回到$uri
中。请注意,如果您选择此路线,您可能还需要手动删除查询字符串。顺便说一句,请注意,您首先所做的事情有点像玩火,因为如果您不完全了解自己在做什么,并且有一天有人决定这样做,那么很容易引入安全漏洞利用您依赖这些编码路径绕过 nginx 的正确处理和审查。
事实上,你想要做的事情在 Apache 中按原样工作更多的是一个错误而不是一个功能 - 这在 nginx 中的设计不同,目的是防止一整类安全漏洞。
我的 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 次。
此答案仅与问题标题相关。
如果你正在做
location / {
proxy_pass https://example.com/;
}
根据 to this thread,您需要将其更改为不包含尾随斜杠 - 显然,当您不使用尾随斜杠时,它会以不同的方式转发请求。
location / {
proxy_pass https://example.com;
}
如果您的“位置”不只是针对“/”,而是针对某些子目录,您可能会遇到其他其他问题,这些问题在此处进行了描述和回答。
如果使用 URL 查询参数,就不会有任何麻烦。 当您可以控制服务器路由时,您可以选择:
http://example.com/articles/view/?path=foo%2fbar
并且 nginx 不会接触 %2f