在将其放入dom之前,我想使用标签,属性和值的白名单来清理html字符串。我可以安全地构造一个dom元素,并遍历它以实现白名单过滤器,假设在我将dom元素附加到文档之前没有恶意javascript可以执行吗?这种方法有缺陷吗?
答案 0 :(得分:2)
根据@ rvighne的回答,在插入文档之前似乎没有任何内容会执行,但至少存在这些(异常)异常(在FF 27.0中测试):
var userInput = '<a href="http://example.com" onclick="alert(\'boo!\')">Link<\/a>';
var el = document.createElement('div');
el.innerHTML = userInput;
el.addEventListener("click", function(e) {
if (e.target.nodeName.toLowerCase() === 'a') {
alert("I will also cause side effects; I shouldn't run on the wrong link!");
}
});
el.getElementsByTagName('a')[0].click(); // Alerts "boo!" and "I will also cause side effects; I shouldn't run on the wrong link!"
...或...
var userInput = '<a href="http://example.com" onclick="alert(\'boo!\')">Link<\/a>';
var el = document.createElement('div');
el.innerHTML = userInput;
el.addEventListener("cat", function(e) { this.getElementsByTagName('a')[0].click(); });
var event = new CustomEvent("cat", {"detail":{}});
el.dispatchEvent(event); // Alerts "boo!"
...或...(虽然不推荐使用setUserData,但它仍然有效):
var userInput = '<a href="http://example.com" onclick="alert(\'boo!\')">Link<\/a>';
var span = document.createElement('span');
span.innerHTML = userInput;
span.setUserData('key', 10, {handle: function (n1, n2, n3, src) {
src.getElementsByTagName('a')[0].click();
}});
var div = document.createElement('div');
div.appendChild(span);
span.cloneNode(); // Alerts "Boo!"
var imprt = document.importNode(span, true); // Alerts "Boo!"
var adopt = document.adoptNode(span, true); // Alerts "Boo!"
......或在迭代期间......
var userInput = '<a href="http://example.com" onclick="alert(\'Boo!\');">Link</a>';
var span = document.createElement('span');
span.innerHTML = userInput;
var treeWalker = document.createTreeWalker(
span,
NodeFilter.SHOW_ELEMENT,
{ acceptNode: function(node) { node.click(); } },
false
);
var nodeList = [];
while(treeWalker.nextNode()) nodeList.push(treeWalker.currentNode); // Alerts 'Boo!'
但是如果没有这些(不寻常的)事件相互作用,就我自己能够检测到的那样,单独构建DOM的事实不会导致任何副作用(当然上面的例子都是人为的,并且如果有的话,不会期望经常遇到它们!)。
答案 1 :(得分:1)
HTML中嵌入的脚本在放入文档之前不能执行。尝试在任何页面上运行此代码:
var html = "<script>document.body.innerHTML = '';</script>";
var div = document.createElement('div');
div.innerHTML = html;
你会注意到没有任何变化。如果运行HTML中的“恶意”脚本,那么文档应该已经消失。因此,您可以使用DOM来清理HTML,而不必担心HTML中存在错误的JS。只要您在洗手液中删除脚本当然。
顺便说一下,你的方法比大多数人尝试的方法更安全,更聪明(用正则表达式解析它,the poor fools)。但是,最好依靠良好,可信的HTML清理库,例如HTML Purifier。或者,如果你想在客户端做,你可以使用ESAPI-JS(由@Brett Zamir推荐)
答案 2 :(得分:0)
您可以使用不会执行任何操作的“沙盒” iframe。
var iframe = document.createElement('iframe');
iframe['sandbox'] = 'allow-same-origin';
从w3schools:
sandbox属性可为 iframe中的内容。存在沙箱属性时,它将:
- 阻止表单提交
- 阻止脚本执行
- 禁用API
- ...
P.S。顺便说一下,这就是我们在Html Sanitizer https://github.com/jitbit/HtmlSanitizer中的处理方式-我们使用浏览器来解释HTML并将其转换为DOM。随意检查代码(或实际使用组件)
(免责声明:我是该OSS项目的贡献者)