3

我的问题

我想清理粘贴在富文本编辑器中的 HTML(目前为 FCK 1.6)。清理应该基于标签的白名单(可能还有另一个带有属性的)。这主要不是为了防止 XSS,而是为了移除丑陋的 HTML。

目前我看不到在服务器上做这件事,所以我想它必须在 JavaScript 中完成。

当前的想法

我找到了jquery-clean 插件,但据我所知,它使用正则表达式来完成这项工作,我们知道这是不安全的。

由于我没有找到任何其他基于 JS 的解决方案,因此我开始使用 jQuery 自己实现一个。它可以通过创建粘贴的 html ( $(pastedHtml)) 的 jQuery 版本来工作,然后遍历生成的树,通过查看属性删除每个与白名单不匹配的元素tagName

我的问题

  • 这更好吗?
  • 我可以相信 jQuery 能够很好地表示粘贴的内容(可能有不匹配的结束标签和你有什么)?
  • 有没有我找不到的更好的解决方案?

更新

这是我当前的基于 jQuery 的解决方案(详细且未经过广泛测试):

function clean(element, whitelist, replacerTagName) {
    // Use div if no replace tag was specified
    replacerTagName = replacerTagName || "div";

    // Accept anything that jQuery accepts
    var jq = $(element);    

    // Create a a copy of the current element, but without its children
    var clone = jq.clone();
    clone.children().remove();

    // Wrap the copy in a dummy parent to be able to search with jQuery selectors
    // 1)
    var wrapper = $('<div/>').append(clone);

    // Check if the element is not on the whitelist by searching with the 'not' selector
    var invalidElement = wrapper.find(':not(' + whitelist + ')');

    // If the element wasn't on the whitelist, replace it.
    if (invalidElement.length > 0) {
       var el = $('<' + replacerTagName + '/>'); 
       el.text(invalidElement.text()); 
       invalidElement.replaceWith(el);   
    }

    // Extract the (maybe replaced) element
    var cleanElement = $(wrapper.children().first());

    // Recursively clean the children of the original element and
    // append them to the cleaned element
    var children = jq.children();
    if (children.length > 0) {
        children.each(function(_index, thechild) {
                          var cleaned = clean(thechild, whitelist, replacerTagName);
                          cleanElement.append(cleaned);
                      });
      } 
    return cleanElement;
}

我想知道一些要点(请参阅代码中的注释);

  1. 我真的需要将我的元素包装在一个虚拟父级中以便能够将它与 jQuery 的 ":not" 匹配吗?
  2. 这是创建新节点的推荐方法吗?
4

1 回答 1

2

如果您利用浏览器的 HTML 更正能力(例如,您将富文本复制到innerHTML一个空文本div并获取生成的 DOM 树),则 HTML 将被保证是有效的(它的更正方式在某种程度上取决于浏览器)。尽管这可能是由富编辑器完成的。

jQuery 自己的 text-top DOM 转换可能也是安全的,但肯定更慢,所以我会避免它。

使用基于 jQuery 选择器引擎的白名单可能有点棘手,因为在保留其子元素的同时删除元素可能会使文档无效,因此浏览器会通过更改 DOM 树来纠正它,这可能会混淆试图遍历无效元素的脚本. (例如,您允许ulli不允许ol;脚本会删除列表根元素,裸li元素无效,因此浏览器会再次将它们包装起来ul,这ul将被清理脚本遗漏。)如果您将不需要的元素与其所有子元素一起丢弃,我看不出有什么问题。

于 2011-03-17T17:51:43.193 回答