Nginx、PATH_INFO 和 url-rewriting:我肯定漏掉了什么

Nginx、PATH_INFO 和 url-rewriting:我肯定漏掉了什么

我正在从 Apache 切换到 Nginx/fcgi,在尝试设置应用程序重写规则时遇到了一个小问题。

代码通过使用 PATH_INFO 来处理路由,例如 example.com/foo/bar/ 将被路由到 example.com/index.php/foo/bar/

我已经修改了服务器配置以传递PATH_INFO:

location ~ \.php$ {
      include /etc/nginx/fastcgi_params;
      fastcgi_pass   127.0.0.1:9000;
      fastcgi_index  index.php;

      fastcgi_split_path_info ^(.+\.php)(.*)$;
      fastcgi_param SCRIPT_FILENAME  /var/www/public$fastcgi_script_name;
      fastcgi_param PATH_INFO $fastcgi_path_info;
      fastcgi_param PATH_TRANSLATED $document_root$fastcgi_path_info;
}

重写处理程序:

location / {
      root   /var/www/public;
      index  index.html index.htm index.php;

      if (!-f $request_filename) {
        rewrite ^(.*)/(.*)$ /index.php/$2 break;
      }
    }

和 '重写登录',该 URL 似乎路由正确:

[error]: *2 open() "/var/www/public/index.php/test" failed (20: Not a directory), client: 192.168.0.254, server: example.com, request: "GET /test HTTP/1.1", host: "example.com", referrer: "http://example.com/index.php"

然而,它似乎正在寻找目录“test”。我如何强制它请求index.php,并将'/test'传递给脚本?

答案1

看起来您正在遵循一个非常过时的糟糕教程(if (!-f 通常不推荐,有try_files更好的替代品)。您遇到了许多问题:

第一的您在location /上下文中有指令,这些指令应该在server上下文中,这样您就可以避免SCRIPT_FILENAME变量中的路径重复。

第二,您在重写中使用该break标志;这意味着它不应重新评估位置匹配。这实际上使请求永远不会离开块location /,而是被视为静态文件请求。

第三,看看你的location ~ \.php$ {:Nginx 根据 URI 匹配位置,并且你明确告诉 Nginx 只处理以 结尾的 URI .php,但如果你重写为,index.php/test/那么它就不会触发。

最后,而您使用的是 ,PATH_INFO而您应该使用REQUEST_URI。区别在于,要使 PATH_INFO 工作,您必须告诉 Nginx 将任何带有 的请求传递.php给 PHP,然后 PHP 必须找到正确的文件。

这意味着您允许example.org/uploads/image.jpg/index.php向 PHP 发送类似这样的请求,并且还允许 PHP 执行文件/uploads/image.jpg。如果恶意用户上传了包含 PHP 的文件,他们现在就可以在您的服务器上执行任意代码。这是一个非常真实的漏洞我亲眼见过人们对此十分敏感。

请不要使用随机在 Google 上搜索的教程,因为其中 90% 都是垃圾,而是去阅读维基百科。真正了解您正在使用的网络服务器可能会很麻烦,但另一种情况是您的服务器受到攻击。

相关内容