通过Web方式访问的时候,Content-Type是文件类型最权威的描述。此时文件扩展名在大多数情况下都会被忽略。

HTTP 1.1规范

只有在完全没有Content-Type响应头时,接收方才可能需要根据网页的内容并结合资源定位URI后缀,去主动检测传输的媒体类型。

正文开始前的游戏

在web服务器新建文件demo.abcde,并写入如下代码,然后浏览器访问。

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title></title>
</head>
<body>
    <h2>HelloWorld</h2>
</body>
</html>

此时你将会看到如下这种景观。

fun.png

是的,后缀是.abcde的文件被当作了html文件解析。

当然,如果里面包含恶意的XSS Payload时,依旧可以。

如果你感觉并不惊讶,一切尽在掌握,那么便可以跳过这篇文章了,但是如果你有些恍然,那么你可以继续读下去,来获取答案。

内容嗅探机制(content sniffing)

  1. 浏览器会检查文件的静态特征,与已知的文件格式进行对比,推测文件类型;
  2. 不符合格式特征的文档,如HTML文件,会扫描文件的内容,查找特定的子字符串(如寻找熟悉的标签<body> <font>等等);
  3. 有些浏览器还会考虑URL里路径部分的文件后缀。

浏览器之间的解析差异

以HTML文件来说,在进入浏览器的内容检测机制后,

Chrome和Firefox会自动检测在文件起始位置有没有发现某几个预定义的HTML标签;

Firefox只要碰到URL里面有.html这样的文件扩展名,就会急切的把文档判断为HTML类型,即使没有发现可以识别的标签代码。

IE浏览器,默认的就会把文档归为HTML格式处理。

Opera浏览器,会扫描数据里面的前1000个字节,看是否有能识别的HTML标签。

如何迫使浏览器进入内容嗅探阶段

格式错误的MIME Type写法

从服务器端返回的MIME类型写法无效时,浏览器也可能会主动去猜测页面类型。

Content-Type响应头的值由斜线分隔

Content-Type: 类型/子类型[;charset=编码方式]

Image/png

  1. 当缺少中间写斜线时,几乎所有浏览器都会主动去猜测内容的类型。
  2. 在类型位置,如果包含空格和某些控制符时,也会启用内容检测。

特殊的Content-Type 值

application/octet-stream

很多web服务器对各种不透明的非Web文件,如供下载的可执行文件活归档文件,如果没有更合适的Content-Type与之相匹配,都会默认把他们归到application/octet-stream类型。

经过测试当访问如下文件时,edge与ie浏览器仍然会进入内容嗅探机制,最终当作HTML解析。

而其他浏览器,Firefox、Chrome、Opera则会当作附件下载。

<?php
    header('Content-Type: application/octet-stream');
?>
<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title></title>
</head>
<body>
    <h2>HelloWorld</h2>
</body>
</html>
text/plain

某些web服务器会把text/plain作为某些类型响应的默认值。

在旧版本的IE浏览器(IE8及以下),在对这类文档也会通过内容检测来判断类型。

无法识别的Content Type类型

旧版本的IE浏览器(IE8及以下)在碰到浏览器内部原本可以识别的文件格式,但是出于为止的原因该文件不能被正常解析时,浏览器会进入内容嗅探机制。

例如文件是图片格式,但是内容却是HTML代码,此时浏览器无法正确解析时,会进入嗅探机制,因此会当作HTML文件进行解析。

直白一点,在web服务器上新建一个文件,demo.png,然后写入上面重复很多次的HTML代码。

然后用低版本的IE浏览器访问(IE8及以下),依旧会当作HTML解析。

png.png

[NOTE] 推荐一款工具IETester,一个ie浏览器多版本测试工具。

其他非HTTP内容

当通过file协议ftp等协议访问文件时,是不存在Content-Type字段的。

对file协议的文件处理,完全依赖于文件扩展名的信息和内容嗅探。

当通过ftp协议访问文件时,大多数浏览器都不太关心文件扩展名,直接进入内容嗅探阶段。

唯一的例外是Opera,扩展名优先级永远高于内容嗅探。

完全陌生的文件扩展名

对于完全陌生的文件扩展名,则会有两种处理方式。

  1. 注册给外部程序处理的其他扩展名,IE浏览器通常会启动外部程序来打开这些文件,但大多数其他浏览器会启用内容检测。
  2. 如果是一个完全陌生的扩展名,那么所有的浏览器都会启用内容检测机制,情况和这些文件是通过HTTP形式加载且没有哦content-type设置时的处理一模一样。

也正是文章开始前的那个小游戏那样,几乎所有浏览器都会启用内容检测机制。

防御措施

Content-Type

通过Web方式访问的时候,Content-Type是文件类型最权威的描述。此时文件扩展名在大多数情况下都会被忽略。

X-Content-Type-Options

X-Content-Type-Options: nosniff

禁用浏览器的内容嗅探机制。

Content-Disposition

将数据体设定为附件

Content-Disposition: attachment[;filename="文件名"]

此时大多数浏览器在碰到这个响应头时,不会直接解析或显示其返回的数据,而是显示文件下载对话框。


本文由 TEag1e 创作,采用 知识共享署名 3.0,可自由转载、引用,但需署名作者且注明文章出处。

还不快抢沙发

添加新评论

icon_redface.gificon_idea.gificon_cool.gif2016kuk.gificon_mrgreen.gif2016shuai.gif2016tp.gif2016db.gif2016ch.gificon_razz.gif2016zj.gificon_sad.gificon_cry.gif2016zhh.gificon_question.gif2016jk.gif2016bs.gificon_lol.gif2016qiao.gificon_surprised.gif2016fendou.gif2016ll.gificon_mrgreen.pngicon_neutral.pngicon_twisted.pngicon_arrow.pngicon_eek.pngicon_smile.pngicon_confused.pngicon_cool.pngicon_evil.pngicon_biggrin.pngicon_idea.pngicon_redface.pngicon_razz.pngicon_rolleyes.pngicon_wink.pngicon_cry.pngicon_surprised.pngicon_lol.pngicon_mad.pngicon_sad.pngicon_exclaim.pngicon_question.pngicon_rolleyes.gif2016gz.gif2016kun.gif2016zhem.gif2016am.gif2016kel.gificon_twisted.gif2016lh.gificon_neutral.gif2016ka.gif2016tx.gificon_evil.gif2016bb.gif2016yun.gif2016qq.gif2016baojin.gificon_confused.gif2016kk.gif2016zk.gif2016kb.gificon_mad.gif2016yhh.gificon_exclaim.gif2016xia.gif2016gg.gif2016qd.gificon_smile.gif2016lengh.gificon_biggrin.gif2016bz.gif2016wq.gificon_eek.gificon_arrow.gificon_wink.gif2016tuu.gif