C#怎么从XML中安全地读取数据以避免注入

12次阅读

xml注入风险可通过安全配置XmlReader/XDocument、禁用DTD与外部实体、避免XPath拼接及不执行用户数据来规避。关键在于不将不可信内容当代码执行,而非法防“XML注入”本身。

C#怎么从XML中安全地读取数据以避免注入

XmlReaderXDocument.Load() 配合验证,不拼接、不反射、不执行动态 XPath,就能基本避开 XML 注入风险。关键不是“防注入”,而是避免把不可信内容当代码执行。

用 XmlReader 流式读取,不解析实体

XmlReader 默认禁用 DTD 和外部实体(.net Core / .NET 5+ 默认安全),但旧版 .NET Framework 需手动配置:

  • 创建 XmlReaderSettings,设 DtdProcessing = DtdProcessing.Prohibit
  • 关闭 XmlResolver:设 XmlResolver = NULL
  • 再用 XmlReader.Create(stream, settings) 读取

这样可防止 XXE(XML 外部实体)攻击,也避免实体展开导致的内存/服务端请求问题。

用 XDocument 时禁用 DTD 解析

XDocument.Load() 底层仍走 XmlReader,所以同样要传入安全的 XmlReaderSettings

  • 不要直接写 XDocument.Load(xmlPath)
  • 改用 XDocument.Load(XmlReader.Create(FileStream, safeSettings))
  • 若从字符串加载,用 StringReader 包一层再传给 XmlReader.Create

别用 XPath 查询未过滤的用户输入

XPath 表达式拼接是常见隐患。例如:$"/root/user[@id='" + userId + "']" —— 这等于把攻击面交给了用户。

  • 优先用 linq to XML(如 doc.Root.Elements("user").FirstOrDefault(x => x.Attribute("id")?.Value == userId)
  • 若必须用 XPath,用 XPathSelectElement(doc, xpath, namespaceManager),且确保 xpath 是硬编码或白名单枚举值
  • 绝不将用户输入直接插进 XPath 字符串

不信任任何属性值和文本节点内容

XML 数据本身不是“代码”,但若你把它当代码用,就出问题。比如:

  • node.Attribute("type").Value 当作类名去反射加载 —— 可能触发任意类型实例化
  • node.Value 当作 sql 片段拼接 —— 引发 SQL 注入
  • node.Attribute("url").Value 直接用于 HttpClient.GetAsync() —— 可能外连恶意地址

这些不是 XML 注入,而是业务逻辑误用。应对方式是:校验 + 白名单 + 转义(如输出到 html 时用 WebUtility.HtmlEncode)。

基本上就这些。XML 本身没有“注入漏洞”,危险来自解析器配置不当、XPath 拼接、或把数据当指令执行。关掉 DTD、不用拼接、不反射用户值,就稳了。

text=ZqhQzanResources