上传的安全威胁
Posted
技术标签:
【中文标题】上传的安全威胁【英文标题】:Security threats with uploads 【发布时间】:2012-06-19 03:41:58 【问题描述】:我允许用户将文件上传到我的服务器。我面临哪些可能的安全威胁?如何消除它们?
假设我允许用户从他们的系统或网络上传图像到我的服务器。现在要检查这些图像的大小,我必须将它们存储在我的/tmp
文件夹中。不是很危险吗?如何将风险降到最低?
另外假设我正在使用wget
从用户在我的表单中上传的链接下载图像。我首先必须将这些文件保存在我的服务器中以检查它们是否真的是图像。另外,如果恶作剧者给了我一个 URL,我最终下载了一个充满恶意软件的整个网站怎么办?
【问题讨论】:
您并没有真正在问题本身上投入大量工作,但这是一个非常好的问题,它的核心和重点。我希望这可以成为这个主题的规范问题。 为什么人们投票结束这个话题是题外话?这完全是主题,这是每个程序员都需要非常注意的事情! 我会尽量具体一点。假设我允许用户从他们的系统或网络上传图像到我的服务器。现在要检查这些图像的大小,我必须将它们存储在我的 /tmp 文件夹中。不是很危险吗?如何将风险降到最低? @deceze 同意这是主题。确实需要进行非近距离投票来对抗 CV 潮流。 @finnw 重新打开不是一回事,因为它发生在关闭之后。 php 问题是积极投递简历的,非近距离投票可能会在当时引发更彻底的讨论。在 meta 上进行了讨论,并在那里被拒绝,理由是不投票结束,你实际上是投了一个不结束的投票。不过我不同意这个结论。 【参考方案1】:首先,要意识到上传文件意味着用户向您提供了大量各种格式的数据,并且用户可以完全控制这些数据。这甚至是一个普通表单文本字段的问题,文件上传是相同的,而且更多。第一条规则是:不要相信任何一个。
您通过文件上传从用户那里得到什么:
文件数据 文件名 MIME 类型这是文件上传的三个主要组成部分,没有一个是可信的。
不要信任$_FILES['file']['type']
中的 MIME 类型。这是一个完全任意的、用户提供的值。
不要将文件名用于任何重要的事情。这是一个完全任意的、用户提供的值。通常,您不能信任文件扩展名或名称。不要使用'dir/' . $_FILES['file']['name']
之类的方式将文件保存到服务器的硬盘上。如果名称为'../../../passwd'
,则您正在覆盖其他目录中的文件。始终自己生成一个随机名称以将文件另存为。如果您愿意,您可以将原始文件名作为元数据存储在数据库中。
永远不要让任何人或任何东西任意访问文件。例如,如果攻击者将malicious.php
文件上传到您的服务器,并且您将其存储在站点的 webroot 目录中,则用户只需转到example.com/uploads/malicious.php
即可执行该文件并在您的服务器上运行任意 PHP 代码.
切勿将任意上传的文件公开存储在任何地方,始终将它们存储在只有您的应用程序可以访问它们的地方。
只允许特定进程访问文件。如果它应该是图像文件,则只允许读取图像并调整图像大小的脚本直接访问该文件。如果此脚本在读取文件时出现问题,则可能不是图像文件,标记它和/或丢弃它。其他文件类型也是如此。如果该文件应该可供其他用户下载,请创建一个脚本来提供该文件以供下载,并且不对其进行任何其他操作。
如果您不知道正在处理的文件类型,请自行检测文件的 MIME 类型和/或尝试让特定进程打开文件(例如,让图像大小调整进程尝试调整假定图像的大小)。这里也要小心,如果该过程中存在漏洞,恶意制作的文件可能会利用它,从而导致安全漏洞(此类攻击的最常见示例是 Adobe 的 PDF 阅读器)。
解决您的具体问题:
[T] 要检查这些图像的大小,我必须将它们存储在我的 /tmp 文件夹中。是不是很危险?
没有。如果您不对这些数据进行任何操作,那么仅将数据存储在临时文件夹中的文件中是没有风险的。数据只是数据,无论其内容如何。仅当您尝试执行数据或程序正在解析数据时才会有风险,如果程序包含解析缺陷,恶意数据可能会诱使他们做出意想不到的事情。
当然,在磁盘上存放任何类型的恶意数据比在任何地方都没有恶意数据风险更大。你永远不知道谁会来和它一起做点什么。所以你应该验证所有上传的数据,如果它没有通过验证,请尽快丢弃它。
如果恶作剧者给了我一个网址,我最终下载了一个充满恶意软件的整个网站怎么办?
具体下载什么取决于您。一个 URL 最多会产生一个数据块。如果您正在解析该数据并根据该初始 blob 下载更多 URL 的内容,那是您的问题。不要这样做。但即使你这样做了,那么你也会有一个临时目录,里面装满了东西。同样,如果您不使用这些东西做任何危险的事情,这并不危险。
【讨论】:
+1 非常有趣的阅读,写得很好,并指出了一些我没有想到的问题。【参考方案2】:1 个简单的场景是: 如果您使用的上传接口对允许上传的文件类型没有限制,那么攻击者可以上传带有恶意代码的 PHP 或 .NET 文件,从而导致服务器受损。
参考: http://www.acunetix.com/websitesecurity/upload-forms-threat.htm 以上链接讨论了常见问题
另请参阅: http://php.net/manual/en/features.file-upload.php
【讨论】:
【参考方案3】:以下是其中的一些:
当文件上传到服务器时,PHP 会将变量 $_FILES['uploadedfile']['type'] 设置为客户端正在使用的 Web 浏览器提供的 mime-type。但是,文件上传表单验证不能仅取决于此值。恶意用户可以使用脚本或其他允许发送 HTTP POST 请求的自动化应用程序轻松上传文件,从而允许他发送虚假的 mime-type。
几乎不可能编译一个包含攻击者可以使用的所有可能扩展的列表。例如。如果代码在托管环境中运行,通常此类环境允许使用大量脚本语言,例如 Perl、Python、Ruby 等,而且列表可能无穷无尽。
恶意用户可以通过上传名为“.htaccess”的文件轻松绕过此类检查,该文件包含类似于以下的代码行:
AddType application/x-httpd-php .jpg
【讨论】:
【参考方案4】:有一些通用规则可以避免文件上传的一般问题:
将上传的文件不存储在您的网站根文件夹下 - 这样用户将无法重写您的应用程序文件并直接访问上传的文件(例如在 /var/uploads,而您的应用位于 /var/www)。 在数据库中存储经过清理的文件名,物理文件给出文件哈希值的名称(这也解决了存储文件重复的问题 - 它们将具有相同的哈希值)。为避免 /var/uploads 文件夹中文件过多时文件系统出现问题,请考虑将文件存储在文件夹树中:
file hash = 234wffqwdedqwdcs
-> 存储在/var/uploads/23/234wffqwdedqwdcs
通用规则: /var/uploads/<first 2 hash letters>/<hash>
如果你还没有安装 nginx - 它像魔术一样提供静态服务,它的 'X-Accel-Redirect' 标头将允许你使用自定义脚本首先检查权限的文件
【讨论】:
以上是关于上传的安全威胁的主要内容,如果未能解决你的问题,请参考以下文章
安天移动安全应对“DressCode”威胁,发布企业移动威胁检查工具