如何安全地防止在任何服务器上通过PHP运行上传的文件?

我注意到可以通过PHP运行一个文件,即使它的扩展名不是.php ,例如文件test.xyz.php.whatever.zyx仍然可以用PHP运行,即使扩展名不是.php ! 它恰好有.php. 在文件名中,这足以让我的Apache运行PHP脚本。

我试过(如有人build议)把这个文件夹中的.htaccess文件:

 php_flag engine off 

但是在我的机器上没有用。

我现在知道的唯一解决scheme是:

  • 重命名为不是通过PHP运行的已知文件扩展名,例如.txt
  • 删除文件名中的所有点,从而使其不扩展。

但我仍然不确定这些解决scheme如何在Windows服务器(使用Apache)上运行。

有没有其他解决scheme不需要文件名以任何方式重命名?

Solutions Collecting From Web of "如何安全地防止在任何服务器上通过PHP运行上传的文件?"

对于用户上传,我建议您在本例中上传根路径上方的文件夹只有您有访问权限上传文件夹(直接寻址),攻击者无法访问此文件夹中的任何文件因此,您禁用攻击者操作来运行恶意文件

为了完全安全,你需要做一些事情:

将上传目录设置在“公共”文件夹上方,使其无法从浏览器访问。 这个设置是在php.ini(php配置文件)。 您需要重新启动Apache才能生效。 在大多数Redhat / Fedora / CentOS Web服务器上,这可以是:

 upload_tmp_dir = "/var/tmp/" 

或者,在我的本地Windows 7 WAMP安装中,它被设置为:

 upload_tmp_dir = "c:/wamp/tmp" 

在.htaccess中禁用运行在该目录(c:/ wamp / tmp)上的脚本:

 RemoveHandler .php .phtml .php3 RemoveType .php .phtml .php3 php_flag engine off 

在您的PHP脚本中,获取上传的文件,根据mimetype(不是文件类型扩展名)过滤它,更改文件名,并将其放入一个安全的可公开访问的文件夹中。 更详细地说:

最好使用一个MVC框架,比如包含文件类型过滤的Zend Framework。

如果你这样做,你应该是安全的。 显然你永远不会百分之百的安全,因为在PHP,MySQL,命令行等方面有着无数晦涩的漏洞,特别是在老系统上。 在较大的公司网络服务器(我工作的)上,他们禁用了所有的东西,并有选择地只启用项目所需的东西。 有了像WAMP这样的系统,他们可以实现一切,从而缓解当地的发展。

在专业项目上开展工作的良好做法是在Rackspace或Amazon获得云服务器帐户,并了解如何配置php.ini和httpd.conf设置以及PHP安全性最佳实践。 一般来说,不要相信用户的输入,期望它是腐败的/恶意的/格式不正确的,最后你会很安全的。

首先你需要了解这里发生的事情:

 test.xyz.php.whatever.zyx 

它自己的网络服务器上的这样的文件将不会做任何事情。 只有添加的配置才会告诉Apache在该文件上执行PHP。

所以如果你删除了这个添加的配置,Apache不会在意那里找到.php – 无论是在最后还是堆叠文件扩展的一部分。

检查您的服务器配置中为php设置了哪个处理程序。 删除它的上传目录。 然后,这将不会解决任何其他配置问题,你可能有与上传的文件,但PHP文件不会再由PHP执行 – 这是你想要的,如果我明白你的权利。

如果您在查找问题时遇到问题,则需要将您的PHP配置发布到您的系统的httpd.conf文件和关联的Apache HTTPD配置文件中。

有人告诉你的指令.htaccess

 php_flag engine off 

只有在你运行PHP作为apache的SAPI模块时才能工作。

您可以使用.htaccess文件为单个目录删除PHP文件的处理程序,而不是使用php_flag engine off

在禁用PHP的目录中,你的.htaccess应该包括:

 RemoveHandler .php .phtml .php3 .php4 .php5 RemoveType .php .phtml .php3 .php4 .php5 

但是,根据你在默认的Apache配置中配置哪些AddHandler类型,在windows上应该在C:\Program Files\Apache<version>\conf\httpd.conf

 RemoveHandler .php RemoveType .php 

您还需要确保在主apache配置文件中包含.htaccess文件的目录位于由设置了AllowOverride FileInfoDirectory语句覆盖。 如果您将使用.htaccess文件用于其他目的,您可能会考虑AllowOverride All – 请参阅AllowOverride的Apache文档以获取有关差异的解释。

在Apache上,您可以禁用包含不受信任文件的目录的所有动态处理程序。

 SetHandler default-handler 

这不是很好的答案,但希望在一些特殊情况下有用…

你可以像这样在.htaccess文件中使用mod_rewrite:

 RewriteRule ^(.+).xyz.php.whatever.zyx$ index.php?openfile=$1 [NC,L] 

并在你的index.php文件中:

 $file = secure_this_string($_GET['openfile']); include($file.'.xyz.php.whatever.zyx'); # or some other files 

记得看到这个答案出于安全原因StackOverFlow

并在test.xyz.php.whatever.zyx文件中:

 <?php echo 'hello'; 

现在如果客户端请求/test.xyz.php.whatever.zyx文件,输出应该是'hello'

一个简单的正则表达式可以完成这个工作

 <?php $a = strtolower($_FILES["file"]["name"]); $replace = array(".php", ".phtml", ".php3", ".php4", ".php5"); $_FILES["file"]["name"] = str_replace($replace, "", $a); ?> 

这在任何服务器上工作正常

下面的.htaccess代码可以工作,并拒绝访问包含“ php ”的文件:

 <FilesMatch "php"> Deny from all </FilesMatch> 

我可以很容易地在我们的服务器上重现您的问题。 有一种方法可以解决这个问题,你需要编辑/etc/mime.types和注释掉行

 #application/x-httpd-php phtml pht php #application/x-httpd-php-source phps #application/x-httpd-php3 php3 #application/x-httpd-php3-preprocessed php3p #application/x-httpd-php4 php4 #application/x-httpd-php5 php5 

这些行会导致任何名称上的.php文件被处理。 一旦你注释掉了mime.types中的条目,/etc/apache2/mods-enabled/php5.conf中的mod_php配置有这个条目,它正确地只处理文件ENDING与.php

 <FilesMatch "\.ph(p3?|tml)$"> SetHandler application/x-httpd-php </FilesMatch> 

什么是真正可怕的是,这是一个默认配置(在我们的情况下Ubuntu 10.04)。


编辑

在Windows上,mime.types文件应该位于apache_home / conf / mime.types中

就个人而言,这是我在任何情况下都不再上传文件到Web服务器的主要原因。 相反,我使用S3 / Amazon SDK将上传的临时文件直接移动到S3的私有权限(我使用S3,任何其他CDN也可以)。 如果文件需要被Web客户端查看或查看,我使用一个与SDK集成的“getter”函数获取文件并显示。

只要你允许任何类型的文件上传到Web服务器,就会有太多的不可控制的变量,很难管理权限,过滤,甚至只是空间。 使用S3(或任何其他CDN),这是非常容易管理的,并且所有文件都默认从服务器有效隔离。