xss 一点总结
xss 一点总结
我不是很理解 xss 这个词: Cross-site scripting ,它怎么就跟跨站勾搭上了呢?
xss 输入/输出
网页是xss的舞台,要达成 xss 攻击,首先必须找到页面中可以注入代码的地方(注入点),而且网页必须要有执行注入代码的地方(输出点)。
发现 xss 漏洞的一种方法就是在所有用户输入的地方输入一些特殊字符(字母和数字的随机组合,方便与正常文本区分开),看看页面有没有展示这些特殊字符,如果没有那肯定没戏了,如果有还可以继续测试。
xss 类型
先看看 xss 类型。根据 要不要与后台交互 和 会不会保存到数据库 大致可以分为不需要与后台交互的 DOM XSS ,需要与后台交互但不会被保存到数据库的 反射型XSS ,以及会把注入代码保存到数据库的 存储型 XSS 。因为存储型XSS可以一处存储,多处显示,所以危害比较大。
输出场景/编码方式/解码顺序
之前说页面展现特殊字符可以继续测试。特殊字符可能出现的地方,有:
- HTML 标签之间
<div>[输出]</div>
- HTML 属性值
<input value="[输出]">
- javascript 代码里面
<script type="text/javascript">val = [输出]</script>
- CSS 代码里面
<style type="text/css"> body {height: [输出]px;} </style>
为什么要区分不同的地方呢?这与不同语境下不同的编码以及浏览器的解码次序有关。
先来说说编码:
- HTML 支持实体编码(如
<
就是 ‘<’),十进制(<)、十六进制(<)ASCII编码,以及unicode字符编码(<)。 - javascript 支持 八进制(\74)、十六进制(\x3c)ASCII编码,以及 unicode字符编码(\u003c)。
- CSS 支持十六进制ASCII编码(#fff 可以写成#\66\66\66) 以及 utf-8 编码(\0066)。
- URL 支持十六进制ASCII编码 以及 utf-8 编码 和 GB2312 编码 或者还有更多。
在不同的语境下用其支持的编码有时候可以绕过后台的字符过滤。能不能绕过,得测试很多种情况,所以要借助工具。
浏览器获取源码之后,一边解析一边执行源码:
-
一开始解析 HTML 代码,如果遇到 script 标签,停止解析 HTML ,开始解析 script 内容(如果要加载远程代码,一般情况下——没有加 defer ;浏览器不作优化——在加载完成后解析),解析完毕后,继续解析 HTML 。解析 HTML 时,同时也在解析 CSS 。因为 javascript 有可能会读取样式,在解析 CSS 时怎样处理 javascript ,各浏览器有不同的实现,详见how browsers work。
-
解析 HTML 时,如果遇到标签属性中的事件句柄,如 onclick ,会先当作 HTML 代码解析,在事件被触发时,再调用脚本解析器解析。
比如下面这行代码:
<button onclick="location.href = 'http://www.yoursite.com?userName=<%= userName %>';">redirect</button>
用户输入的 userName 到达浏览器之后,首先会被当作 HTML 解析,当 click 事件触发之后,又会被当作 script 解析,因为是 url 的一部分,最后还会被当作 url 来解析。
为了不出乱子(即把用户的输入当作当前环境下的代码执行),后台对 userName 的编码将是浏览器解码的逆过程,先是 url 编码,再是 script 编码,最后是 HTML 编码。
-
解析 script 时,也有可能调用 HTML 解析器解析代码。这时先进行 script 解析,再进行 HTML 解析。
比如下面的代码:
<scirpt> var div = document.createElement('div'); div.innerHTML = "\x3cimg src=1 onerror=alert(1)\x3e"; // 与 div.innerHTML = "<img src=1 onerror=alert(1)>" 效果一样 // 试试 div.innerHTML = "<img src=1 onerror=alert(1)>" // 试试 div.innerHTML = "<script alert(1);" 为什么不执行? //document.body.appendChild(div); 不用 append 到页面中 </script>
会弹出提示窗。不是所有 DOM 元素调用其 innerHTML 方法都会像上面一样弹窗,比如 textarea 就不会。
具体编码方式
-
待编码的内容在 HTML 标签之间,只需要对以下字符编码即可:
字符 编码结果 & & < < > > ” " ’ ' / / ` ` - 待编码的内容在 HTML 属性里面,不包含事件句柄属性的情况
- 除去数字和字母,用
&#xHH;
( HH 是该字符对应的十六进制数) 格式(也可以是实体编码,如果有的话)编码其他 ASCII 码小于 256 字符。 - 还要记得用引号把属性值括起来。
- 除去数字和字母,用
- 待编码的内容在 HTML 事件句柄属性或在 javascript 里
- 除去数字和字母,用
\xHH
( HH 是该字符对应的十六进制数)格式编码其他 ASCII 码小于 256 字符。 - 若在 javascript 里,还要记得用引号把属性值括起来。
- 除去数字和字母,用
- 待编码的内容在 CSS 代码里面
- 除去数字和字母,用
\HH
( HH 是该字符对应的十六进制数)格式编码其他 ASCII 码小于 256 字符。
- 除去数字和字母,用
- 待编码的内容在 URL 里面
- 除去数字和字母,用
%HH
( HH 是该字符对应的十六进制数)格式编码其他 ASCII 码小于 256 字符。 - 还要记得用引号把属性值括起来。
- 除去数字和字母,用
未尽事宜
XSS 漏洞是网络攻击的第一步,黑客可以利用漏洞加载远程脚本、盗取用户信息(cookie),再配合 CSRF 实施进一步攻击。