FlawOpen

flawopen.com/XXE/.NET XML 解析器

.NET 中的 XmlReader 能防御 XXE 吗?

CWE-611: XML External Entity Reference简短回答
简短回答

可以把 DTD 想成允许解析器获取 XML 中所命名文档的通行证。XmlReader.Create 默认拒绝 DTD,因此除非应用启用它,不可信文档无法走这条路径。旧 API 和目标框架版本也很重要:应明确禁止 DTD,并在解析边界关闭外部资源解析。

不安全 — 旧式或被弱化的配置
// 直接使用旧 reader 时可能启用 DTD 解析
// 外部 resolver 会获取 XML 中引用的资源。
var legacy = new XmlTextReader(stream) {
    DtdProcessing = DtdProcessing.Parse,
    XmlResolver = new XmlUrlResolver()
};
while (legacy.Read()) { }

// 对不可信 XML 显式启用 DTD 存在风险:
var unsafeSettings = new XmlReaderSettings {
    DtdProcessing = DtdProcessing.Parse,
    XmlResolver = new XmlUrlResolver()
};
using var reader = XmlReader.Create(stream, unsafeSettings);
已加固 — 拒绝 DTD 和外部资源
var settings = new XmlReaderSettings {
    // 拒绝任何包含 DTD 的文档。
    DtdProcessing = DtdProcessing.Prohibit,
    // 纵深防御:不获取外部资源。
    XmlResolver = null,
    // 根据应用的合法输入选择限制值。
    MaxCharactersInDocument = 1_000_000,
    MaxCharactersFromEntities = 1_024,
};

using var reader = XmlReader.Create(stream, settings);
var doc = new XmlDocument { XmlResolver = null };
doc.Load(reader);

你使用的是哪种 XML API 和 .NET 版本?

.NET has several XML APIs whose defaults have differed, and whose defaults have also changed across framework versions. The practical summary:

.NET Framework 4.5.2 将 XmlReaderSettings.XmlResolver 的默认值设为 null,并将 MaxCharactersFromEntities 初始化为 1000 万;但这并不意味着所有 XML API 或配置都相同。兼容开关可能恢复旧默认值。应显式设置解析器策略、限制文档大小,并检查实际目标框架和运行时配置。

常见问题

XmlReader.Create 默认禁止 DTD 吗?

是。XmlReaderSettings.DtdProcessing 默认值为 Prohibit,遇到 DTD 时会抛出异常。仍建议显式设置,并将 XmlResolver 设为 null 作为纵深防御。

.NET Framework 4.5.2 有哪些变化?

出于安全考虑,XmlReaderSettings.XmlResolver 默认改为 null,MaxCharactersFromEntities 初始化为 1000 万。EnableLegacyXmlSettings 可恢复旧行为;应检查部署配置,而不只是目标框架。

SOAP、SAML 或 Office 文档解析会受影响吗?

可能会。这些格式包含 XML,但具体影响取决于解析器和配置。确保每个不可信 XML 入口都使用加固后的 reader,限制输入大小,并遵循相应格式库的安全指南。

来源与参考

另请参阅 XML 外部实体注入(XXE,CWE-611):原理与防御方法 — flawopen.com Java XXE:DocumentBuilderFactory 默认安全吗? Python XML XXE 安全:ElementTree、Expat 与 lxml