Javascript/jQuery DOM创建是否安全,直到它被添加到文档中?

Gar*_*een 30 javascript security jquery dom

请仔细阅读本声明:在将任何元素添加到$ dom中的document 所有不安全元素之前,我们假设已删除.但他们最初创建.好的,让我们继续....


如果处理了一段用户文本并且可以像这样加载:

var comment = 'I\'m a naughty person!!' +
              '<script src="http://blah.com/some_naughty_javascript.js">';
var $dom = $('<div>' + comment + '</div>');
Run Code Online (Sandbox Code Playgroud)

本身有危险吗?我的观点是,只是创建一个DOM的简单行为以某种方式注入任何东西,或者只是简单地处理并创建结构?

例如:

var $dom = $('<script>alert("hi");</script>');
Run Code Online (Sandbox Code Playgroud)

显然,消息hi不会弹出,直到它被添加到document.但:

  • 任何标签或以这种方式创建的任何东西都可能是危险的
  • javascript/jquery中的任何函数都可以"监视"以这种方式创建的元素并在它被剥离坏元素并放入文档之前对其进行操作吗?

赏金编辑

因此,如下面的答案中所述,似乎这种方法不是很安全,特别是出于一个原因:

  • var $dom = $('<img src="blah.jpg"/>') - 无论对象是否已添加到文档中,这都将立即请求图像.

这会产生处理HTML ajax请求的主要问题.例如,如果我们想从表单的输入中获取值:

$.ajax({
  url: 'test.php',
  success: function(responseHTML) {
    var inputs = $(responseHTML).find('form input');
  }
});
Run Code Online (Sandbox Code Playgroud)

这将不自觉地导致浏览器请求所有图像.

赏金奖励给任何人:

  • 在没有上述问题的情况下,谁可以提供一种处理ajax请求的好的,安全的方法.
  • 理想情况下不提供正则表达式的答案...即如果我们想要做什么$(responseHTML).find('img')- 用正则表达式删除图像标签不是一个选项,所以需要一种不显眼的方式来阻止src加载,但仍然有相同的属性,结构等

Mar*_*man 12

这本身有危险吗?我的观点是,只是创建一个DOM的简单行为以某种方式注入任何东西,或者只是简单地处理并创建结构?

简单地创建一个元素而不将其附加到dom将不会导致任何脚本运行,因为此时它纯粹是一个对象(HtmlScriptElement).当它实际附加到dom时,将由浏览器评估并运行脚本元素.说到这一点,我想一个非常狡猾的人可能会利用你可能用来导致不良结果的某个框架或浏览器中出现的错误.

考虑这个例子:

<p>
    <input type="button" value="Store 'The Script' In Variable" id="store"/>
    <input type="button" value="Append 'The Script' To Dom" id="append"/>
</p>
<br/>
<p>
    <input type="button" value="Does nothing"/>
</p>
<h1>The Script</h1>
<pre id="script">
    $(function(){
        function clickIt(){
            $(this).clone().click(clickIt).appendTo("body");
        }
        $("input[type='button']").val("Now Does Something").click(clickIt);
    });
</pre>

var theScript;

$("#store").click(function() {
    theScript = document.createElement('script');
    var scriptText = document.createTextNode($("#script").text());
    theScript.appendChild(scriptText);
});

$("#append").click(function() {
    var head = document.getElementsByTagName('head')[0];
    head.appendChild(theScript);
});
Run Code Online (Sandbox Code Playgroud)

单击store它将创建HtmlScriptElement并将其存储到变量中.您会注意到即使创建了对象也没有运行任何内容.单击append脚本后会立即附加到dom并立即进行评估,按钮会执行不同的操作.

关于jsfiddle的代码示例


javascript/jquery中的任何函数都可以"监视"以这种方式创建的元素并在它被剥离坏元素并放入文档之前对其进行操作吗?

jQuery 有点为你做这件事,因为它做了一些内部脚本eval


来自Karl Swedberg的帖子.append()

所有jQuery的插入方法都在内部使用domManip函数来清理/处理元素插入DOM之前和之后.domManip函数所做的一件事就是拉出要插入的任何脚本元素,并通过"evalScript例程"运行它们,而不是将它们与其余的DOM片段一起注入.它单独插入脚本,对它们进行评估,然后将它们从DOM中删除....

您可以更改jQuery的行为以删除所有内容<script/>onclick, mouseover, etc在调用时使用内联javascript清理其他元素,append()但这只会影响jQuery,因为有人可以轻松使用vanilla javascript来附加<script/>元素.

Dom Mutation活动

Dom Level 2确实定义了一些Dom变异事件来捕获添加到dom中的元素,这些元素将看向事件DOMNodeInserted.但是,在添加元素后会触发它.请注意,根据Raynos,这些目前弃用.

DOMNodeInserted将节点添加为另一个节点的子节点时触发.插入发生后将调度此事件.此事件的目标是要插入的节点.气泡:是可取消:无上下文信息:relatedNode保存父节点

最后它似乎没有完全停止<script/>通过其他一些javascript附加到dom.(至少不是我能找到的).

我建议的最好方法是永远不要相信用户输入,因为所有用户输入都是邪恶的.当你进行dom操作时,请仔细检查以确保没有禁用标签,无论是它<script/>还是普通<p/>元素,并在保留之前清理所有输入.

此外,正如John指出的那样,您需要担心任何可以附加onclick事件或任何内联javascript事件处理程序的元素.

  • @Gary:不要忘记其他标签可以包含也可以运行的javascript.例如,用户可以插入*<a href="javascript:alert('breach your code'); return false;"> Nasty link </a>*.如果他这样做并且你将它插入到DOM中,那么他们可以将自己的代码压缩到页面中. (3认同)

s4y*_*s4y 7

对你的第一个例子的强制性回应

var comment = 'I\'m a naughty person!!' +
              '<script src="http://blah.com/some_naughty_javascript.js">';
var $dom = $('<div>' + comment + '</div>');
Run Code Online (Sandbox Code Playgroud)

不要这样做.相反,您应该使用将文本视为文本的API,并且根本不会让您注入注入.在此示例中,您应该这样做:

var $dom = $('<div>').text(comment);
Run Code Online (Sandbox Code Playgroud)

...创建一个div,然后设置其文本内容.comment永远不会被解析为HTML,因此浏览器不可能做任何危险的事情.

继续讨论这个问题

如果我理解正确的话,你想要从任意HTML中解析信息,而浏览器没有准备好显示它(比如通过加载图像).

这很棘手,因为构建到Web浏览器中的DOM是为了处理在某些时候显示的内容而构建的.jQuery(以及任何创建DOM节点的库)都受此限制.

DOM Level 2 定义了一个API来创建与活动文档完全分开的文档:.在我的测试中,当在其中一个文档上创建时,不会加载任何内容:document.implementation.createHTMLDocument(title)img

var doc = document.implementation.createHTMLDocument(''),
    img = doc.createElement('img');
img.src = 'http://example.com/image.jpg'; // Nothing happens.
// Alternatively…
doc.body.innerHTML = '<img src="http://example.com/image.jpg">'; // Nope.
Run Code Online (Sandbox Code Playgroud)

因此,以这种方式创建的文档似乎是一个很好的沙箱来解析和探索HTML.您甚至可以在不同文档($(doc.body))中的节点周围创建一个jQuery包装器,并通过jQuery API进行探索.当你找到你要找的节点,你可以将它们转换回HTML插入到活动文档,或使用类似的方法importNode()adoptNode()他们直接转移到活动文档.

不幸的是,对所有这些的支持是新的.Firefox支持createHTMLDocument版本4及更高版本(类似的createDocument处理XML的方法,在旧版本中可用),Internet Explorer 在版本9及更高版本中支持它.另外,据我所知,规范并不保证图像和脚本不会预先加载到这些文档中.

更好的解决方案是避免浏览器的HTML解析器.最近出现了许多JavaScript HTML解析器.最简单的可能是John Resig的Pure JavaScript HTML Parser.您可以将其提供给HTML,并在触及新标记,属性和文本时触发回调.从这些回调中,您可以创建新的HTML,构建DOM节点或以您喜欢的任何形式存储文档 - 您可以忽略您认为危险的属性和节点.

你可以在Dan Kaminsky的Interpolique中找到一个这样的例子,这一个概念验证,旨在一劳永逸地杀死XSS和SQL注入.该项目尚未开始,但如果您下载Interpolique,您会发现一个safeParse()功能卡在htmlparser.js的底部,它使用标签名称和属性的白名单,并抛弃其他所有内容.

jsdom是一个完整的(直到DOM级别2,有一些级别3)用JavaScript编写的HTML DOM - 您可以使用它来安全地使用HTML.你甚至可以加载自己的jQuery副本.但是,它是为CommonJS编写的,没有考虑到浏览器兼容性.我不知道它是否适用于大多数没有修改的Web浏览器.它也是一个大型图书馆.

如果可能的话,理想的解决方案是以HTML以外的格式提供AJAX响应.您是否需要包含额外的,不安全的HTML?如果你在服务器上做的工作只返回你需要的东西......

{
    "inputs": [
        '<input …>',
        '<input …>'
    ],
}
Run Code Online (Sandbox Code Playgroud)

......你在客户端的工作变得容易多了.