XSLT禁用输出转义时如何仅放行指定HTML标签防范XSS漏洞
XSLT评论输出防XSS白名单配置方案
问题说明
当前使用如下XSLT代码输出评论内容时,全局开启disable-output-escaping="yes"会直接原样输出所有HTML/脚本内容,存在XSS跨站脚本安全漏洞:
<xsl:value-of disable-output-escaping="yes" select="//datafor:field[datafor:name='comments']/datafor:value" />
需要实现白名单过滤机制,仅放行指定标签和属性,在保留内容渲染格式的同时规避安全风险,待放行范围如下:
- 无属性允许标签:
b、strong、i、ul、ol、li、br - 带属性允许标签:
p(仅允许style属性)、div(仅允许class属性)
实现方案
核心原则:彻底移除全局disable-output-escaping="yes"配置,改用XSLT模板递归遍历评论内容的所有节点,基于白名单规则逐节点校验输出,非白名单内容自动转义或过滤。
完整实现代码
<!-- 1. 替换原有value-of输出逻辑,调用清洗模板处理评论节点 --> <xsl:apply-templates select="//datafor:field[datafor:name='comments']/datafor:value/node()" mode="comment-sanitize" /> <!-- 2. 基础身份模板:默认复制所有校验通过的节点 --> <xsl:template mode="comment-sanitize" match="@*|node()"> <xsl:copy> <xsl:apply-templates select="@*|node()" mode="comment-sanitize" /> </xsl:copy> </xsl:template> <!-- 3. 匹配无属性白名单标签 + p标签(放行style属性) --> <xsl:template mode="comment-sanitize" match="b|strong|i|ul|ol|li|br|p"> <xsl:element name="{local-name()}"> <xsl:if test="local-name() = 'p'"> <!-- 仅复制p标签的style属性,其余属性自动忽略 --> <xsl:copy-of select="@style" /> </xsl:if> <xsl:apply-templates select="node()" mode="comment-sanitize" /> </xsl:element> </xsl:template> <!-- 4. 匹配div标签,仅放行class属性 --> <xsl:template mode="comment-sanitize" match="div"> <xsl:element name="div"> <xsl:copy-of select="@class" /> <xsl:apply-templates select="node()" mode="comment-sanitize" /> </xsl:element> </xsl:template> <!-- 5. 非白名单标签:剔除标签本身,仅输出内部纯文本,特殊字符自动转义 --> <xsl:template mode="comment-sanitize" match="*[not(local-name() = ('b','strong','i','ul','ol','li','br','p','div'))]"> <xsl:apply-templates select="node()" mode="comment-sanitize" /> </xsl:template> <!-- 6. 非白名单属性:直接拦截不输出 --> <xsl:template mode="comment-sanitize" match="@*[not( (local-name() = 'style' and parent::p) or (local-name() = 'class' and parent::div) )]" />
注意事项
- 如果评论字段存储的是转义后的HTML字符串(节点内容为
<b>测试</b>这类未解析的文本),XSLT 1.0需要借助对应处理器的节点集扩展函数(如MSXML的msxml:node-set、libxslt的exslt:node-set)将字符串解析为节点集后再套用上述模板;XSLT 2.0及以上版本可直接使用parse-xml-fragment()函数解析后处理。 - 建议对放行的
style属性值增加二次校验,拦截javascript:、expression()等危险脚本片段,避免属性值注入风险。 - 所有输出的非白名单内容会被XSLT默认转义为实体字符,从根源上阻断XSS注入路径。
内容的提问来源于stack exchange,提问作者adam78
相关产品推荐
相关产品推荐

