工作 NginX 配置

工作 NginX 配置

我花了好几个小时才弄清楚如何正确配置NginX,但我仍然认为我可能错过了一些东西。主要是因为这个完美工作的设置引发的问题比它解答的问题还多。也许这甚至是一个-bug 或中NginX引入的东西,我根本不知道。DebianVersion: 1.2.1-2.2+wheezy2Package: nginx-extras

请注意,我的示例已被精简到最低限度(因此以此为起点),但它仍然包含所有必要的当前安全修复。

请注意,我不喜欢容易出错的启发式方法。因此,这将使用/etc/php/fpm/pool.d/www.conf如下设置运行,它php-fpm直接从中获取脚本,PATH_TRANSLATED而不是猜测它:

php_admin_value[cgi.fix_pathinfo]=0
security.limit_extensions = .php
php_admin_flag[expose_php] = off

这是转储变量的php文件:/home/tino/www/index.php

<?
header("content-type: text/plain");
$a = array("PATH_TRANSLATED", "SCRIPT_FILENAME", "DOCUMENT_URI", "PATH_INFO", "QUERY_STRING" );
foreach ($a as &$v)
  printf("%-15s %s\n", $v, $_SERVER[$v]);
?>

工作 NginX 配置

请注意,这/home/tino/www就是我的测试脚本所在位置。您可能希望从中填充所有其他参数/etc/nginx/fastcgi_params。例如,您需要

fastcgi_param SCRIPT_NAME $fastcgi_script_name;

填充PHP_SELF

server_tokens off;

server {
        listen          80;
        root            /home/tino/www;

        if ($request_uri ~ " ") { return 444; }

        location ~ [^/]\.php(/|$) {
                limit_except GET HEAD POST { deny all; }

                fastcgi_split_path_info ^((?U).+\.php)(.*)$;

                try_files $fastcgi_script_name =404;

                set             $wtf              $fastcgi_path_info;
                fastcgi_param   PATH_INFO         $wtf;
                fastcgi_param   REQUEST_METHOD    $request_method;
                fastcgi_param   PATH_TRANSLATED   $document_root$fastcgi_script_name;
                fastcgi_param   SCRIPT_FILENAME   $request_filename;
                fastcgi_param   DOCUMENT_URI      $document_uri;

                fastcgi_pass unix:/var/run/php5-fpm.sock;
                fastcgi_index index.php;
        }
}

这给了我以下输出http://example.com/index.php/a.php?b=b.php

PATH_TRANSLATED /home/tino/www/index.php
SCRIPT_FILENAME /home/tino/www/index.php
DOCUMENT_URI    /index.php
PATH_INFO       /a.php
QUERY_STRING    b=b.php

这正是我想要的。当然,请注意,这也适用于问题较少的 URI。

不起作用的配置

然而,直接配置不起作用,我真的很困惑,为什么:

server_tokens off;

server {
        listen          80;
        root            /home/tino/www;

        if ($request_uri ~ " ") { return 444; }

        location ~ [^/]\.php(/|$) {
                limit_except GET HEAD POST { deny all; }

                fastcgi_split_path_info ^((?U).+\.php)(.*)$;

                try_files $fastcgi_script_name =404;

                fastcgi_param   PATH_INFO         $fastcgi_path_info;
                fastcgi_param   REQUEST_METHOD    $request_method;
                fastcgi_param   PATH_TRANSLATED   $document_root$fastcgi_script_name;
                fastcgi_param   SCRIPT_FILENAME   $request_filename;
                fastcgi_param   DOCUMENT_URI      $document_uri;

                fastcgi_pass unix:/var/run/php5-fpm.sock;
                fastcgi_index index.php;
        }
}

这与上面的相同,只是$wtf缺少解决方法:

                set             $wtf              $fastcgi_path_info;
                fastcgi_param   PATH_INFO         $wtf;

成为

                fastcgi_param   PATH_INFO         $fastcgi_path_info;

但这不起作用,目前的输出http://example.com/index.php/a.php?b=b.php是:

PATH_TRANSLATED /home/tino/www/index.php
SCRIPT_FILENAME /home/tino/www/index.php
DOCUMENT_URI    /index.php
PATH_INFO       
QUERY_STRING    b=b.php

如您所见:PATH_INFO消失了。这与 无关php-fpm,它纯粹是一个NginX事物!

不安全的配置再次起作用

配置完成后,这将带来重大的安全漏洞由于缺少文件检查,再次运行:

server_tokens off;

server {
        listen          80;
        root            /home/tino/www;

        if ($request_uri ~ " ") { return 444; }

        location ~ [^/]\.php(/|$) {
                limit_except GET HEAD POST { deny all; }

                fastcgi_split_path_info ^((?U).+\.php)(.*)$;

                fastcgi_param   PATH_INFO         $fastcgi_path_info;
                fastcgi_param   REQUEST_METHOD    $request_method;
                fastcgi_param   PATH_TRANSLATED   $document_root$fastcgi_script_name;
                fastcgi_param   SCRIPT_FILENAME   $request_filename;
                fastcgi_param   DOCUMENT_URI      $document_uri;

                fastcgi_pass unix:/var/run/php5-fpm.sock;
                fastcgi_index index.php;
        }
}

但结果有一点不同http://example.com/index.php/a.php?b=b.phpSCRIPT_FILENAME看起来是错误的,DOCUMENT_URI但从不同的角度来看可能是正确的)。

PATH_TRANSLATED /home/tino/www/index.php
SCRIPT_FILENAME /home/tino/www/index.php/a.php
DOCUMENT_URI    /index.php/a.php
PATH_INFO       /a.php
QUERY_STRING    b=b.php

所以,请

显然,在使用设置正则表达式后,解析try_files方式会中断。$fastcgi_path_infofastcgi_split_path_info

所以,请问有人能告诉我,这种$wtf解决方法是否确实是正确的解决方案,或者我是否仍然需要担心其他不良副作用try_files

谢谢。(如果我遗漏了一些重要的安全信息,请评论。)

答案1

昨天我正在使用 PHP-FPM 设置我的第一个 Nginx 服务器,我可能遇到了和你一样的问题。长话短说,我无法正确安全地设置 Nginx,并且所有 PHP 的服务器变量都正确设置。我终于找到了一个合适的设置,我将与你分享。但是,如果能从 Nginx 专家那里得到关于这个问题的意见,那就太好了。说真的,我们遇到了一些本来不应该发生的非常奇怪的问题。

您的设置问题

因此,基本上,您需要一个可工作且安全的 Nginx+PHP-FPM 安装。我说的“可工作”是指 PHP 的服务器变量已正确设置,我说的“安全”是指 Nginx 已受到保护,免受已知漏洞的侵害。

第一的of,我能够重现您的配置和问题。出于某种原因,正在try_files破坏某些东西。我无法说出原因,但您说得对。try_files用以下代码替换指令似乎可以解决该问题:

if (!-f $document_root$fastcgi_script_name) {
    return 404;
}

编辑:正如下面评论中讨论的那样,上面的代码应该避免。而且,原始try_files指令正在按预期发挥作用。

第二,我注意到您没有包含fastcgi_params负责设置所有需要的(和必需的)FastCGI 参数的文件,这些参数将用于设置 PHP 的服务器变量。我不知道您为什么不包含此文件,因为我在网上读到的每一篇文档都告诉我们要使用该文件。现在文件已包含,我们需要修改一些默认情况下未正确设置的参数。最后,我们需要添加以下指令:

include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param PATH_INFO $fastcgi_path_info;
fastcgi_param PATH_TRANSLATED $document_root$fastcgi_path_info;

注意SCRIPT_FILENAME与您的有何不同。同样,我读过很多文档,它们告诉我们要使用此值(我将在下面提供链接)。您可以将指令fastcgi_param直接放在fastcgi_params文件中,也可以放在您的location部分中。

然后,什么都不起作用。如果我使用和你相同的链接,我得到的是No input file specified。查看日志文件,我得到的是Unable to open primary script: /var/www/a.php (No such file or directory)。我不知道为什么会这样,但所有的 fastcgi 参数似乎都混淆了。

现在,最奇怪的是,如果我删除这一行:

fastcgi_param PATH_TRANSLATED $document_root$fastcgi_path_info;

它又能正常工作了,但 PHP 的服务器变量混淆了。不仅PATH_TRANSLATED没有设置,PHP_SELF而且其他变量也没有正确设置。这是我长期以来一直苦苦挣扎的地方。幸运的是,我找到了一个似乎符合我们目标的解决方案。

工作设置

如果我们在 PHP 配置中重新启用cgi.fix_pathinfo,一切就都正常了。起初,我认为这样做是个坏主意。但是,我阅读了cgi.fix_pathinfo启用后的安全风险,才发现我们已经受到了保护。默认情况下security.limit_extensions设置为.php,我们就可以免受cgi.fix_pathinfo问题的影响。此外,文件存在性检查(if我们之前添加的条件)可以更好地保护我们,防止 FastCGI 尝试将其他文件解释为 PHP。

最后location部分应如下所示:

location ~ [^/]\.php(/|$) {
    fastcgi_split_path_info ^((?U).+\.php)(.*)$;

    try_files $fastcgi_script_name =404;

    include fastcgi_params;
    fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
    fastcgi_param PATH_INFO $fastcgi_path_info;
    fastcgi_param PATH_TRANSLATED $document_root$fastcgi_path_info;

    fastcgi_pass unix:/var/run/php5-fpm.sock;
    fastcgi_index index.php;
}

其他想法

有一件事没人谈论,即使他们的做法各不相同。我说的是locationandfastcgi_split_path_info指令中使用的正则表达式。就我个人而言,我选择了这一个,因为它们对我来说更有意义:

location ~ ^.+\.php(/|$) { ... }
fastcgi_split_path_info ^((?U).+\.php)(/?.+)$;

我非常想知道另一个的优点和缺点。再次,很高兴能听到 Nginx 专家对此主题的见解。

来源

答案2

不确定为什么以下链接没有出现在这个对话中:try_files & $fastcgi_path_info

try_files 指令将请求的 URI 更改为文件系统上匹配的 URI,随后尝试将 URI 拆分为 $fastcgi_script_name 和 $fastcgi_path_info 会导致路径信息为空 - 因为 try_files 之后的 URI 中没有路径信息。

我认为这不应该被视为错误,而应该被视为 try_files 工作方式的一个特性。它使 try_files 与 fastcgi_split_path_info 一起使用不太方便,但有多种方法可以解决这个问题,包括上面提供的方法。

提及多于解决方法是您在问题中提到的那个。

因此,您发现的缺陷之一nginx,并且(截至 2016 年)不会得到修复。您的解决方法完全有效,实际上,在随 Debian 一起分发的nginx代码片段中引用了它。

相关内容