仅在白名单 MIME 内容类型下提供任何用户上传的文件是否安全?

信息安全 应用安全 病毒 上传文件
2021-08-28 16:24:46

假设我开发了一个应用程序,

  1. 允许任何用户上传仅包含白名单 mime 内容类型和扩展名(word 和 pdf)的文件。
  2. 以允许的扩展名和内容类型提供这些文件。

这是安全风险吗?为什么?

任何浏览器都会从文件字节中推断出内容类型(使用魔术头)并丢弃我在头中指定的内容类型吗?

确保此安全的解决方案是什么?我是否应该断言正在上传的文件具有与客户端提供的 mime 类型匹配的魔术字节?

我知道这个问题类似于Is it safe to store and replay user-provided mime types? ,但不要认为它是重复的。

4个回答
  1. Krzysztof 概述的 HTML 内容嗅探;主要但不完全是 IE。

  2. jar:旧版 Firefox 中的URL 漏洞

  3. 类似于 JAR 文件(GIFAR等)的内容 - 托管可以解释为 Java 存档的内容意味着 XSS,因为 Java 实施了不同的同源策略。

  4. 包含看起来有点像 crossdomain.xml 内容的文件可以通过 loadPolicyFile 调用来定位,以获取 Flash 调用者的 XSS。

我是否应该断言正在上传的文件具有与客户端提供的 mime 类型匹配的魔术字节?

不足以对抗变色龙(文件与任何一种类型都同样有效)。

确保此安全的解决方案是什么?

唯一强有力的缓解措施是从与您的主站点不同的主机名提供不受信任的上传内容。

  1. 如果您只担心直接的 JavaScript XSS/同源策略,那么不同的主机名可以是您主站点的子域。

  2. 如果您需要阻止它读取 cookie(例如会话 ID),它必须是不相交的子域。也就是说,如果您的主站点位于 www.example.com,则它可能是 insecure.example.com,但在这种情况下,您也不能允许您的站点在裸露的“example.com”上做出响应。无法阻止 example.com cookie 继承到 IE 上的 insecure.example.com。最佳实践:将对 example.com 的所有访问重定向到 www.example.com。

  3. 如果您需要防止 cookie 强制,它必须是一个完全不同的域:也就是说,insecure.example.com 可以编写一个将由 www.example.com 读取的 cookie,可能会覆盖 www.example.com 设置的 cookie。这是一个不太严重的漏洞:读取 cookie 的能力通常会导致会话劫持,而 cookie 强制只会导致拒绝服务(因为 www.example.com 没有它的 cookie 将无法工作)。

  4. 如果您担心使用旧 Java 插件中的漏洞来防止 cookie 窃取,或者如果您在不希望小程序能够访问的端口上运行其他服务,则它也必须在不同的 IP 地址上提供服务。

在它们之间,浏览器和插件使安全地托管上传的文件成为一种可怕的考验。

不幸的是,在您的示例中,Internet Explorer 仍将尝试从文件内容的前 256 个字节中检测 MIME 类型(称为 MIME 嗅探)。引用有关该主题的 MSDN 文档

2. 如果服务器提供的 MIME 类型是已知的或不明确的(我的注释:application/pdf已知),则会扫描缓冲区以尝试从实际内容中验证或获取 MIME 类型。如果发现肯定匹配(硬编码测试之一成功),则立即返回此 MIME 类型作为最终确定,覆盖服务器提供的 MIME 类型(此类型的行为是识别正在发送的 .gif 文件所必需的作为文本/html)。在扫描期间,确定缓冲区主要是文本还是二进制。

我刚刚通过使用以下 PHP 文件确认了这种行为:

<?php header('Content-Type: application/pdf'); ?>
<html>
<p>Hello, <b>world</b></p>

这将在 IE8/Win XP SP2 中显示 HTML 内容。

您可以通过在响应中指定X-Content-Type-Options: nosniffHTTP 标头来更改此过程,但它在IE8+中受支持。幸运的是,其他浏览器信任 HTTP 标头,并且 MIME 嗅探在它们中要轻得多,请参阅例如Firefox 文档有一个非常好的白皮书记录了各种浏览器中的 MIME 嗅探。

如果可能,您还应该尝试从文件内容中检查魔术字节。我还建议您使用Content-disposition: attachment标题。

内容嗅探。你的提议还不够:它很容易受到内容嗅探攻击。我在其他地方写过关于防止内容嗅探攻击的策略。有多种防御方式。以下是主要的:

  • Content-Type:在响应中包含标头。确保它包含有效的 MIME 类型(避免无效的 MIME 类型。)

  • X-Content-Type-Options: nosniff在响应中包含标头。这将在最新版本的 IE 上关闭 IE 的内容嗅探算法。

  • 如果您不打算在浏览器中查看内容,可以设置Content-Disposition: attachment, 以使浏览器将其视为文件下载。

即使这些步骤也不能保证足够。例如,如果用户使用的是 IE6,他们仍然容易受到攻击。

(如果这听起来很烦人,那你肯定是对的。责怪 Apache 的人包含了一个糟糕的默认配置,多年来违反了 Web 标准,并且忽略了对它做点什么的请求。不幸的是,现在为时已晚:我们被卡住了拥有大量部署的浏览器,这些浏览器会做危险的事情。)

单独的域。更好的防御措施是将用户提供的内容托管在单独的域上,该域仅用于用户上传的内容。这样,成功的内容嗅探攻击就不会攻击您网站的内容。一个用户的上传仍然可以攻击其他用户的上传,但这可能是可以容忍的。

检查您的白名单。您似乎认为 PDF 和 Word 文件是无害的。然而,这是两种强大而危险的文件格式。PDF 因是矢量而臭名昭著。恶意 PDF 文件比比皆是,并且可以成功渗透到许多较旧的 PDF 查看器中。PDF 风险如此之高,以至于 Chrome 在允许您在 PDF 查看器中下载和查看 PDF 文档之前采取了特殊的预防措施。Word 也是一种强大而危险的文件格式,可能成为攻击的宿主。因此,我不会认为 Word 或 PDF 是无害的。

您可以将用户重定向到 Google 文档,以通过 Google 文档在浏览器中查看 Word/PDF 文件。Google 会将 Word/PDF 文件转换为 HTML,然后将其发送到查看者的浏览器。在您的情况下,这可能会或可能不会被接受。

扫描文件上传以查找病毒。我建议您使用一些病毒或恶意软件扫描程序扫描所有用户上传的内容以查找病毒。对于 PDF 文件,另请参阅如何扫描 PDF 中的恶意软件?. 您可能希望在上传后立即对其进行扫描。您还可以考虑定期重新扫描旧文件(这可能会捕获一些以前未检测到的恶意软件,因为防病毒/恶意软件定义已更新)。

更多信息。另请参阅Mozilla 的文件上传清单,在其安全编码标准中。这是一个很好的安全实践列表。

概括。总之,您可以使用的最强大和最有效的防御措施是将用户上传的内容放在单独的域中。然后,作为额外的保护,您可能需要考虑此处列出的其他防御措施。


更新:我刚刚了解到您的方案的另一个问题。显然,Flash 忽略了 Content-Type 标头,这可能允许加载恶意 SWF,然后它可以执行您使用 XSS 执行的所有操作。(叹气,愚蠢的 Flash。)不幸的是,再多的白名单也无法阻止这种攻击。因此,似乎唯一安全的解决方案是将用户上传的内容托管在单独的域上。

我认为其他2个答案很好。但是还有一点需要考虑:即使您完全成功地限制了您所服务的内容类型,Word 文档和 PDF 文档本身仍然可能是恶意的。

PDF 文档可以利用旧版本 Adob​​e 阅读器中存在的数百个漏洞中的任何一个。最好的缓解方法是使用防病毒/恶意软件检测扫描每个上传的文件。(尽管由于病毒特征的猫捉老鼠性质,这仍然是有限的缓解措施。)