【问题标题】:How to allow curly braces in href attributes inside content that is processed with HTML Purifier如何在使用 HTML Purifier 处理的内容内的 href 属性中允许大括号
【发布时间】:2021-07-09 20:57:06
【问题描述】:

我的 CMS 中有一个编辑器类型字段(我使用 Craft CMS),用户可以在其中输入一些“变量”,如下所示:

“你好,{name}”

唯一的问题是,当启用 HTML 净化器时,它会去除所有这些在 href 属性中的“变量”,并用代码替换它们。 例如:

<a href="tel:{client tel}">{client tel}</a>

变成

<a href="tel:7207">{client tel}</a>

我当然可以禁用 HTML 净化器,但我宁愿不这样做。我只是很难找到正确的净化器配置来允许所需的行为。有人可以帮忙吗?

【问题讨论】:

  • 我无法确认这种行为
  • 我刚刚在使用 Redactor 插件的全新 Craft3 安装中对此进行了测试。虽然我在任何地方都没有找到净化器的开/关开关,但 HTML 输出与预期的一样。我确实尝试过使用和不使用净化过滤器。 ``` {% for entry in entries %}
  • {{ entry.getLink() }} – {{ entry .test|purify }}
  • {% endfor %} ``` 输出是:```

    你好, {name}

    ``` 你想在这里做什么?预渲染电子邮件模板?非 Twig 占位符有什么用?
  • 通常的方法是(1)如果您需要跨会话保存未纯化的 HTML(不确定您是否这样做,我不知道您的用例是什么,确切地说), (2) 每当您需要在预览中显示它时,在输出时对其进行净化;然后当你想用值渲染它时(3)做变量替换first,(4)在结果上运行HTML Purifier。无论如何,您实际上都希望在结果上运行 HTML Purifier,因为“名称”可能是“&lt;script&gt;alert(1);&lt;/script&gt;”。不幸的是,我不熟悉 Craft CMS 以及它是否可以让您调整订单。
  • 标签: php htmlpurifier craftcms


    【解决方案1】:

    这个具体的例子是两个过滤器串联应用的结果。第一个是percent-encoding the "path" portion of the value - 属性值中tel 方案之后的所有内容,导致tel:%7Bclient%20tel%7D。第二个是特定于 tel 的过滤器:根据 cmets 的说法,该 URL 方案“从电话号码中删除所有非数字字符、非 x 字符,除了前导加号。” - 剩下的就是tel:7207

    来自HTMLPurifier_URIScheme_tel->doValidate

    // Delete all non-numeric characters, non-x characters
    // from phone number, EXCEPT for a leading plus sign.
    $uri->path = preg_replace('/(?!^\+)[^\dx]/', '',
        // Normalize e(x)tension to lower-case
        str_replace('X', 'x', $uri->path));
    

    所以这确实是两个问题,第一个是大括号的 URL 编码,第二个是 tel: 方案中的正则表达式。

    解决此问题的简单方法是指示 HTMLPurifier 将 a 标签上的 href 属性评估为文本而不是 URI。 URI 评估非常严格,应该如此。由于您需要通过过滤器传递无效的 URI,您可以使用默认的文本过滤,或者根据您的需要创建自己的过滤器。我将在这里描述前者,后者是一个更复杂的练习。

    请注意,这将导致 HTMLPurifier 将所有 a href 属性评估为文本,您将失去对所有链接的严格验证 - 请确保您了解对应用程序安全性的潜在影响。

    $config = HTMLPurifier_Config::createDefault();
    $config->set('HTML.DefinitionID', 'trusted');
    
    if ($def = $config->maybeGetRawHTMLDefinition())
    {
        $def->addAttribute('a', 'href', 'Text');
    }
    
    $purifier = new HTMLPurifier($config);
    

    有关详细信息,请参阅customizing 文档。

    这里的主要危险是您正在删除 javascript: 方案的过滤。文本过滤器将转义脚本标签,但不会过滤方案中的内联命令。

    输入:

    <a href="<script>alert(1)</script>">Script tag in href with alert</a>
    <a href="javascript:alert(1)">javascript scheme with alert</a>
    

    默认转义:

    <a href="">Script tag in href with alert</a>
    <a>javascript scheme with alert</a>
    

    文本转义:

    <a href="&lt;script&gt;alert(1)&lt;/script&gt;">Script tag in href with alert</a>
    <a href="javascript:alert(1)">javascript scheme with alert</a>
    

    当我做这样的事情时,我使用两种不同的定义,一种称为“受信任”,用于过滤来自受信任来源的内容,例如应该知道自己在做什么的 CMS 管理员,另一种称为“偏执狂”,用于来自不受信任来源的内容。

    这里降低风险的另一种策略是在将内容输入 CMS(可信定义)时允许这种许可转义,然后在呈现内容后应用更严格的过滤(偏执定义)。无论如何,最好在输出时转义,以防止stored xss attacks

    【讨论】:

    • 这是一个很好的答案,我不喜欢敲它,但我确实需要强调底部的免责声明,而不是现在为了 OP 而强调。 “javascript:” 是一个有效的伪模式,有多种方法可以通过它直接在此处记录(以及其他 XSS 技巧):owasp.org/www-community/xss-filter-evasion-cheatsheet - 这不是人们想要重新发明消毒轮的地方。
    • 你说得对,我更新了答案以强调风险并提供缓解策略。
    • 谢谢!您的回答似乎值得一试,并且安全隐患并不大,因为此内容来自 CMS 中受信任的作者。我的下一个障碍是“翻译”您提供给 JSON 的配置,因为 Craft CMS 将 .json 文件用于 HTML Purifier 配置。我是 stackoverflow 的新手,我可能应该将这个问题转移到 Craft StackExchange(哦!)。这会被视为双重发布吗?有没有推荐的继续对话的方式?
    • 我会问如何在定义中添加一个属性。我快速浏览了 Craft CMS 代码(看起来非常不错),虽然它们允许按字段定义净化器(很酷!),但我没有看到向定义添加属性的方法,它们只是设置顶部级值。 github.com/craftcms/redactor/blob/v2/src/Field.php#L1017 可能有办法做到这一点,但这是要问的具体问题。如何向 HTML Purifier 定义添加属性。
    • 如果将来有人来到这里并正在寻找如何将特定的每个元素属性允许添加到他们的 Craft CMS Redactor / HTML Purifier 配置中,我已经在这里回答了这个问题:craftcms.stackexchange.com/a/38833/10878
    猜你喜欢
    相关资源
    最近更新 更多
    热门标签