29

我在我的网站上用 php 创建了一个上传表单,人们可以上传一个 zip 文件。然后提取 zip 文件并将所有文件位置添加到数据库中。上传表格仅供人们上传图片,显然,文件位于 zip 文件夹中,在文件被提取之前我无法检查正在上传的文件。我需要一段代码来删除所有不是图像格式的文件(.png、.jpeg 等)。我真的很担心人们能够上传恶意的php文件,安全风险很大!我还需要注意人们更改 php 文件的扩展名以试图绕过此安全功能。

这是我使用的原始脚本http://net.tutsplus.com/videos/screencasts/how-to-open-zip-files-with-php/

这是实际提取 .zip 文件的代码:

function openZip($file_to_open) {
    global $target;

    $zip = new ZipArchive();
    $x = $zip->open($file_to_open);
    if($x === true) {
        $zip->extractTo($target);
        $zip->close();

        unlink($file_to_open);
    } else {
        die("There was a problem. Please try again!");
    }
}

谢谢,本。

4

10 回答 10

67

我真的很担心人们能够上传恶意的php文件,安全风险很大!

冰山一角!

我还需要注意人们更改 php 文件的扩展名以试图绕过此安全功能。

通常更改扩展名将阻止 PHP 将这些文件解释为脚本。但这不是唯一的问题。除了 '...php' 之外,还有更多的东西会损坏服务器端;'.htaccess' 和设置了 X 位的文件是显而易见的,但绝不是您需要担心的全部。即使忽略服务器端的东西,也存在一个巨大的客户端问题。

例如,如果有人可以上传一个 '.html' 文件,他们可以在其中包含一个 <script> 标签来劫持第三方用户的会话,并删除他们所有上传的文件或更改他们的密码或其他东西。这是典型的跨站点脚本 (XSS) 攻击。

另外,由于某些浏览器(主要是 IE)的“内容嗅探”行为,以“.gif”形式上传的文件实际上可能包含诸如此类的恶意 HTML。如果 IE 在文件开头附近看到类似(但不限于)“<html>”之类的信息,它可以忽略提供的“Content-Type”并显示为 HTML,从而导致 XSS。

此外,可以制作一个文件,该文件既是您的图像解析器将接受的有效图像,包含嵌入的 HTML。根据用户浏览器的确切版本和图像文件的确切格式(尤其是 JPEG 具有一组非常可变的可能标题格式),可能会出现各种结果。IE8 中有一些缓解措施,但现在没有用,你不得不想知道为什么他们不能简单地停止进行内容嗅探,你们这些白痴 MS,而不是给我们负担本应具有的 HTTP 标头的不合格的非标准扩展刚开始工作。

我又陷入了咆哮。我会停下来。安全地提供用户提供的图像的策略:

1:永远不要使用取自用户输入的文件名将文件存储在服务器的文件系统上。这可以防止错误和攻击:不同的文件系统对于文件名中允许哪些字符有不同的规则,而且“清理”文件名比您想象的要困难得多。

即使你使用了一些非常严格的东西,比如“只有 ASCII 字母”,你仍然需要担心太长、太短和保留的名称:尝试将一个像“com.txt”这样无害的名称保存在Windows 服务器并观察您的应用程序出现故障。认为您知道您的应用程序可能在其上运行的每个文件系统的路径名的所有奇怪缺点吗?自信的?

相反,将文件详细信息(例如名称和媒体类型)存储在数据库中,并使用主键作为文件存储中的名称(例如“74293.dat”)。然后,您需要一种方法来为它们提供不同的明显文件名,例如将文件吐出的下载器脚本、执行 Web 服务器内部重定向的下载器脚本或 URL 重写。

2:使用 ZipArchive 时要非常非常小心。extractTo 中存在相同类型的遍历漏洞,这些漏洞影响了大多数基于路径的 ZIP 提取器。此外,您还可以接受ZIP 炸弹的攻击。最好通过逐步检查存档中的每个文件条目(例如,使用zip_read/zip_entry_*)并检查其详细信息,然后手动将其流解压缩到具有已知良好名称和模式标志的文件,从而避免任何错误文件名的危险,您在没有存档帮助的情况下生成。忽略 ZIP 中的文件夹路径。

3:如果您可以加载图像文件并再次将其保存回来,特别是如果您在两者之间以某种方式处理它(例如调整大小/缩略图或添加水印),您可以合理地确定结果将是干净的。从理论上讲,可以制作一个针对特定图像压缩器的图像,这样当它被压缩时,结果也看起来像 HTML,但这对我来说似乎是一个非常困难的攻击。

4:如果您可以将所有图像作为下载提供(即在下载脚本中使用“Content-Disposition:附件”),那么您可能是安全的。但这对用户来说可能太不方便了。不过,这可以与 (3) 协同工作,提供更小的、已处理的内联图像,并且原始的高质量图像仅可作为下载使用。

5:如果您必须在线提供未更改的图像,您可以通过从不同的域提供它们来消除跨站点脚本风险。例如,对不受信任的图像使用“images.example.com”,对包含所有逻辑的主站点使用“www.example.com”。确保 cookie 仅限于正确的虚拟主机,并且设置了虚拟主机,以便它们除了正确的名称之外无法响应任何内容(另请参阅:DNS 重新绑定攻击)。这就是许多网络邮件服务所做的。

总之,用户提交的媒体内容是一个问题。

总结总结,AAAARRRRRRRGGGGHHH。

ETA 重新评论:

在顶部您提到“设置了 X 位的文件”,这是什么意思?

我不能说ZipArchive.extractTo()因为我还没有测试过,但是许多提取器,当被要求从档案中转储文件时,将重新创建与每个文件关联的 [一些] Unix 文件模式标志(如果档案是在一个 Unix,所以实际上有模式标志)。如果缺少所有者读取权限,这可能会导致您出现权限问题。但是,如果您的服务器启用了 CGI,这也可能是一个安全问题:X 位可以允许将文件解释为脚本并传递给第一行 hashbang 中列出的任何脚本解释器。

我以为 .htaccess 必须在主根目录中,不是这样吗?

取决于 Apache 的设置方式,尤其是 AllowOverride 指令。通用主机在任何目录上允许覆盖是很常见的。

如果有人仍然上传像 ../var/www/wr_dir/evil.php 这样的文件会发生什么?

我希望领先的“..”会被丢弃,这就是遭受相同漏洞的其他工具所做的。

但是我仍然不相信extractTo()恶意输入,有太多奇怪的小文件名/目录树的东西可能会出错 - 特别是如果你期望在 Windows 服务器上运行。zip_read()使您可以更好地控制取消归档过程,从而减少攻击者。

于 2009-03-02T16:09:11.470 回答
15

首先,您应该禁止每个没有正确图像文件扩展名的文件。之后,您可以使用该getimagesize功能检查文件是否为常规图像文件。

但此外,您应该知道某些图像格式允许评论和其他元信息。这可用于恶意代码,例如某些浏览器将在某些情况下执行的 JavaScript(请参阅Internet Explorer 中的风险 MIME 嗅探)。

于 2009-03-02T14:46:38.797 回答
9

那么,您可能不应该只依赖文件扩展名。尝试通过图像库传递每个文件以验证它是否真的是图像。

于 2009-03-02T14:39:49.423 回答
2

您可能还想考虑使用以下库进行 mime 类型检测:

http://ca.php.net/manual/en/ref.fileinfo.php

于 2009-03-02T20:55:20.377 回答
2

我没有看到在您的数据库中重命名 php 文件的风险......只要您不将它们评估为 PHP 文件(或根本不评估它们),它们就不会造成太大的伤害,并且由于没有 .php 扩展名,php 引擎不会触及它们。

我想你也可以搜索文件<?php...

另外:假设上传到您机器的文件最糟糕。将保存它们的文件夹重命名为“病毒”并相应地对待它。不要公开,不要授予任何文件启动权限(尤其是 php 用户)等。

于 2009-03-02T14:40:23.587 回答
1

就个人而言,我会在 Apache 配置中添加一些内容,以确保它将 PHP 文件作为文件上传到的位置的文本提供,这样您就安全了,并且可以允许将来上传其他文件类型。

于 2009-03-04T19:29:13.657 回答
1

现在您依靠硬盘空间进行提取。您可以检查文件头以确定它们是什么类型的文件。可能有图书馆。

题外话:让用户选择几张图片而不是上传一个 zip 文件不是更好吗?更适合不知道 zip 是什么的人(是的,它们存在)

于 2009-03-02T14:43:40.550 回答
1

如果您将 php 设置为仅解析以 .php 结尾的文件,那么您只需将文件从 somename.php 重命名为 somename.php.jpeg 就可以了。

如果你真的想删除文件,php 有一个可用的zip 库。您可以使用它来检查上传的 zip 存档中所有文件的名称和扩展名,如果它包含 php 文件,则给用户一条错误消息。

于 2009-03-02T14:52:35.727 回答
0

当心通过 getimagesize() 传递恶意 PHP

通过图像函数注入 PHP,尝试使用 getimagesize() 函数确保图像安全

在这里阅读更多http://ha.ckers.org/blog/20070604/passing-malicious-php-through-getimagesize/

更适合您的用户徽标使用 gravatar,如 Stackoverflow 使用的此处;)

于 2013-10-31T21:55:34.373 回答
0

使用 getimagesize 函数。完整程序:- 1.) 提取图像/上传文件的扩展名,然后将扩展名与允许的扩展名进行比较。2.) 现在创建一个用于重命名上传文件的随机字符串。最好的想法是。md5(session_id().microtime())它不能被复制,并且如果您的服务器非常快并且可以处理不到一微秒而不是使用增量变量并使用字符串添加它们。现在移动那个文件。

提示 在上传目录中禁用 PHP 文件处理,它将始终防止您受到任何服务器端攻击,如果可能的话,将您的 htaccess 添加到根目录或 httpd 配置文件中并从那里禁用 htaccess 文件现在它可以解决您的最大问题

于 2014-07-12T09:29:36.833 回答