“new DOMParser.parseFromString”可以比“createElement”更安全吗?

时间:2016-05-31 19:58:59

标签: javascript xss

我创建了一个脚本,用于尝试删除不安全的内容(我将其用于浏览器扩展):

var str = "<strong>Hello</strong> mundo <script src="http://site/badscript.js"></script>";
CreateDOM(str);

function RemoveAttrs(target)
{
    var attrs = target.attributes, currentAttr;
    var validAttrs = [ "href", "class", "id", "target" ];

    for (var i = attrs.length - 1; i >= 0; i--) {
        currentAttr = attrs[i].name;

        if (attrs[i].specified && validAttrs.indexOf(currentAttr) === -1) {
            target.removeAttribute(currentAttr);
        }

        if (
            currentAttr === "href" &&
            /^(#|javascript[:])/gi.test(target.getAttribute("href"))
        ) {
            target.parentNode.removeChild(currentAttr);
        }
    }
}

function RemoveEls(target)
{
    var current;

    //Remove elements insecure (blacklist)
    var list = target.querySelectorAll("script,link,...");

    for (var i = list.length - 1; i >= 0; i--) {
        current = list[i];
        current.parentNode.removeChild(current);
    }

    //Remove insecure attributes (whitelist)
    list = target.getElementsByTagName("*");

    for (i = list.length - 1; i >= 0; i--) {
        RemoveAttrs(list[i]);
    }

    return target;
}

function CreateDOM(MinhaString)
{
     var tmpDom = document.createElement("div");
     tmpDom.innerHTML = MinhaString;

     tmpDom = RemoveEls(tmpDom);

     //Inject in container
     document.getElementById("container").appendChild(tmpDom);
}

我在为Opera和Google Chorme创建的插件中使用此脚本,但网站主持人(“addons.opera.com”)对我说:

  

您的cleanDomString方法不安全,请替换:   tmpDom.innerHTML = data; with:var tmpDom =(new   DOMParser).parseFromString(data,“text / html”)。body;

     

并删除:var tmpDom = document.createElement(“div”);

     

或使用:   https://github.com/operatester/safeResponse/blob/1.1/safeResponse.js

     

dmichnowicz; 2016年5月30日上午8:46:57 UTC

代码如下所示:

var str = "<strong>Hello</strong> mundo <script src="http://site/badscript.js"></script>";
CreateDOM(str);

function RemoveAttrs(target)
{
    var attrs = target.attributes, currentAttr;
    var validAttrs = [ "href", "class", "id", "target" ];

    for (var i = attrs.length - 1; i >= 0; i--) {
        currentAttr = attrs[i].name;

        if (attrs[i].specified && validAttrs.indexOf(currentAttr) === -1) {
            target.removeAttribute(currentAttr);
        }

        if (
            currentAttr === "href" &&
            /^(#|javascript[:])/gi.test(target.getAttribute("href"))
        ) {
            target.parentNode.removeChild(currentAttr);
        }
    }
}

function RemoveEls(target)
{
    var current;

    //Remove elements insecure (blacklist)
    var list = target.querySelectorAll("script,link,...");

    for (var i = list.length - 1; i >= 0; i--) {
        current = list[i];
        current.parentNode.removeChild(current);
    }

    //Remove insecure attributes (whitelist)
    list = target.getElementsByTagName("*");

    for (i = list.length - 1; i >= 0; i--) {
        RemoveAttrs(list[i]);
    }

    return target;
}

function CreateDOM(MyString)
{
     var tmpDom = (new DOMParser).parseFromString(MyString, "text/html").body;

     tmpDom = RemoveEls(tmpDom);

     //Inject in container
     document.getElementById("container").appendChild(tmpDom);
}

我做了更改,但我想了解我的代码变得更安全。对我来说,他们似乎都做同样的事情。

有什么不同(他们的安全条款)?

1 个答案:

答案 0 :(得分:7)

实际上,您当前的代码并不安全。 innerHTML不会在创建的<script>元素中运行脚本,但会运行事件处理程序内容属性。

function createDOM(str) {
  document.createElement("div").innerHTML = str;
}
createDOM('<img src="//" onerror="console.log(\'You are pwned!\')" />');

function createDOM(str) {
  new DOMParser().parseFromString(str, "text/html");
}
createDOM('<img src="//" onerror="console.log(\'You are safe\')" />');

但是,请注意DOMParser如果您只想从不受信任的HTML字符串中操作DOM元素,则会提供安全性。它就像一个沙箱。但如果那时你得到这些元素并将其附加到当前文档中,它们仍然可以运行JS。

function createDOM(str) {
  document.body.appendChild(new DOMParser().parseFromString(str, "text/html").body);
}
createDOM('<img src="//" onerror="console.log(\'You are pwned!\')" />');

如果你真的需要这样的东西,我会使用一个允许元素和属性的小白名单,并摆脱其他一切。