默认XmlDocument和XmlReader触发XXE因.NET默认启用DTD解析,需同时设DtdProcessing.Prohibit和XmlResolver=null;XmlSerializer也需用加固XmlReader;还需限制MaxDepth、MaxCharactersInDocument等防DoS。

为什么默认的 XmlDocument 和 XmlReader 会触发XXE
因为 .NET 默认启用 DTD 解析(XmlResolver 非空),当 XML 包含 ]> 这类声明时,XmlDocument.Load() 或 XmlReader.Create() 会尝试解析并加载外部实体,导致文件读取、网络请求甚至 SSRF。
禁用 DTD 解析的两种可靠方式
核心是让解析器完全忽略 DOCTYPE 声明,不执行任何外部实体解析。推荐以下任一做法:
- 使用
XmlReaderSettings显式关闭:var settings = new XmlReaderSettings { DtdProcessing = DtdProcessing.Prohibit, // 关键:禁止 DTD 处理 XmlResolver = null // 关键:移除解析器 }; using var reader = XmlReader.Create(stream, settings); var doc = new XmlDocument(); doc.Load(reader); - 对
XmlDocument直接设置:var doc = new XmlDocument(); doc.XmlResolver = null; // 必须在 Load 前设置 doc.Load(xmlStream);
注意:此方式仅在 .NET Framework 4.5.2+ 和 .NET Core 2.0+ 有效;旧版需配合ProhibitDtd = true(但该属性已过时)
别踩 XmlSerializer 的坑
XmlSerializer 默认不解析 DTD,看似安全,但它会隐式使用 XmlReader,若你传入的是未加固的 XmlReader 实例,风险仍在。安全做法是始终用加固后的 XmlReader 构造:
var settings = new XmlReaderSettings { DtdProcessing = DtdProcessing.Prohibit, XmlResolver = null };
using var reader = XmlReader.Create(stream, settings);
var serializer = new XmlSerializer(typeof(MyClass));
var obj = serializer.Deserialize(reader);不要直接传 stream 给 Deserialize() —— 它会内部创建不设防的 reader。
额外加固:限制解析深度与大小
防止恶意构造的超深嵌套或超大文本耗尽内存:
-
MaxDepth = 10(默认 64,建议压到 8–12) -
MaxCharactersInDocument = 10 * 1024 * 1024(如限制 10MB) -
MaxCharactersFromEntities = 10240(防实体膨胀攻击)
这些都应在 XmlReaderSettings 中一并配置,否则单禁 DTD 仍可能被 DoS。
XXE 防御不是“关一个开关”就完事;DtdProcessing.Prohibit 和 XmlResolver = null 必须同时生效,且所有入口(XmlDocument、XmlReader、XmlSerializer)都要走同一套加固逻辑。漏掉任意一种路径,攻击面就还在。










