6.5 字符集缺陷导致的 XSS
有些安全问题的罪魁祸首是字符集的使用(即字符集编码与解码)不正确导致的,字符集本身也有一些问题,比如,各种说不清道不明的原因导致字符集之间的交集分歧。如果世界上只有一种字符集,也只有一种编码方式,那么这个字符世界应该就是和平的。
在介绍安全问题前,我们来了解一些基本概念:什么是字符、什么是字节、什么是字符集、什么是字符集编码。
1. 字符与字节
肉眼看到的一个文字或符号单元就是一个字符(包括乱码),一个字符可能对应1~n字节,1字节为8位,每一位要么为1,要么为0。
2. 字符集
一个字符对应1~n字节是由字符集与编码决定的,比如,ASCII字符集就是一个字符对应1字节,不过1字节只用了7位,最高位用于其他目的,所以ASCII字符集共有2的7次方(128)个字符,基本就是键盘上的英文字符(包括控制符)。
ASCII字符集表达不了拉丁系的字符,更表达不了东亚字符,所以各种演变出现了诸多字符集,如ISO8859系列、GB2312、GBK、GB18030、BIG5、Shift_JIS等,直到Unicode字符集出现,才看到了世界和平的曙光,但是各国的这些字符集还在沿用,不可能清零从头开始,所以这个字符的世界还是很混乱。
3. 字符集编码
这些字符集大都对应一种编码方式(比如GBK字符集对应了GBK编码),不过Unicode字符集的编码方式有UTF-8、UTF-16、UTF-32、UTF-7,常见的是UTF-8与UTF-7。
编码的目的是最终将这些字符正确地转换为计算机可理解的二进制,对应的解码就是将二进制最终解码为人类可读的字符。
6.5.1 宽字节编码带来的安全问题
GB2312、GBK、GB18030、BIG5、Shift_JIS等这些都是常说的宽字节,实际上只有两字节。宽字节带来的安全问题主要是吃ASCII字符(一字节)的现象,比如,下面这个PHP示例,在magic_quotes_gpc=On的情况下,如何触发XSS?
<?php header("Content-Type: text/html;charset=GBK"); ?> <head> <title>gb xss</title> </head> <script> a="<?php echo $_GET['x'];?>"; </script>
我们会想到,需要闭合双引号才行,如果只是提交如下语句:
gb.php?x=1";alert(1)//
双引号会被转义成\",导致闭合失败:
a="1\";alert(1)//";
由于这个网页头部响应指明了这是GBK编码,GBK编码第一字节(高字节)的范围是0x81~0xFE,第二字节(低字节)的范围是0x40~0x7E与0x80~0xFE,这样的十六进制表示。而\符号的十六进制表示为0x5C,正好在GBK的低字节中,如果之前有一个高字节,那么正好会被组成一个合法字符,于是提交如下:
gb.php?x=1%81";alert(1)//
双引号会继续被转义成\",最终如下:
a="1[0x81]\";alert(1)//";
[0x81]\组成了一个合法字符,于是之后的双引号就会产生闭合,这样我们就成功触发了XSS。
这些宽字节编码的高低位范围都不太相同,具体可以查相关维基百科。
这里有一点要注意,GB2312是被GBK兼容的,它的高位范围是0xA1~0xF7,低位范围是0xA1~0xFE(0x5C不在该范围内),把上面的PHP代码的GBK改为GB2312,在浏览器中处理行为同GBK,也许是由于GBK兼容GB2312,浏览器都做了同样的兼容:把GB2312统一按GBK行为处理。
上面这类宽字节编码问题的影响非常普遍,不仅是XSS这么简单,从前端到后端的流程中,字符集编码处理不一致可能导致SQL注入、命令执行等一系列安全问题。
6.5.2 UTF-7问题
UTF-7是Unicode字符集的一种编码方式,不过并非是标准推荐的,现在仅IE浏览器还支持UTF-7的解析,比如,Firefox从5版本就不支持UTF-7了。UTF-7的存在是有历史原因的,感兴趣的读可以去维基百科上查阅。
IE浏览器历史上出现以下好几类UTF-7 XSS。
1. 自动选择UTF-7编码
在IE 6/IE 7时代,如果没声明HTTP响应头字符集编码方式或者声明错误:
Content-Type: text/html;charset=utf-8 // 声明字符集编码方式 Content-Type text/html // 未声明字符集编码方式 Content-Type: text/html;charset=uf-8 // 声明错误的字符集编码方式
同时,<meta http-equiv>未指定charset或指定错误,那么IE浏览器会判断响应内容中是否出现UTF-7编码的字符串,如果有当前页面会自动选择UTF-7编码方式,如下:
<title>utf-7 xss</title> +ADw-script+AD4- alert(document.location)+ADw-/script+AD4- <div>123</div>
历史上,Yahoo和Google都因为这个而被XSS漏洞攻击过,它们的POC分别如下:
http://search.yahoo.com/search?p=% 2BADw-/title%2BAD4-%2BADw-script% 2BAD4-alert(document.cookie)%2BADw-/script %2BAD4-&fr=yfp-t-501&togg le=1&cop=mss&ei=UTF-8&eo=euc // 注:euc是错误的字符集编码方式
http://www.google.com/search? hl=en&oe=cp932&q=%2BADw-script%2BAD4 -alert(document.cookie)%2BADsAPA-/script %2BAD4-%2BACI- // 注:cp932是错误的字符集编码方式
这是一种危险的机制,现在已经修补。
2. 通过iframe方式调用外部UTF-7编码的HTML文件
父页通过Content-Type或<meta>标签来声明UTF-7编码,然后使用<iframe>标签嵌入外部UTF-7编码的HTML文件,代码如下:
<html> <meta http-equiv="Content-Type" content="text/html; charset=UTF-7"> <body> <iframe src=" utf-71.html"/> </body> </html>
utf-71.html的代码如下:
<html> +ADw-script+AD4-alert('XSS')+ADw-/script+AD4- </html>
不过现在IE限制了<iframe>只能嵌入同域内的UTF-7编码文件,虽然曾经有通过重定向跳转到外域的方式绕过这个限制。
3. 通过link方式调用外部UTF-7编码的CSS文件
通过<link>标签嵌入外部UTF-7编码的CSS文件,此时父页不需要声明UTF-7编码方式,代码如下:
<html> <title>123</title> <link rel="stylesheet" href="http://www.evil.com/utf7.css" type="text/css"/> </html>
utf7.css可以在外域,代码如下:
@charset "utf-7"; body+AHs-x:expression(if(!window.x)+AHs- alert(1)+ADs-window.x=1+ADsAfQ-)+AH0-
4. 通过指定BOM文件头
BOM的全称为Byte Order Mark,即标记字节顺序码,只出现在Unicode字符集中,BOM出现在文件的最开始位置,软件通过识别文件的BOM来判断它的Unicode字符集编码方式,常见的BOM头如表6-1所示。
表6-1 字符集编码BOM
其中,LE是Little Endian,指低位字节在前,高位字节在后;BE是Big Endian,指高位字节在前,低位字节在后。
相关解析软件如果发现BOM是+/v8,就认为目标文档是UTF-7编码,IE曾经出现的漏洞就是:以最高的优先级判断UTF-7 BOM头。这样只要能控制目标网页开头是UTF-7 BOM头,后续的内容就可以以UTF-7方式编码,从而绕过过滤器。
在实际的攻击场景中,能控制目标网页开头部分的功能如下:
· 用户自定义的CSS样式文件(如:曾经的百度空间)。
· JSON CallBack类型的链接,这类出现在几乎各大Web 2.0网站中。
修补这类安全问题很简单,只要在目标网页开头部分强制加一个空格即可,这样BOM头就无效了。
6.5.3 浏览器处理字符集编码BUG带来的安全问题
历史上所有的浏览器在处理字符集编码时都出现过BUG,这类安全问题大多是模糊测试出来的。在此不打算一一列举,不过有一点需要特别说明的是:标准总是过于美好,比如字符集标准,但是每个浏览器在实施这些标准时不一定就能很好地实施,所以不要轻信它们不会出现BUG。
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论