HTMLPurifier Library 移除所有自定义标签

HTMLPurifier Library removes all custom tags

我正在使用 4.0.0 版的 htmlpurifier 库,我的所有请求都被该库净化了。有时我们需要允许一些不属于标准定义的任意自定义标签和 xml 标签。这里库删除了所有不支持的。

我知道我们可以编写定义来支持自定义属性和标签,但我的问题是支持任何自定义标签,而不是只允许少数标签,如脚本、iframe 等。

有没有办法在库中实现这个?

简答

没有

长答案

一般来说,HTML净化器的原理是白名单。这意味着它必须知道所有合法的星座,并且会丢弃任何它不能识别的东西。

即使您使用 HTML.ForbiddenElements 将 HTML 净化器置于 黑名单 模式,这也是次要设计功能。 HTML Purifier 仍然坚持它知道它所提供的所有元素和属性,并且会去除任何其他元素。

为什么要限制?

为什么不使用基本黑名单方法的一个生动例子是查看 HTML5 中已添加到 HTML 规范中的大量元素和属性。

考虑 HTML5 Security Cheatsheet。如果您在浏览器支持 HTML5 之前实施了黑名单方法,您可能没有意识到:

你看到问题了。这就是 HTML Purifier 不允许您信任任意自定义标签的原因。

做什么

我建议向 HTML Purifier 教授您所有的自定义标签和属性。如果它们不是完全任意的,这种方法真的很有帮助。我曾为一个项目将许多自定义 Outlook 标记和属性编码到 HTML Purifier 中 - 虽然开发很乏味,但净收益(强大的安全性)是值得的。

如果您决定走这条路,请查看“Enduser: Customize”文档。

页面上的示例尝试实现 <form>,HTML Purifier 本身不支持它。从用例的角度来看,它技术上不是自定义元素,但它足够好地说明了该过程:

Juicy! With just this, we can answer four of our five questions:

  1. What is the element's name? form
  2. What content set does this element belong to? Block (this needs a little sleuthing, I find the easiest way is to search the DTD for FORM and determine which set it is in.)
  3. What are the allowed children of this element? One or more flow elements, but no nested forms
  4. What attributes does the element allow that are general? Common
  5. What attributes does the element allow that are specific to this element? A whole bunch, see ATTLIST; we're going to do the vital ones: action, method and name

Time for some code:

$config = HTMLPurifier_Config::createDefault();
$config->set('HTML.DefinitionID', 'enduser-customize.html tutorial');
$config->set('HTML.DefinitionRev', 1);
$config->set('Cache.DefinitionImpl', null); // remove this later!
$def = $config->getHTMLDefinition(true);
$def->addAttribute(
    'a',
    'target',
    new HTMLPurifier_AttrDef_Enum( array('_blank','_self','_target','_top') )
);
$form = $def->addElement(
    'form',   // name
    'Block',  // content set
    'Flow', // allowed children
    'Common', // attribute collection
    array( // attributes
        'action*' => 'URI',
        'method' => 'Enum#get|post',
        'name' => 'ID'
    )
 );
 $form->excludes = array('form' => true);

Each of the parameters corresponds to one of the questions we asked. Notice that we added an asterisk to the end of the action attribute to indicate that it is required. If someone specifies a form without that attribute, the tag will be axed. Also, the extra line at the end is a special extra declaration that prevents forms from being nested within each other.