图像上传-安全问题

17
我正在开发一个ASP.NET Web应用程序,希望用户可以从本地系统上传图像或传递图像的URL。该图像可以是JPG或PNG格式。在这样做时,我应该关注什么安全问题?我已经看到了在JPG文件中嵌入代码的各种方法。是否有C#(或外部库)中的方法可以确认文件是JPG / PNG,否则抛出错误?至少,我会将存储上传图像的目录设为不可浏览,并设置最大大小限制为1MB,但我想实现更进一步的检查。
感谢任何建议。
4个回答

14

有没有C#中的方法(或外部库)可以确认文件是JPG / PNG,否则会抛出错误?

也许有,但这本身并没有什么帮助。您可以轻松地创建一个既是有效图像格式又包含活动HTML /脚本内容供IE内容嗅探绊倒的文件。或者还有破碎的Java和Flash起源策略需要担心,这可能会产生同样的影响,将脚本化到服务器的安全上下文中。

  1. 如果您处理图像(例如剪裁,调整大小)并重新保存,则极其难以进行内容走私攻击。然而,您应始终确保您的服务器端工具是最新的,因为图像处理库中的漏洞可能使您暴露于服务器端利用。

  2. 如果您无法这样做,那么作为减轻所有内容注入问题的最佳选择是从不具有对主站点敏感凭据(cookie,基本认证)的任何内容的不同[子]域提供图像。

  3. 如果使用此目的的子域,例如images.example.com,则您的主站点应仅通过www.example.com访问,而不是example.com。否则,在IE中向images.example.com注入内容可以访问example.com的cookie。example.com应301重定向到www.example.com,以防止不必要的cookie泄漏。

  4. 将响应添加头X-Content-Type-Options: nosniff,以阻止来自IE8的内容走私攻击。(很遗憾,无法帮助早期版本。)

此外:

  1. 在 Windows 服务器上,用户指定的文件名的过滤是很困难的,因为可用文件名的规则非常复杂。一个好的起点是只允许使用字母和数字,并添加自己的文件扩展名和前缀。(需要前缀来避免 Windows 保留的文件名和空文件名.)

  2. 更好的做法是将用户提供的文件名存储在数据库中,而不是直接使用它作为真实文件名。

有关文件上传安全问题的更多讨论,请参见此问题


嗨。处理图像的最佳方法是什么?只需读取图像并将其保存到文件系统中(使用自己的命名方案)就足够了吗?谢谢。 - keyboardP
通过“处理”我指的是将其加载到图像处理器中,对图像进行某些操作并保存它。您可以在.NET中使用System.Drawing.Bitmap。不幸的是,如果图像是JPEG,则重新保存会损失图像质量,因此如果您需要保留完全原始的图像,则这不是一个好的方法。 - bobince
我想我可以使用像Amazon S3这样的服务来存储图像。我猜这会减轻大部分风险?(特别是我的服务器与图像文件没有任何关联的事实)。 - keyboardP
是的。注入到该安全上下文中的内容将无法影响您的站点。您仍然面临人们上传利用文件来尝试黑客攻击彼此浏览器的常见风险,但这不是针对您的站点的直接攻击(通常也没有太多可以做的)。 - bobince
添加边框比裁剪或缩放对图像的干扰要小。 - Mark Ransom

5

这是个绝对的雷区。以下是一些需要考虑的内容(并非详尽无遗,不做任何保证等):

  • 有些人会使用正则表达式来解析文件,因此无法知道文件是否包含代码。ZIP 文件将其目录放在末尾。现在 Sun/Oracle Java PlugIn/WebStart 检查文件是否以 ZIP 当地头部/条目魔术数字开头,以避免“GIFAR”攻击。
  • 从不同的域名提供,以避免同源问题。
  • 从不同的 IP 地址提供,以避免同源问题。
  • 检查文件是否利用了例如 0-day 缓冲区溢出漏洞等问题有点棘手。它甚至可能利用无限循环来创建 DoS。
  • 最好重新编码图像。
  • URL/文件路径名称要小心。如果可以选择,请使用白名单检查。特别是 NUL 字符会很“有趣”。还请注意目录遍历攻击。总体而言,在已知位置放置特定内容的文件至少也是十分危险的。
  • 或者如果是图像,您可能需要检查大小是否合理。解压巨大的图像很可能导致 DoS。此外,请注意压缩算法通常可以通过巨大的因数压缩微不足道的数据。

谢谢。目前,我只能将图像存储在同一服务器系统上。然而,在向用户显示图像之前,我很乐意以任何方式操作它。这样做是否会减轻主要问题?谢谢。 - keyboardP
@TenaciousImpy:在我不太专业的意见中:如果你足够隐蔽,你可能可以通过重新编码(可能在chroot监狱中)并小心处理URL来逃避检测。请注意,可以配置单个服务器具有多个IP地址(多主机),以及多个主机/域名。但最好不要采纳我的意见。 - Tom Hawtin - tackline

4
不要让用户决定将在您的服务器上使用的文件名。请改用[生成的guid].jpg,并将他们使用的文件名放入数据库表中(如果需要)。参见此处的#12:http://www.codinghorror.com/blog/2009/01/top-25-most-dangerous-programming-mistakes.html 当您在构建文件名时使用外部输入时,结果的路径可能会指向预期目录之外。攻击者可以结合多个“..”或类似序列,使操作系统导航到受限目录之外。其他与文件相关的攻击可以通过外部控制文件名来简化,例如符号链接跟随,这会导致您的应用程序读取或修改攻击者无法直接访问的文件。如果您的程序正在以提高的权限运行并接受文件名作为输入,则同样适用。对于URL和允许外部人指定任意URL也适用类似规则。
URL也要小心,确保它是绝对的、外部的URL,这样他们就不能使用您自己的Web服务器将机密文件从LAN复制到他们可以访问的区域,因为您将从在您的Web服务器上运行的代码加载该URL。

谢谢,我将使用正则表达式来确保它不是来自我的域名(或相对路径)。数据库将保存图片的链接,而不是图片本身(适用于那些仅提交URL链接而不上传图像的人)。 - keyboardP
对于上传的文件,我建议在数据库中存储您分配给文件的Guid,而不是“图像链接”(我想您指的是“UNC路径到图像”)。这样,您可以轻松地采用不同的图像存储目录方案,例如,基于将guid分割为三元组的子目录,以避免一个目录中有太多文件。 - Ian Mercer

0

您可以使用基础设施即服务来处理图像,例如我们的解决方案 - Uploadcare:

https://uploadcare.com

如果您对上传的图像应用任何图像操作,它将被修改,因此文件中嵌入的任何代码都将被破坏。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接