Jdbc Attack防护绕过浅析
字数 1932 2025-08-18 11:35:36
JDBC Attack防护绕过技术深入分析
0x00 前言
当传入DriverManager.getConnection(jdbcUrl)中的jdbcUrl用户任意可控时,通过构造恶意的jdbcUrl(恶意连接属性、恶意连接类型等),在JDBC Driver处理jdbcUrl进行连接的过程中进行恶意操作(这类JDBC Driver本身是有漏洞的),可能导致任意文件读取、RCE等严重危害。
0x01 常见防护方法
JDBC连接字符串通常格式为:
jdbc:<type>://<hosts|host:port>/<db><properties>
常见防护措施包括:
-
数据源类型(type)限制:
- 使用黑白名单限制可连接的数据源类型
- 防止调用高风险数据源如mysql、postgresql等
-
host/port/db字段格式限制:
- port限制只允许数字
- host字段限制字符集(字母、数字、中文、点、短横线、斜杠、冒号等)
-
连接属性(properties)黑名单:
- 维护不同数据源的恶意连接属性黑名单
- 以MySQL为例,防护的关键属性包括:
private static final Map SENSITIVE_REPLACE_PARAM_MAP = new HashMap() { { put("autoDeserialize", "false"); put("allowLoadLocalInfile", "false"); put("allowUrlInLocalInfile", "false"); } }; private static final Set SENSITIVE_REMOVE_PARAM_MAP = new HashSet() { { add("allowLoadLocalInfileInPath"); } };
0x02 绕过方式
2.1 使用特定的值替换
MySQL JDBC驱动中,autoDeserialize参数设置为true或yes效果相同:
- 各版本实现:
- 8.0.12:
com.mysql.cj.conf.BooleanPropertyDefinition中TRUE和YES等效 - 6.0.5:
com.mysql.cj.core.conf.BooleanPropertyDefinition#getAllowableValues同样处理 - 5.1.1:
BooleanConnectionProperty#getAllowableValues处理方式相同
- 8.0.12:
绕过方法:使用autoDeserialize=yes代替autoDeserialize=true
2.2 大小写绕过
MySQL驱动解析时会统一转换大小写:
- 8.0.12:调用
toUpperCase()统一大写 - 其他版本:使用
equalsIgnoreCase()进行不区分大小写比较
绕过方法:使用autoDeserialize=TrUe等变体
2.3 URL编码绕过
MySQL驱动解析时会进行URL解码:
-
8.0.x版本:
- 对协议、path和参数都进行URL解码
- 解析流程:
getConnection→connect→ConnectionUrl.acceptsUrl→ConnectionUrlParser#parseConnectionString
-
5.1.x版本:
- 仅对参数值进行解码
绕过方法:
- 8.0.x:对参数名和值都编码,如
%61%75%74%6f%44%65%73%65%72%69%61%6c%69%7a%65=%74%72%75%65 - 5.1.x:仅对参数值编码
2.4 头尾空白符绕过
当防护代码使用split分割参数时:
String[] keyValue = pair.split("=");
String key = keyValue[0];
String value = keyValue.length > 1 ? keyValue[1] : "";
而MySQL驱动(8.0.12)会调用StringUtils#safeTrim去除空白符:
绕过方法:
- 使用
autoDeserialize = true(含空格) - 使用制表符
\t等空白字符(如CVE-2023-46227案例)
2.5 使用注释符
MySQL 8.0.x支持#作为注释符:
- 解析时使用正则
[^#]*匹配查询参数,忽略#后内容 - 5.1.x不支持此特性
绕过方法:
- 在8.0.x中:
autoDeserialize=true#&autoDeserialize=false
2.6 注入拼接
当jdbcUrl通过拼接用户输入构建时:
StringBuilder url = new StringBuilder("jdbc:mysql://");
url.append(host).append(":").append(port).append("/").append(dbname);
url.append("?user=").append(user).append("&password=").append(password);
绕过方法:
- 在user/password字段注入恶意参数,如
user=root&autoDeserialize=true
0x03 防护建议
-
组件升级:
- 升级数据源组件至安全版本(如mysql-connector/j 8.0.21+)
- 考虑使用替代组件(如mariadb-java-client替换mysql-connector-java)
-
输入归一化处理:
- 统一大小写
- URL解码
- 去除所有空白字符(包括
\t等) - 处理注释符
#
-
严格输入校验:
- 限制数据源type为预期值
- port字段严格限制为数字
- user/password字段禁止包含
=等敏感字符
-
参数处理优化:
- 使用
java.net.URI解析jdbcUrl,利用其非法字符检测 - 修复示例:
String jdbcUrl = url.replaceAll("\\s", ""); URI uri = new URI(jdbcUrl.replace("jdbc:", "")); String query = uri.getQuery();
- 使用
-
黑名单维护:
- 长期维护各数据源的恶意属性黑名单
- 覆盖所有可能的变体(如yes/true、大小写、编码等)
通过综合应用以上防护措施,可有效降低JDBC Attack的风险。