使用 DocumentFragment 和 innerHTML 的富文本注释的存储型 XSS 预防

Stored XSS prevention with rich-text comments using DocumentFragment and innerHTML

我想知道是否有人能够确认这是否安全,因为我似乎无法在网上找到任何参考资料,也找不到关于 SO 的其他问题,专门针对此 "solution" XSS.

我需要在我的页面中嵌入富文本评论。显然 XSS 的风险很高,所以我的计划是在 DocumentFragment 中内部 HTML 一个临时的 DIV 然后递归树,使用我认为的预定义的 tagNames 和属性名称的白名单'safe',删除所有不安全的。然后我可以将这个现在安全的 HTML 移到我的真实文档中。

这样做安全吗?通过 DocumentFragment 执行此操作是否可以触发 XSS 攻击?我希望它将与真实文档隔离开来,从而避免可能引发任何攻击的用户事件触发。

我不建议编写您自己的反 XSS 库,因为恶意用户一定会知道您没有考虑到的漏洞。我建议使用第三方库,例如 Google Caja HTML Sanitiser.

查看你的 Pen,如果 <> 标签被转义,你的代码仍然容易受到攻击:

var unsafe = '\u003Cimg src=1 onerror=alert(\u0027XSS_attack_in_progress\u0027)\u003E',
  //var unsafe = '<h3>Hello</h3><h4>World</h4>',
  whitelistTags = ['h1', 'h2', 'h3', 'b', 'i', 'em', 'strong', 'u'],
  testNode = document.getElementById('testNode');

makeSafeAndAddToDoc(unsafe, testNode);

function makeSafeAndAddToDoc(unsafe, targetParent) {
  var safeDocFrag = document.createDocumentFragment(),
    containerDiv = safeDocFrag.appendChild(document.createElement("DIV")),
    nextChild;
  containerDiv.innerHTML = unsafe;
  while ((nextChild = containerDiv.firstChild)) {
    if (isSafe(nextChild)) {
      safeDocFrag.appendChild(containerDiv.firstChild);
      console.debug(safeDocFrag.children);
    } else {
      containerDiv.removeChild(nextChild);
    }
  }
  safeDocFrag.removeChild(containerDiv);
  targetParent.appendChild(safeDocFrag);
}

function isSafe(testNode) {
  var tag = testNode.tagName && testNode.tagName.toLowerCase(),
    isTextNode = testNode.nodeType === 3;
  if (!isTextNode && whitelistTags.indexOf(tag) === -1) {
    console.warn('Removing unsafe element: ', testNode.tagName);
    return false;
  }
  for (var i = 0; i < testNode.childNodes.length; i++) {
    if (!isSafe(testNode.childNodes[i])) {
      testNode.removeChild(testNode.childNodes[i]);
      i--;
    }
  }
  return true;
}
#testNode {
  min-width: 10px;
  min-height: 10px;
  border: 1px solid red;
}
<div id="testNode"></div>