使用浏览器使用javascript清理html字符串来解释html



我想在将 html 字符串放入 dom 之前,使用标签、属性和值的白名单来清理它。我可以安全地构造一个 dom 元素,并遍历它以实现白名单过滤器,假设在我将 dom 元素附加到文档中之前没有恶意 javascript 可以执行吗?这种方法是否存在缺陷?

根据@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 中的事实不会引起任何副作用(当然,上面的例子是人为的,人们不会期望经常遇到它们,如果有的话!

HTML 中嵌入的任何脚本在放入文档之前都无法执行。尝试在任何页面上运行此代码:

var html = "<script>document.body.innerHTML = '';</script>";
var div = document.createElement('div');
div.innerHTML = html;

你会注意到任何变化。如果运行了 HTML 中的"恶意"脚本,则文档应该已经消失了。因此,您可以使用 DOM 来清理 HTML,而不必担心 HTML 中存在糟糕的 JS。当然,只要你在消毒液中剪掉脚本。


顺便说一句,你的方法比大多数人尝试的方法非常安全和聪明(用正则表达式解析它,可怜的傻瓜)。但是,最好依靠良好的,值得信赖的HTML清理库,例如HTML Purifier。或者,如果你想在客户端做,你可以使用ESAPI-JS(由@Brett Zamir推荐)

您可以使用不会执行任何内容的"沙盒"iframe。

var iframe = document.createElement('iframe');
iframe['sandbox'] = 'allow-same-origin';

来自w3schools:

沙盒属性为 内嵌框架中的内容。当沙盒属性存在时,它将:

  • 块表单提交
  • 块脚本执行
  • 禁用接口

附言顺便说一下,这正是我们在 Html 清理器 https://github.com/jitbit/HtmlSanitizer 中的做法 - 我们使用浏览器来解释 HTML 并将其转换为 DOM。 随意检查代码(或实际使用组件)

(免责声明:我是该 OSS 项目的贡献者)

最新更新