前言
首先这里为什么要讨论DOM XSS而不是比较常见的反射型XSS和存储型XSS,因为基于DOM XSS原理和利用场景,服务端过滤及客户端转义的防护手段并不能完全适用于DOM XSS。
DOM XSS原理
与反射型XSS、存储型XSS的区别就在于xss代码并不需要服务器解析响应的直接参与,触发XSS靠的是浏览器端的DOM解析。
例如如下代码:
<script>
("a").innerHTML="yyyyyy";
</script>
如果yyyyyy内容是请求过来的参数,那么攻击者就可以通过构造请求的参数完成DOM XSS攻击。
其实DOM XSS的形成原因及其它的难防护性,与浏览器对DOM的渲染有很大关系。
JavaScript与HTML自解码机制
首先来看样例1,如下
<input type="button" οnclick="('<img src=@ οnerrοr=alert(1) />')" />
当执行时,会弹出提示框,如下图
说明JavaScript执行之前,HTML形式的编码会自动解码。这样的编码形式有以下两种:
- 进制编码:&#xH;(十六进制格式)、&#D;(十进制格式),最后的分号(;)可以不要
- Html实体编码
样例2,如下
<script>
("a").innerHTML="<img src=@ οnerrοr=alert(1) />";
</script>
并没有弹出提示框,如下图:
这段HTML编码的内容在JavaScript执行之前并没有自动解码,因为用户输入的这段内容上下文环境是JavaScript,不是HTML(可以认为<script>标签里的内容和HTML环境毫无关系),此时用户输入的这段内容要遵守的是JavaScript法则,即JavaScript编码,具体有如下几种形式。
- Unicode形式:\uH(十六进制)
- 普通十六进制:\xH
- 纯转义:\'、\"、\<、\>这样在特殊字符之前加\进行转义
通过以上两个例子,知道了HTML和JavaScript自动解码的差异,如果防御没有区分这样的场景,就会出现问题。
在HTML标签中,有些标签是不会解析的,例如:
<textarea>
<title>
<iframe>
<noscript>
<noframes>
<xmp>
<plaintext>.
防护方案
1.在输入点过滤敏感关键字
=encodeHTML([输出])