Nginx + PHP-FPM的PHP选项'cgi.fix_pathinfo'真的很危险吗?


51

已经有一个 很大 谈论关于相对于一个安全问题cgi.fix_pathinfo与Nginx的(通常是PHP-FPM,快速CGI)使用PHP选项。

结果,默认的nginx配置文件用来表示:

# NOTE: You should have "cgi.fix_pathinfo = 0;" in php.ini

但是,现在,“官方” Nginx Wiki 指出可以在不禁用上述PHP选项的情况下正确处理PATH_INFO。所以呢?

问题

  • 您能清楚地解释cgi.fix_pathinfo做什么吗?(官方文档只是说:“有关PATH_INFO的更多信息,请参见CGI规范”)
  • PHP将如何真正处理这些变量PATH_INFOSCRIPT_FILENAME变量?
  • 为什么使用Nginx以及如何会有危险?(详细示例)
  • 在这些程序的最新版本中是否仍然存在该问题?
  • Apache容易受到攻击吗?

我试图在每个步骤中了解问题。例如,我不明白为什么使用php-fpm Unix套接字可以避免此问题。


1
:您可能会被理解PATH_INFO和PATH_TRANSLATED的区别回答自己的问题blogs.msdn.com/b/david.wang/archive/2005/08/04/...
乔瓦尼Tirloni

Answers:


79

TL; DR-解决方案(您甚至可能不需要)非常简单,并且在此答案的结尾。

我将尝试解决您的特定问题,但是您对PATH_INFO的误解会使问题本身有些错误。

  • 第一个问题应该是“这条路径信息业务是什么?”

  • 你的下一个问题应该是:“如何PHP确定什么PATH_INFOSCRIPT_FILENAME是谁?”

    • 早期版本的PHP天真,并且在技术上甚PATH_INFO至不支持,因此本来应该PATH_INFO混用的东西SCRIPT_FILENAME在很多情况下就被破坏了。我没有足够老的PHP版本可进行测试,但我认为它SCRIPT_FILENAME的整体含义是:上例中的“ /path/to/script.php/THIS/IS/PATH/INFO”(前缀为docroot照常)。
    • 在启用cgi.fix_pathinfo的情况下,PHP现在可以正确地为上述示例找到“ / THIS / IS / PATH / INFO”,并将其放入PATH_INFOSCRIPT_FILENAME获得指向所请求脚本的部分(当然以docroot前缀)。
    • 注意:当PHP真正开始支持时PATH_INFO,他们必须为新功能添加配置设置,以便运行依赖于旧行为的脚本的人可以运行新的PHP版本。这就是为什么甚至需要配置开关的原因。它从一开始就应该是内置的(具有“危险”行为)。
  • 但是PHP如何知道脚本的哪一部分以及其路径信息?如果URI类似于:

    http://example.com/path/to/script.php/THIS/IS/PATH/INFO.php?q=foo

    • 在某些环境中,这可能是一个复杂的问题。PHP中发生的事情是,它找到URI路径的第一部分,该部分与服务器docroot下的任何内容都不对应。对于此示例,它看到您的服务器上没有“ /docroot/path/to/script.php/THIS”,但您当然可以肯定有“ /docroot/path/to/script.php”,因此现在SCRIPT_FILENAME已经确定并PATH_INFO得到其余的。
    • 因此,现在Nginx文档和HrvojeŠpoljar的答案(您不能对这样一个明确的例子大惊小怪)中详细阐述了危险的一个很好的例子:给定Hrvoje的例子(“ http:// example。”)。 com / foo.jpg / nonexistent.php ”),PHP在您的文档根目录“ /foo.jpg”上看到一个文件,但看不到任何名为“ /foo.jpg/nonexistent.php”的文件,因此SCRIPT_FILENAME获取了“ /foo.jpg” (再次,以docroot PATH_INFO开头)并获得“ /nonexistent.php”。
  • 现在应该清楚为什么以及如何可能造成危险:

    • Web服务器确实没有错-只是将URI代理给PHP,PHP无辜地发现“ foo.jpg”实际上包含PHP内容,因此它将执行它(现在您已经被伪装了!)。这是不是特别Nginx的本身。
  • 真正的问题是,你让不可信的内容被上传的地方没有消毒,并允许你在同一位置,这PHP愉快何时能执行其他任意请求。
  • 可以构建或配置Nginx和Apache来阻止使用这种欺骗手段的请求,并且有很多示例说明如何做到这一点,包括在user2372674的答案中这篇博客文章很好地解释了这个问题,但是缺少正确的解决方案。

  • 但是,最好的解决方案是仅确保正确配置PHP-FPM,以便它永远不会执行文件,除非文件以“ .php”结尾。值得注意的是,最新版本的PHP-FPM(〜5.3.9 +?)将此默认设置为默认值,因此这种危险不再是太大的问题了。

解决方案

如果您具有最新版本的PHP-FPM(〜5.3.9 +?),则无需执行任何操作,因为以下安全行为已经是默认设置。

否则,请找到php-fpm的www.conf文件(可能/etc/php-fpm.d/www.conf取决于您的系统)。确保您有以下内容:

security.limit_extensions = .php

同样,这些天在许多地方都是默认设置。

请注意,这不会阻止攻击者将“ .php”文件上传到WordPress的上载文件夹并使用相同的技术执行该文件。您仍然需要为应用程序提供良好的安全性。


5
好答案!需要澄清的是:如果您说的是PHP确定是什么SCRIPT_FILENAME,为什么fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;我的nginxconf中有一行?它是否超越了PHP自己发现其价值的努力SCRIPT_FILENAME
Totor

是否有获取值的函数security.limit_extensions?我想phpinfo()ini_get(security.limit_extensions)ini_get_all()没有成功。
elbowlobstercowstand

谢谢,如果最新版本的PHP-FPM(〜5.3.9 +?)将其作为默认值,为什么php7.1需要它?还是这篇文章错了?
Yevgeniy Afanasyev

14

本质上,没有此功能,您可以将名为“ foo.jpg”的php代码文件上传到Web服务器;然后像http://domain.tld/foo.jpg/nonexistent.php那样请求它,Web服务器堆栈会错误地说哦;这是一个PHP;我需要处理此问题,它将找不到foo.jpg / nonexistent.php,因此它将回落到foo.jpg并将foo.jpg作为php代码进行处理。这很危险,因为它使系统很容易受到入侵。例如,任何允许图像上传的Web应用程序都会成为上传后门的工具。

关于使用带有unix套接字的php-fpm来避免它;IMO不会解决问题。


您只重复在我提供的链接上可以阅读的内容。您没有解释真正的机制。您的答案需要增值恕我直言。
Totor

6
可能是正确的,但是您的标题中有问题,对此的答复是我的答复。如果您明确想要它;是的,这很危险;非常危险。
HrvojeŠpoljar2014年

1 /我的回答不仅限于标题:它有一个主体。2 / user109322已经证明您做错了:用于的任何值都不cgi.fix_pathinfo是危险的,因为默认的conf 是安全的(它将仅执行扩展名为的文件)。php-fpm.php
Totor

2

Nginx Wiki中作为安全措施

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

包含在位置栏中。在其他教程中

try_files $uri =404;

使用了,应该做同样的事情,但是根据Nginx Wiki可能会出现问题。使用这些选项,cgi.fix_pathinfo=1不再是问题。在这里可以找到更多信息。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.