使用Javascript& A验证图片上传Java的

时间:2013-05-02 23:00:10

标签: java javascript security file-upload

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

  1. 通过检查文件扩展名来验证图像客户端。如果扩展名有效,请将其发送到servlet以进行后端验证。
  2. 验证图片的mime类型,并确保其为image/jpegimage/gifimage/png
  3. 读取图像的前10个字节,将其转换为十六进制,并验证十六进制是否匹配PNGJPEGGIF的{​​{3}}。以下是用户上传PNG时获得的神奇数字示例 - 89 50 4E 47 0D 0A 1A 0A
  4. 服务器端的mime和幻数验证,以及客户端的扩展验证。一切都很好但我有两个简单的问题......

    1. 是否有任何目的将文件名发送到servlet以检查扩展服务器端,因为我已经检查了mime和魔法?
    2. 在安全方面我还应该做些什么,你对我目前的方法有什么改变?
    3. 请不要对任何安全步骤说“我认为这不是必要的”,因为我的首要目标是学习。因此,即使我的网站只有0.001%的可能存在风险,我仍然希望学习保护自己的最佳方法。谢谢。

2 个答案:

答案 0 :(得分:2)

  

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

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

添加一个JS警告说“这个文件不以.png / .gif / .jpeg / .jpg结尾 - 你确定它是一个图像吗?”会很有用,但它通常不是很好想要禁止基于扩展名的上传。

  

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

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

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

  

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

1)注意用于存储文件的名称 - 由于目录遍历,特殊文件名和扩展名(.htaccess.jsp等)而逐字记录用户提交的文件名是危险的,并且不可靠仅仅因为文件命名规则可能跨平台复杂。

如果你想在本地文件系统上使用提供的名称,它应该是basenamed,slugified(替换除了简单字符的白名单之外的所有字符),长度限制,并且从检测到的文件类型替换/添加扩展名。< / p>

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

2)仅仅因为它有图像魔术数字并不意味着它必然是一个图像,或者即使 是一个有效的图像,它也没有其他形式的其他内容同时(一个'变色龙'文件)。

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

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

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

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

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

答案 1 :(得分:1)

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

  

1)是否有任何目的将文件名发送到servlet以检查扩展服务器端,因为我已经检查了mime和magic?

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

  

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

您目前的做法很好。我会考虑在客户端和服务器端强制添加文件大小限制。客户端很容易被击败,但同样可以节省带宽并节省攻击者的时间。除非您正在构建照片编辑应用程序或类似的东西,否则图像的合理范围不应超过几MB。

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