html()和innerHTML的注意事项

作者:简简单单 2016-08-29


jQuery 是最常用的一个 JavaScript 库,其中的 element.html() 是一个将 HTML 代码插入某元素的方法,而 element.innerHTML 是 JavaScript 原生的插入方法。

以前,因为没有使用的需求,所以一直单纯地认为 jQuery 的 element.html() 只是对 element.innerHTML 的一个简单封装,但是昨天,发现事情并没有这么简单。

 

老师说过,写文章要有起因、经过、结果,所以先说说故事起因。

 

起因

小伙伴在某企鹅网站上发现一个存储型 XSS 漏洞,因为他对前端不了解,所以叫我来帮忙绕过滤。该页面不仅会对输入内容进行过滤,并且有最高 50 字符的字数限制,虽然没有了解到完整的过滤规则,但是经过简单的测试发现过滤比较鸡肋,连


 
 


 

写好剧本:

1、打开 index.html(需要 HTTP Server);

2、页面自动发起 Ajax 请求,获取 index.txt 中的内容并加入 div 中;

3、最后自动执行 ,也添加到了 DOM 中,但是就如同写入的是文本一样,完全不执行任何代码。

 

Google 一下,你就知道:

在 window.onload 触发前,通过 element.innerHTML 写入的脚本会正常执行,但是 window.onload 已经被触发后再加入脚本,就不会再自动执行了。

怎么办,正常情况下可以直接使用 eval() 执行脚本,虽然不怎么安全,但也是一种解决方法。但是在日站这种非正常情况下,就得另辟蹊径了。

 

别忘了,还有一个方法,是 document.write(),这个方法没有 element.innerHTML 好用,因为前者每次都会重写整个文档流,引起整个页面的重流,但后者可以对某个具体的元素的内容进行更改,也就不会重流整个页面了。虽然这个方法可以执行脚本,但是后果就是整个页面只剩下写入的内容,其他包括 、 统统都没了。所以想要不破坏页面,还是少用它吧。

 

zepto.js 测试

打开页面应该做的第一件事应该是右键查看源代码。——沃兹吉·硕得

本人贯彻上述真理,当然在第一时间了解到有漏洞的页面是使用了 zepto.js 库。

zepto.js 是一个轻量级的类 jQuery 库,其也是使用 $ 符号,而且很多功能实现与 jQuery 一致。OK,把代码改吧改吧,用 $.ajax 获取脚本看看会不会执行。

 

修改后的代码长这样:




 






 
 


 

不同于使用原生 JavaScript 的没有任何反应,zepto 给足了面子,立刻弹出了 “index.txt” 字样的对话框。

哟西,内联的 JavaScript 代码执行成功,那引用外部的脚本那也是可以的吧?