普通的 XSS,是经过服务端(好比模板技术)将数据输出到 HTML 中。而 DOM Based 类型 的 XSS,是经过 JS 将数据输出到 HTML 中。javascript
请看下例:java
<script type="text/javascript">
var x='<来源于 input 输入框>';
document.write("<a href='"+x+"'>demo</a>")
</script>
复制代码
这里的 x 变量,其值来源于用户所输入的内容。网站开发者使用普通 XSS 的防护方法(DefaultEncoder.getInstance().encodeForJavaScript(str)
)对该变量进行编码,以免 XSS 攻击。bash
假设,攻击者使用 'onclick=alert('dom_based_xss');//'
做为输入内容,那么通过 encodeForJavaScript 编码,变量 x 变为这样:cookie
<script type="text/javascript">
var x='\x27onclick\x3Dalert\x28\x27dom_based_xss\x27\x29\x3B\x2F\x2F\x27';
document.write("<a href='"+x+"'>demo</a>")
</script>
复制代码
攻击结果:dom
难道 ESAPI 也防护不了基于 DOM Based 类型的 XSS 攻击了吗?咱们来分析分析。xss
这是由于 encodeForJavaScript 只能保护 JS。而编码过的恶意脚本,经过 document.write()
方法输出到 HTML 页面时,又会被解码还原回去,从而致使 XSS 攻击成功。网站
那是否对上述场景应用 HtmlEncode 就解决问题了呢?请看下面这一段代码:ui
var y=xxx'; document.write("<a href=# onclick='alert(\""+y+"\")'>demo2</a>");
复制代码
假设攻击者编写的攻击字符串是这样的:正常逻辑");alert('dom_based_xss');///
,通过 HtmlEncode 编码为:正常逻辑");alert('dom_based_xss');///
编码
攻击结果: spa
第一次仍然会执行正常逻辑,第二次就被 XSS 注入攻击咯。因此单纯使用 HtmlEncode 编码,仍然防不住被攻击。
终极防护方法为:输出到 <script>
时,先使用 encodeForJavaScript 对其编码。而后在 doucment.write() 方法中作判断,若是是输出到 HTML 页面,则再使用 encodeForHTML 二次编码;若是是输出到 JavaScript,则使用 encodeForJavaScript 二次编码。这样,才能确保万无一失。
可能发生 DOM Based 类型的 XSS 攻击,有如下这些方法:
如下这些地方有可能成为 DOM Based 类型的 XSS 攻击字符串的注入点,也须要注意防范: