XSLT 中安全转义 XML 内容以生成符合 HTML 规范的输出

在使用 .net 的 xslt 转换生成 html 时,`xsl:value-of` 默认会正确转义文本节点,但属性值(如 `value` 或自定义 `data-*` 属性)中的内联表达式不会自动转义,导致 xss 风险;需通过 xhtml 输出方法或手动编码确保所有上下文均安全。

在标准 .NET System.Xml.Xsl(仅支持 XSLT 1.0)中, 对属性值中的动态内容(如 value="{/Contact/Name}")不执行 HTML 实体转义,而仅对 输出的文本内容做转义。这会导致原始 XML 中已编码的 zuojiankuohaophpcnscriptyoujiankuohaophpcn 在属性中被错误解析为未转义的

✅ 正确方案:使用 method="xhtml"(推荐)

XHTML 输出模式强制所有属性值和文本内容遵循 XML 编码规则,天然支持统一转义。但注意:原生 .NET Framework / .NET Core 的 XslCompiledTransform 不支持 XSLT 2.0/3.0 或 xhtml 方法。因此必须借助第三方处理器:

▪ 使用 SaxonCS(.NET 6+ 推荐)

SaxonCS(Saxon 11/12,商业版)原生支持 XSLT 3.0 和 xhtml 输出,配置简洁且可靠:


using Saxon.CSharp.Api;

var processor = new Processor();
var compiler = processor.NewXsltCompiler();
var stylesheet = compiler.Compile(xslt); // xslt 中 
var transformer = stylesheet.Load();

var input = processor.NewDocumentBuilder().Build(xml);
using var output = new StringWriter();
transformer.Run(new Serializer(output));

Console.WriteLine(output.ToString());

对应 XSLT 片段应明确声明:

✅ 效果:data-title 和 value 属性中的 /Contact/Name 值将被自动 HTML-encode(zuojiankuohaophpcn →

▪ 兼容旧框架:Saxon HE + IKVM(.NET Framework)

若受限于 .NET Framework,可使用 IKVM 将 Java 版 Saxon HE 11.4 跨编译为 .NET 程序集(需额外配置 XML Resolver)。详见 GitHub 示例项目。

⚠️ 替代方案(不推荐,仅作兜底)

若无法引入 Saxon,可在 XSLT 中手动调用编码函数(需扩展对象):



  
    
  

并在 C# 中实现:

var args = new XsltArgumentList();
args.AddExtensionObject("urn:utils", new HtmlEncoderHelper());

但此方式耦合度高、维护成本大,且易遗漏上下文(如 JSON 字符串内嵌属性),强烈建议优先采用 xhtml 输出模式

? 关键总结

  • method="html" 是“宽松渲染模式”,不保证属性值转义,不适合含用户数据的 HTML 输出
  • method="xhtml" 是“严格 XML 模式”,所有内容按 XML 规则序列化,天然防御 XSS;
  • .NET 原生 XslCompiledTransform 无法满足需求,必须升级至 SaxonCS(现代 .NET)或 Saxon HE + IKVM(旧框架);
  • 永远避免在 HTML 属性中拼接未经转义的动态内容——这是前端安全的黄金法则。