1

我正在设计的站点允许用户将图像( 、 或 )上传PNGJPEGGIF的后端中的 servlet。这是我迄今为止在安全方面所取得的成就......

  1. 通过检查文件扩展名来验证图像客户端。如果扩展有效,则将其发送到 servlet 以进行后端验证。
  2. 验证图像的 MIME 类型并确保它是image/jpegimage/gifimage/png
  3. 读取图像的前 10 个字节,将它们转换为十六进制,并验证十六进制与aPNGJPEGGIF匹配。这是用户上传 PNG - 时我得到的神奇数字的示例89 50 4E 47 0D 0A 1A 0A

所以服务器端的 mime 和幻数验证,以及客户端的扩展验证。一切都很好,但我有两个简单的问题......

  1. 既然我已经在检查 mime 和魔法,是否有任何目的将文件名发送到 servlet 以检查扩展服务器端?
  2. 在安全性方面我还应该做些什么,你会改变我目前的方法吗?

并且请不要对任何安全步骤说“我认为没有必要”,因为我的首要目标是学习。因此,即使我的网站存在风险的可能性只有 0.001%,我仍然想学习保护自己的最佳方法。谢谢你。

4

2 回答 2

2

通过检查文件扩展名来验证图像客户端。如果扩展有效,则将其发送到 servlet 以进行后端验证。

对于非 Windows 用户,这可能会失败,他们的文件类型不一定由文件名的扩展名决定。

添加 JS 警告说“此文件不以 .png/.gif/.jpeg/.jpg 结尾 - 你确定它是图像吗?”可能很有用,但通常不允许基于扩展的上传。

验证图像的 mime 类型并确保它是 image/jpeg、image/gif 或 image/png。

这里再次存在一些问题。在 Windows 上,MIME 类型是从注册表关联中检索的,这些关联是可变的,并不总是正确的。例如,IE 通常以 JPEG 格式发送 JPEG image/pjpeg,Citrix 用户可能会发现它们以image/x-citrix-pjpeg.

由于上传脚本通常不使用媒体类型,因此阅读/检查它几乎没有意义。对于这里的类型,我想说你最好的选择是忽略文件名和 MIME 类型;仅使用幻数嗅探来确定格式。

在安全方面我还应该做什么

1) 小心你使用什么名称来存储文件 - 由于目录遍历、特殊文件名和扩展名(等),逐字获取用户提交的文件名是危险的.htaccess.jsp并且因为文件命名规则可能是复杂的跨平台而不可靠。

如果您想在本地文件系统上使用提供的名称,它应该是基本名称、slugified(替换除了简单字符的白名单之外的所有内容)、长度限制以及从检测到的文件类型替换/添加的扩展名。

更好的是使用完全生成的名称存储文件(例如17264.dat,与数据库中主键为 17264 的项目相关的文件);如果您需要将其提供给具有漂亮文件名的浏览器,您可以在前端 Web 服务器或文件服务 servlet 上使用重写,使其以/images/17264/some_name.png.

2)仅仅因为它具有图像幻数并不意味着它一定是图像,或者即使它有效图像,它也不会同时具有不同形式的其他内容(“变色龙”文件)。

例如,二进制文件中的类似 HTML 的内容可以欺骗旧版本 IE 中狡猾的 MIME 嗅探,将其视为 HTML。类似地,Flash 可能会被欺骗以<crossdomain>在图像中加载由 XML 设置的策略集,而 Java 可以加载也是 GIF 的小程序。

使这变得更加困难的一种方法是使用服务器端图形库加载图像,然后重新保存它,导致一轮重新压缩,这通常会使文件中的任何可解析内容出现乱码。这样做的问题是像JPEG这样的有损压缩,其中重新压缩会导致视觉质量下降。

最终的解决方案通常是放弃并将图像从完全不同的主机名提供给主站点。然后,如果攻击者设法将一些 XSS 内容放入文件中,那也没关系,因为它所在的站点上没有任何东西可以破坏,只有其他静态图像。

3) 如果您出于 (2) 或其他原因在服务器端加载图像,请确保图像大小(文件大小和宽度/高度大小)在尝试加载之前是合理的。否则,您可能会被填满内存并导致拒绝服务的减压炸弹击中。

此外,如果您这样做,请确保使您的图像库/语言(例如 Java Graphics2D)保持最新。这些语言之前存在图像处理漏洞。

于 2013-05-03T23:11:39.093 回答
1

我喜欢你的问题!第一步、第二步和第三步非常适合安全性。干得好!

1) 由于我已经在检查 mime 和魔术,是否有任何目的将文件名发送到 servlet 以检查扩展服务器端?

不,不是。扩展名是一个无意义的标记,仅在尝试解释文件中包含的数据时才有价值。即使是新手攻击者也可以轻松绕过您的客户端验证,但我仍然会这样做,因为您不仅可以通过淘汰最不称职的脚本小子来节省一些带宽,而且您还可以向诚实的用户提供更快的错误消息错误。您正在检查“幻数”服务器端,这是正确的方法。这并不意味着没有恶意代码,但它确实使嵌入恶意代码变得更加困难。你永远不会永远阻止精英,但你可以放慢他们的速度并阻止其他人。

2) 在安全性方面我还应该做些什么,你会改变我目前的方法吗?

你目前的方法很好。我会考虑添加在客户端和服务器端强制执行的文件大小限制。客户端很容易被击败,但它再次为您节省了带宽并花费了攻击者的时间。除非您正在构建照片编辑应用程序或类似的东西,否则图像不应超过几 MB。

我要注意的其他事情是您处理照片的应用程序。一些照片程序中存在漏洞,如果使用该应用程序打开照片,攻击者可以通过这些漏洞获取远程 shell 到您的服务器。这种情况很少见,但确实会发生(这属于您 0.001% 的机会)。因此,请谨慎处理您为处理照片而编写的任何代码,以及您允许打开它的任何应用程序。这是一个深刻的主题。如果您想了解有关编写安全代码的更多信息,我强烈推荐Robert Seacord 的 Secure Coding。我不仅学到了很多关于代码安全的知识,而且还编写了更少的错误代码。

于 2013-05-03T01:28:25.967 回答