在 HTML 属性中使用 handlebars 的默认转义是否安全

Is handlebars' default escaping safe for use in HTML attributes

我正在为一个项目做一些合同工作,该项目有多种 HTML 转义方法。一些属性在后端转义并使用三把手 {{{escaped-in-backend}}} 呈现为原始字符串,其他属性从后端原始传递并使用 double handlebars {{unsafe}}.[=19= 转义]

JS 后端编码是使用(遗留的?)ESAPI 库完成的,并混合使用 encodeForHtml()encodeForHtmlAttribute()。我找不到关于此的大量信息,但 this post 建议属性编码也将空格转义为   以便被认为免受 XSS 攻击。这可能是促使前开发人员在后端进行转义的原因。

后端转义很讨厌,我想摆脱它并依赖把手。我已经 F/E 多年没有做过工作了,所以我只是想仔细检查 handlebars 的转义策略对于属性值是否安全,例如:<input type="text" value="{{unsafe-value}}"/>.

我倾向于 'yes',因为车把非常普遍,这将是一个非常明显的安全漏洞,但我找不到任何明确的文档说明这一点。

你遇到了程序员 reverse-engineering 的问题。您正在推翻之前程序员所做的决定!

您遇到的问题是 HTML 属性中的转义规则不同于转义 in-between 标记,因此我们将这些转义函数分开,因为它们不是 1:1.即

<textarea>{{HTMLEscapingIsDoneHere}}</textarea>

<span background="[HTMLAttributeEscapingIsHere]"> ...

HTML 转义包含比 HTML 属性编码更多的字符。危险在于您可能会转义比预期多得多,从而破坏一些其他功能,例如 css 或 jquery 选择器,这些选择器可能会尝试键入这些属性值,现在将失败是因为您转义了太多,并且这些函数需要纯文本而不是 HTML 属性。 Handlebars 本身可能具有一些功能,这些功能可以在属性值上设置键值,如果您 HTML-Escape 它们会破坏这些值。 [不知道,没用过..]

如果你注意前面转义的内容和后面转义的内容,并且之前的开发人员一致认为唯一转义的是你的 HTML 属性......那么我'我打赌 50 美元,他们尝试将所有内容转义为完整 HTML,破坏了一些东西,然后想出了后端转义作为当时最简单的解决方案。如果他们不一致,那么,所有的赌注都没有了。

在你的情况下,也许可以尝试将所有内容转义为 HTML 以查看你是否破坏了任何东西,但特别是如果它有效,你将需要清楚地记录你的方法,你可以创建未来与其他动态框架的不兼容性.如果你不知道,我之前已经 运行 了解过这个。接受或拒绝该风险是企业的工作。

我的第一个建议是,如果您在 JSPs 中使用车把,那么只需导入 ESAPI 标签库并使用那里的编码函数。丑陋的?当然。您正在使用多个 FE 框架。

我的第二个建议是,因为您可能已经与 handlebars 结缘,所以将您要在此处使用的 esapi 编码函数包装起来,并将它们引入到 handlebars 中。例如,在 JSP 中,您有允许您使用 ESAPI 或编写自定义包装器的标签库。因为我知道 ESAPI 在编码时从未考虑过车把,所以我会编写包装函数并使用车把显式转义 HTML,并使用插入的车把功能转义 HTML 属性。如果 handlebars 没有允许您插入自己的转义函数的能力,那么恐怕后端转义是下一个最佳选择。之前的开发人员看到了分离这些转义函数的价值,但无法在 FE 代码中这样做。

至于更广泛的问题,“将属性转义为 HTML 而不是 HTML 属性是否安全”,这是我所回答的“是的,但是......”之一已经克服了陷阱。使用单页 Web 应用程序框架时,大多数陷阱都会消失,但那是因为您已经将 all client/server 通信规范化为 Javascript。这也是 off-topic,但是你的承包商的箭袋里应该有一支箭。

作为一名目前使用 handlebars 和 esapi4js 的程序员,我可以建议您按照我的方式在单独的 js 文件中使用 handlebars helpers 进行转义,如下所示;

    (function() {
    Handlebars.registerHelper('encodeFor', function(forWhat, param) {
        switch(forWhat) {
            case 'html':
                return $ESAPI.encoder().encodeForHTML(param);
            case 'htmlAttribute':
                return $ESAPI.encoder().encodeForHTMLAttribute(param);
        }
    });

})();

encodeFor 是辅助函数的名称 forWhat和param是that

的参数

注册助手后,您可以在车把模板中使用它,例如 ;

<input type="text" value="{{encodeFor 'htmlAttribute' unsafe-value}}"/>

<td class="headerColumn">{{{encodeFor 'html' unsafe-value}}}</td>