【51CTO.com 独家特稿】IE有一个特性,那就是在将一个文件展示给用户之前会首先检查文件的类型,这乍看起来并没什么问题,但实际上这是相当危险的,因为这会允许IE执行图片中的代码,即嵌入在一个图像中的JavaScript代码。引入MIME sniffing功能的初衷是用来弥补Web服务器响应一个图像请求时有可能返回错误的内容类型信息这一缺陷。
但是事不遂人愿,心怀不轨的人可以轻易滥用这一特性,如通过精心制作一个图像文件,并在其中嵌入可以被浏览器所展示和执行的HTML和JavaScript代码。本文将深入考察该问题,并为用户和网站开发人员介绍如何降低此问题带来的风险。
一、危险的MIME sniffing功能
对于Web 2.0应用程序来说,允许用户上载图像是一项基本的要求。但是,IE用户面对这些图片时却要小心了,因为IE的某些功能会为利用图片进行跨站点脚本攻击大开方便之门。
虽然许多大型站点都设法保护其访问者免受可能的JavaScript攻击,例如实现专门用于防御活动内容的过滤器等,但是他们却无法跟活动内容一刀两断,因为对于个人简介、博客和论坛来说,JavaScript、HTML 代码和Flash小应用程序是不可或缺的活动内容。
此外,大部分交互型站点都允许用户上载和链接他们的图片,但是攻击者却可以利用此功能来颠覆IE为保证兼容性和提供额外的安全性而引入的某些功能。攻击者只需在图像的开头部分嵌入一些HTML代码和JavaScript,那么当IE打开这个做过手脚的图像时,浏览器所做的不是显示图像,而是检测并运行图像中嵌入的代码。
之所以出现这种情况,是因为浏览器可以用来确定文件类型的方式多种多样,例如文件扩展名jpg可以指出一个图像为JPEG格式,此外Web服务器还可以在HTTP报头中定义Content-Type(在本例中为image/jpg),但是一般说来使用上载的文件的文件名扩展部分来指出文件的类型。
最后,大多数 Web 浏览器还会检查一个文件的开始几个字节(即通常所说的文件的“签名”),这几个字节通常为一些众所周知的字节序列,例如PNG、PK、JPEG、JFIF等等。
迄今为止,我们介绍了浏览器可以确定文件内容类型的三种方法,即通过文件本身的扩展名或文件开头部分的签名,或通过服务器响应报头Content-Type来确定文件类型。
不过,后来IE4引入了第四种方法,即通常所说的MIME sniffing或者MIME类型检测方法。所以,现在的IE版本都不自动地假定来自web的文件的内容类型就是服务器在HTTP报头中的所声明的内容类型。IE浏览器既不信任文件名扩展部分,也不信任签名,相反,它是通过检查文件开头的256字节内容来确定文件的类型。
然而,只有当用户直接调用URL下载文件时IE才这样做。当使用IE打开HTML中的图像标签(IMG)所连接的本地存储的文件或者图像的时候,则不会进行嗅探。
IE引入MIME sniffing功能的初衷是用来提防服务器给出的错误内容类型指示的,但是攻击者却利用它来规避IE中的安全防御功能,即防止浏览器自动地执行所下载的文件(如hta文件)的那些功能。
此外,MIME sniffing还使得浏览器能够容忍在Content-Type声明中的偶然性错误,例如,如果服务器声明某文件类型为text/plain文件,然而实际提供的却是一个HTML文件,那么IE将它作为HTML处理。
对于常见的GIF、JPEG和PNG格式,只要文件扩展名、Content-Type和签名所指的类型相一致,那么浏览器就会对MIME sniffing所得到的结果置之不理。只有当文件扩展名、Content-Type和签名所指的类型有出入时,IE才会以MIME sniffing所确定的结果为准。
二、倒打一耙的MIME sniffing功能
现在,如何保护用户免受恶意服务器的侵害与如何为不正确地配置服务器的管理员提供有效帮助已经成为Web 2.0所面临的一大问题。 如果文件的扩展名、Content-Type和签名相抵触,那么浏览器会以内容为准。
所以,如果一幅图片的开头部分为一些HTML代码的话,虽然乍一看好像是无害的,但是实际上却可能相当危险,因为IE会执行图片中的代码。这为攻击者把JavaScript嵌入图像提高了一个机会,所以他们可以利用这种方式执行跨站点脚本攻击,使用精心制作的图像来窃取受害者在当前访问的服务器上的身份验证cookie,然后以受害者的身份登录到那个服务器。
三、援兵未至
微软公司已经认识到这个问题,并计划IE的新版本中加以修复。IE8不再探测图像,因此,它会忽略嵌入的HTML。此外,对于特定的下载,还可以通过为私有的Content-Type以及authoritative指定值来关掉MIME sniffing功能,例如content-type=text/html; authoritative=true;。然后,IE会把文件当作服务器指出的类型来处理。
关键情况下,可以使用新的“X-Download-Options: noopen”头部来确保在站点上下文的外部显示相应的文件,这意味着即使HTML文件也能够安全的投递,因为浏览器只是将文件保存起来而已。遗憾的是,IE8要想全面替代其他版本的IE尚需时日,在此之前,Web站点对此还是指望不上的。
四、急救措施
实际上,如今想要抵挡这些精心制作的文件也并非难事。自Windows XP SP2以来,用户已能禁用IE中的MIME sniffing功能,方法是打开浏览器的“工具”菜单中选择“Internet 选项”,点击“安全”选项卡,在“请为不同的区域的Web内容指定安全设置(z)”下面选择“Internet”图标,在“该区域的安全级别(L)”下面点击“自定义级别”按钮,最后启用“基于内容打开文件,而不是文件扩展名”选项即可。然而,这样做会重新开放一些以前的古老漏洞!
这是否能够提供安全性只能够靠实践来证明。我们的重点不应该放在在用户间推广这个技巧,而是应该设法让web服务应用提供安全保障措施来保护访问者,并确保Web服务提供方的系统不向用户传送精心制作的图像。
管理员可以使用脚本检查上传到其服务器中的文件的类型的一致性。举例来说,如果某图像的文件名扩展部分为.jpg,并且文件起始字节部分的签名也指出是相同的类型(在Linux下可以使用file image.jpg命令,而在PHP中可以使用getimagesize加以印证),经过上述验证后,服务器才能发出该文件。
这样,即使文件包含HTML 代码,IE也不会执行这些代码。然而要注意的是,通过这种方式只能保护图像的安全,同时服务器声明的Content-Type必须完全正确才行。 这个方法对其它格式均不起作用。
然而,要想达到绝对的可靠性,需要检查文件的前256字节是否HTML 代码。IE使用常见的〈body〉、〈head〉、〈html〉、〈img〉、〈script〉等等标签来识别HTML代码。如果在文件的前256字节中没有发现任何标签的话,微软的浏览器就无法解释该文件了。
管理员也可以这样配置服务器,当文件被下载(而非打开)时,服务器总是发出头部“Content-disposition: attachment; filename="〈filename.ext〉”。 这样就能防止浏览器在该站点的上下文中打开此文件,而是使用本地链接的应用程序来打开此文件,但是这样做会使用户感觉很不爽。 遗憾的是,这种头部重写技术只对那些不允许直接访问文件的用户有效。鉴于此,所上传的文件的存储位置不应该位于可公开访问的地方,并且最好为文件随机命名。
实际上,最有效的方法是使用ImageMagick或者类似的工具来转换图像文件的格式。这能从图像中清除掉所有代码段,从而彻底摆脱这些代码为用户带来的威胁。像Facebook和Twitter这样的大型站点会对用户上传的肖像照片进行转换,但是必须小心行事,因为这有可能打开另一个攻击方式。例如,如果某人在ImageMagick中发现了一个缓冲区溢出问题,那么攻击者可能进行一番尝试,并找到一种利用特制的相片来利用该问题的方法。
五、总结
MIME sniffing功能本是IE的忠诚卫士,谁知他如今突然“倒戈”,助纣为虐来危害IE用户。对策当然是有,但是这些对策是否靠谱却是个悬而未解决的问题。目前,通过图像发动的跨站点脚本攻击看起来还不太常见,但是世界正在发生急剧的改变:交互型网站正在变成犯罪的首选目标。好在,我们还可以使用其它的浏览器,例如Firefox等,这倒不失为一个补救措施。当然Firefox也进行MIME sniffing,但是它却不会莫名其妙地将图像作为HTML进行解释。
【编辑推荐】