本文目录导读:

彻底关闭XXE漏洞,不能仅靠单一操作,而需要根据应用场景进行分层防御,以下是经过验证的彻底关闭方案,按优先级排序:
核心原则:除非绝对必要,否则完全禁用外部实体解析。
完全禁用外部实体(最彻底、最推荐)
这是最安全的做法,如果业务根本不需要处理XML实体(例如仅仅是数据传输),直接禁用即可。
通用解析器配置(适用于大多数编程语言)
| 配置项 | 说明 | 示例 |
|---|---|---|
setFeature("http://apache.org/xml/features/disallow-doctype-decl", true) |
完全禁止DOCTYPE声明,这是最优先、最简单的开关,一旦开启,任何包含<!DOCTYPE的XML都会被拒绝。 |
Java: DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); dbf.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true); |
setFeature("http://xml.org/sax/features/external-general-entities", false) |
禁止解析外部普通实体(如 &xxe; 指向外部文件/URL)。 |
Python (lxml): parser = etree.XMLParser(resolve_entities=False, no_network=True) |
setFeature("http://xml.org/sax/features/external-parameter-entities", false) |
禁止解析外部参数实体(%xxe;,常用于DTD中加载外部文件发起攻击)。 |
PHP (libxml): libxml_disable_entity_loader(true); 或 new DOMDocument(['LIBXML_NOENT' => false, 'LIBXML_DTDLOAD' => false]) |
禁用外部实体加载(no_network / LIBXML_NONET)
还需禁止解析器主动发起网络请求加载外部资源。
- Java: 同样使用
setFeature,但禁用了general-entities和parameter-entities后,网络请求也被阻止。 - Python:
parser = etree.XMLParser(no_network=True)禁止从URL加载DTD或实体。 - C# (.NET): 设置
XmlReaderSettings.DtdProcessing = DtdProcessing.Prohibit(彻底禁用DTD处理)。 - PHP:
libxml_disable_entity_loader(true);会禁用从外部加载资源。注意:PHP 8.0+ 中该函数已废弃,推荐直接使用LIBXML_NOENT和LIBXML_DTDLOAD参数。
加固过滤器(当必须使用外部实体时)
如果业务确实需要解析外部实体(例如引用内网配置文件),上述禁用方案会破坏业务,此时需要白名单+输入验证。
-
禁用
SYSTEM和PUBLIC标识符:如果业务只需要解析内部定义的实体(如<),禁止使用外部来源。- 在代码级别,检查输入的XML是否包含
SYSTEM或PUBLIC- 若包含
<!ENTITY xxe SYSTEM "..."或<!ENTITY % xxe PUBLIC "...",直接拒绝请求。 - 若包含
- 在代码级别,检查输入的XML是否包含
-
禁用
file:///expect://等危险协议- 配置白名单,只允许特定协议(如
http://,https://指向内部特定服务)。 - 明确禁止:
file://,expect://,php://,jar://,gopher://,data://等。
- 配置白名单,只允许特定协议(如
-
限制外部资源来源
- 如果必须允许加载外部DTD,将来源限制为内部已知的、安全的服务器IP或域名。
- 使用网络级别的防火墙或代理,拦截解析器发出的、未经授权的DNS或HTTP请求。
方案3:升级解析库与使用安全解析器
旧版本的解析器(如 Java 1.8 以下的 DocumentBuilderFactory、老版 libxml2)默认配置不安全。
- 升级版本:确保你使用的XML解析库是最新稳定版,现代库(如 Java 11+ 的 DOM、SAX、StAX;Python 3.x 的
xml.etree.ElementTree;PHP 8.0+ 的 libxml2)在默认配置下,部分实体解析已被禁用,但仍需显式禁用以杜绝漏网之鱼。 - 使用安全解析器:
- Java:推荐使用
XMLInputFactory(StAX) 或SAXParserFactory,通过上述setFeature进行配置。 - Python:默认的
xml.etree.ElementTree较安全,不解析外部实体,但使用lxml时,需手动设置resolve_entities=False。 - .NET:从 .NET Framework 4.5.2 开始,默认
XmlReader不再解析外部实体。但:如果使用XDocument.Load且未传入XmlReaderSettings,可能仍存在风险。正确做法:始终传入new XmlReaderSettings { DtdProcessing = DtdProcessing.Prohibit, XmlResolver = null }。
- Java:推荐使用
终极检查清单(逐项确认)
- 禁用DOCTYPE:
disallow-doctype-decl=true(最优先)。 - 禁用外部实体:
external-general-entities=false和external-parameter-entities=false。 - 禁用网络加载:
no_network=true或LIBXML_NONET。 - 禁用DTD处理:
dtdProcessing=Prohibit(.NET特有)。 - 升级解析库:使用最新稳定版。
- 避免使用危险API:
- 少用
javax.xml.parsers.DocumentBuilder(若必须用,务必设置)。 - 不用
XmlDocument.LoadXml()(C#) 而不带XmlReaderSettings。 - 不用
simplexml_load_file()(PHP) 而不禁用实体加载。
- 少用
最彻底的方式:
disallow-doctype-decl设为true。如果无法做到,则必须同时禁用外部实体解析、禁用外部网络请求,并拒绝
SYSTEM/PUBLIC关键字。