一、XXE 攻击概述
XXE(XML External Entity Injection)是一种针对 XML 解析器的注入攻击,攻击者通过构造恶意 XML 数据,利用解析器对外部实体的处理机制,读取系统文件、执行命令、发起内网扫描甚至实施拒绝服务攻击。该漏洞源于 XML 解析器默认支持外部实体引用,若应用未对输入的 XML 进行严格过滤,将直接暴露于风险之中。
二、XXE 攻击的威胁与典型安全事件
-
信息泄露
攻击者可通过外部实体引用读取任意系统文件,如/etc/passwd
、数据库配置文件等。典型案例:2013 年某电商平台因 XXE 漏洞导致用户数据库泄露。 -
服务器端请求伪造(SSRF)
利用 XML 解析器访问内网资源,如扫描内部网络、访问数据库等。2014 年某银行系统被利用 XXE 发起 SSRF 攻击,导致内部系统瘫痪。 -
拒绝服务攻击(DoS)
通过构造恶意 XML(如十亿 laughs 攻击)耗尽服务器资源。 -
远程代码执行
在某些环境下,攻击者可通过 XXE 执行系统命令,完全控制服务器。
三、Java 中 XXE 漏洞的修复方案
1. 禁用 XML 解析器的外部实体解析
Java 提供了多种 XML 解析 API,包括 DOM、SAX 和 StAX,以下是针对不同解析器的安全配置示例:
SAXParser 安全配置
java
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import org.xml.sax.InputSource;
public class SecureSAXParserExample {
public static void main(String[] args) throws Exception {
SAXParserFactory factory = SAXParserFactory.newInstance();
// 禁用外部实体解析
factory.setFeature("http://xml.org/sax/features/external-general-entities", false);
factory.setFeature("http://xml.org/sax/features/external-parameter-entities", false);
// 禁用DTD解析
factory.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
SAXParser parser = factory.newSAXParser();
// 解析XML
parser.parse(new InputSource("input.xml"), new org.xml.sax.helpers.DefaultHandler());
}
}
DOM Parser 安全配置
java
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
public class SecureDOMParserExample {
public static void main(String[] args) throws Exception {
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
// 禁用外部实体解析
factory.setFeature("http://xml.org/sax/features/external-general-entities", false);
factory.setFeature("http://xml.org/sax/features/external-parameter-entities", false);
// 禁用DTD解析
factory.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
// 防止XInclude攻击
factory.setXIncludeAware(false);
DocumentBuilder builder = factory.newDocumentBuilder();
// 解析XML
builder.parse("input.xml");
}
}
2. 使用安全的 TransformerFactory
java
import javax.xml.transform.TransformerFactory;
public class SecureTransformerExample {
public static void main(String[] args) {
TransformerFactory factory = TransformerFactory.newInstance();
// 禁用外部实体解析
factory.setAttribute("http://javax.xml.XMLConstants/property/accessExternalDTD", "");
factory.setAttribute("http://javax.xml.XMLConstants/property/accessExternalStylesheet", "");
}
}
3. JAXB 反序列化安全配置
java
import javax.xml.bind.JAXBContext;
import javax.xml.bind.Unmarshaller;
import com.sun.xml.bind.v2.runtime.unmarshaller.UnmarshallerImpl;
public class SecureJAXBExample {
public static void main(String[] args) throws Exception {
JAXBContext jc = JAXBContext.newInstance(MyClass.class);
Unmarshaller unmarshaller = jc.createUnmarshaller();
// 配置安全的XMLReader
if (unmarshaller instanceof UnmarshallerImpl) {
((UnmarshallerImpl) unmarshaller).setXMLReader(createSecureXMLReader());
}
}
private static org.xml.sax.XMLReader createSecureXMLReader() throws Exception {
SAXParserFactory factory = SAXParserFactory.newInstance();
factory.setFeature("http://xml.org/sax/features/external-general-entities", false);
factory.setFeature("http://xml.org/sax/features/external-parameter-entities", false);
factory.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
return factory.newSAXParser().getXMLReader();
}
}
4. 使用 StAX 解析器(XMLStreamReader)
java
import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLStreamReader;
import java.io.FileInputStream;
public class SecureStAXExample {
public static void main(String[] args) throws Exception {
XMLInputFactory factory = XMLInputFactory.newInstance();
// 禁用外部实体解析
factory.setProperty(XMLInputFactory.SUPPORT_DTD, false);
factory.setProperty("javax.xml.stream.isSupportingExternalEntities", false);
XMLStreamReader reader = factory.createXMLStreamReader(new FileInputStream("input.xml"));
// 处理XML
while (reader.hasNext()) {
reader.next();
// 处理逻辑
}
}
}
四、进阶防护措施
-
输入验证与过滤
使用正则表达式或白名单过滤 XML 输入,禁止包含<!DOCTYPE
、<!ENTITY
等关键字的内容。 -
升级依赖库
确保使用最新版本的 XML 解析库,修复已知漏洞(如 Apache Xerces-C/J)。 -
使用安全解析器工厂
封装安全配置,创建可复用的安全解析器工厂:
java
public class SecureXMLFactory {
public static SAXParserFactory createSecureSAXParserFactory() {
SAXParserFactory factory = SAXParserFactory.newInstance();
try {
factory.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
factory.setFeature("http://xml.org/sax/features/external-general-entities", false);
factory.setFeature("http://xml.org/sax/features/external-parameter-entities", false);
factory.setNamespaceAware(true);
} catch (Exception e) {
// 记录安全配置失败
e.printStackTrace();
}
return factory;
}
}
五、XXE 防护最佳实践
-
默认拒绝原则
除非明确需要,否则禁止所有外部实体引用。 -
使用替代数据格式
优先使用 JSON 替代 XML,避免解析风险。 -
安全审计
使用 OWASP ZAP 等工具进行漏洞扫描,定期审查 XML 处理代码。 -
异常处理
捕获并记录 XML 解析异常,避免信息泄露:
java
try {
// XML解析代码
} catch (Exception e) {
logger.error("XML解析失败: {}", e.getMessage());
// 返回安全错误信息给客户端
throw new SecurityException("无效的XML格式");
}
六、总结
XXE 攻击因其隐蔽性和高危害性,成为 Java 应用的重大安全隐患。通过禁用外部实体解析、配置安全解析器、严格输入验证等措施,可有效防范此类攻击。开发团队应将安全编码规范融入 SDLC(软件开发生命周期),结合自动化安全测试,构建多层次的安全防护体系。
参考资源:
- OWASP Top Ten: XML External Entity (XXE)
- CWE-611: Improper Restriction of XML External Entity Reference
- Java Secure Coding Guidelines - XML Processing