我使用内部工具,允许用户上传图像 - 然后将这些图像显示给他们和其他人。
它是Java / Spring应用程序。我的好处是只需要完全担心IE11和Firefox v38 +(Chrome v43 +会很高兴)
首次开发该功能后,用户似乎可以创建一个文本文件,如:
<script>alert("malicious code here!")</script>
并将其保存为&#34; maliciousImage.jpg&#34;并上传它。
稍后,当图像显示在图像标记内时,如:
<img src="blah?imgName=foobar" id="someImageID">
actualImage.jpg显示正常,且maliciousImage.jpg显示为断开的链接 - 最重要的是没有恶意内容被解释!
然而如果用户右键点击此已损坏的链接,并点击“查看图片”,则会发生错误。
浏览器内容嗅探&#39;一个对我来说不熟悉的概念,可以检测到恶意图像。实际上是一个文本文件,非常友好地毫不犹豫地将其呈现为HTML。任何脚本标记都会传递给JavaScript解释器,您可以想象,我们并不想要这样。
简而言之,我可以想到每个可能的响应标头组合,以防止浏览器内容嗅探。我在stackoverflow和其他文档中找到的所有答案都暗示设置内容类型标头应该可以防止大多数浏览器进行内容嗅探,并且设置X内容选项应该会阻止某些版本的IE。
我将x-content-type-options设置为no sniff,并且我设置了响应内容类型。我读过的文档让我相信这应该会停止内容嗅探。
response.setHeader("X-Content-Type-Options", "nosniff");
response.setContentType("image/jpg");
我拦截了响应并且存在这些标头,但似乎对恶意内容的处理方式没有影响......
我还尝试在上传时检测哪些图像是恶意的,但我很快意识到这非常重要...
当然 - 对于不是真实图像的图像(乱码,无法处理的异常等)的任何输出都比在明文中执行HTML / javascript的文本文件更好,但是显示任何恶意HTML转换/ CDATA&gt;纯文本将是理想的...虽然可能有点不切实际。
答案 0 :(得分:1)
所以我最终解决了这个问题,但忘了回答我自己的问题:
为了快速解决问题,我简单地添加了一些相当生硬的代码,用于检查图像是否实际图像 - 在上传期间和服务之前,使用imageio lib:
import javax.imageio.ImageIO;
//......
Image img = attBO.getImage(imgId);
InputStream x = new ByteArrayInputStream(img.getData());
BufferedImage s;
try {
s = ImageIO.read(x);
s.getWidth();
} catch (Exception e) {
throw new myCustomException("Invalid image");
}
现在,我最初希望这能解决我的问题 - 但实际上并不是那么简单,只是让生成有效载荷变得更加困难。
虽然这会阻止:
<script>alert("malicious code here!")</script>
很有可能生成一个有效的图像,这也是一个XSS有效载荷 - 只需要多一点努力....
事实证明,有一个我从未接触过的整个后期处理工作流程,例如将令牌附加到响应主体并使用其他框架来装饰具有CSS,页眉,页脚等的响应。
这意味着,虽然控制器明确地返回了image / png,但它正被抓取并放置(以字节为单位)后处理采用该字节流,并将其包装在页眉和页脚中,以形成完全限定的&# 39;视图&#39; - 此视图始终具有&#39;内容类型&#39; text / html因此从未正确显示。
这个问题的关键在于我的控制器以RESTful方式直接返回一个图像,当构建框架的其余部分来处理控制器返回完整的视图时。
所以我不得不逐步完成这个工作流程,并在我的代码中为控制器创建例外,这些控制器返回的东西不是以宁静的方式工作。
例如使用site-mesh它只是一个排除(一旦我理解了问题,就像往常一样简单修复......):
<decorators defaultdir="/WEB-INF/decorators">
<excludes>
<pattern>*blah.ctl*</pattern>
</excludes>
<decorator name="foo" page="myDecorator.jsp">
<pattern>*</pattern>
</decorator>
然后是其他一些其他定制的调用后拦截器。
现在,我终于得到了只提供图像字节码的阶段,并且没有指定或明确生成评论。
一个名为“内容协商”的春季功能&#39;踢了进来。它试图调和“接受”。请求的标头,以及&#39; messageconverters&#39;它现在可以产生这样的反应。
因为默认情况下spring不会有一个messageconverter来生成image / png响应,所以它回退到text / html - 我仍然看到问题。
现在,如果我使用弹簧4,我可以简单地添加注释:
@Produces("image/png")
到我的控制器 - 简单修复...
但是因为我只有春季3.0.5(而且无法升级)我不得不尝试其他的东西。
我尝试注册新的消息转换器,但这很令人头疼或添加一个新的post-method拦截器,只需将内容类型更改回&#39; image / png&#39; - 但这是一个hacky头痛。
最后,我刚刚在控制器中公开了请求/响应,并将我的图像直接写入了响应主体 - 完全绕过了Spring的内容协商
.... 终于我的图像被用作图像并显示为图像 - 并且没有执行注入的代码!
答案 1 :(得分:0)
这听起来很奇怪,因为它在其他地方完美无缺。您确定响应中是否存在X-Content-Type-Options标题?
这是我之前构建的一个演示,我有一个有效的html,gif和javascript文件。正如您所看到的那样,它首先作为HTML加载,然后将其自身加载为图像和脚本(执行):
http://research.insecurelabs.org/content-sniffing/gifjs.html
但是,如果使用“X-Content-Type-Options:nosniff”标题加载它,脚本将不再执行:
http://research.insecurelabs.org/content-sniffing/nosniff/gifjs.html
顺便说一下,图像在FF / IE中正常渲染,但在Chrome中没有。
这是一个演示,我尝试了你所描述的内容:
http://research.insecurelabs.org/content-sniffing/stackexchange.html
第一张图片没有nosniff,第二张图片是,它似乎按预期工作。当使用“view image”打开时,第二个不会运行脚本。
修改强>
Firefox似乎不支持X-Content-Type-Options:nosniff
因此,您还应该添加“Content-disposition:attachment; filename = image.gif”或类似于图像。如果通过图像标记加载,图像将正常加载,但如果直接打开URL,则会强制下载而不是直接在浏览器中显示图像。
示例:http://research.insecurelabs.org/content-sniffing/attachment/
答案 2 :(得分:-1)
adeneo非常适合。您应该使用您想要检查的任何图像库,以确定上载的文件是否是它声称的类型的有效文件。客户端发送的任何内容都可以被操纵。