Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
package com.vince.xq.common.utils.security;

/**
* JDBC 连接安全校验工具类
*
* 防止通过恶意 JDBC URL 参数触发:
* - MySQL: allowLoadLocalInfile 文件读取, autoDeserialize 反序列化 RCE
* - PostgreSQL: socketFactory 任意类加载 RCE
* - H2: INIT 参数代码执行
*
* 校验策略: 对 URL 全文 toLowerCase() + contains() 匹配,
* 覆盖所有参数分隔符格式 (?, ;, (), address=)
*/
public class JdbcSecurityUtil {

/**
* 全驱动危险参数黑名单 (全小写)
*/
private static final String[] UNSAFE_PARAMS = {
// MySQL / MariaDB
"allowloadlocalinfile",
"allowurlinlocalinfile",
"allowloadlocalinfileinpath",
"autodeserialize",
"queryinterceptors",
"statementinterceptors",
"detectcustomcollations",
"maxallowedpacket",
// PostgreSQL
"socketfactory",
"socketfactoryarg",
"sslfactory",
"sslhostnameverifier",
"sslpasswordcallback",
"authenticationpluginclassname",
"jaasapplicationname",
// H2
"init=",
"runscript",
"trace_level_system_out",
};

/**
* 校验 JDBC URL 是否包含危险参数
*
* @param jdbcUrl JDBC 连接地址
* @throws IllegalArgumentException 包含危险参数时抛出
*/
public static void validate(String jdbcUrl) {
if (jdbcUrl == null || jdbcUrl.trim().isEmpty()) {
return;
}

String lowerUrl = jdbcUrl.toLowerCase();

for (String unsafeParam : UNSAFE_PARAMS) {
if (lowerUrl.contains(unsafeParam)) {
throw new IllegalArgumentException("JDBC URL 包含不安全参数: " + unsafeParam);
}
}
}
}
5 changes: 5 additions & 0 deletions src/main/java/com/vince/xq/project/common/RunUtil.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import com.vince.xq.project.system.ProbeJobInstance.domain.ProbeJobInstance;
import com.vince.xq.project.system.instance.controller.InstanceController;
import com.vince.xq.project.system.jobconfig.domain.Jobconfig;
import com.vince.xq.common.utils.security.JdbcSecurityUtil;
import com.vince.xq.project.system.dbconfig.domain.Dbconfig;
import com.vince.xq.project.system.instance.domain.Instance;
import com.vince.xq.project.system.probeJobConfig.domain.Probejobconfig;
Expand Down Expand Up @@ -214,6 +215,7 @@ public static List<LinkedHashMap<String, String>> runDiffDetail(Dbconfig dbconfi
throw new Exception("注册驱动失败");
}
Connection conn = null;
JdbcSecurityUtil.validate(dbconfig.getUrl());
try {
conn = DriverManager.getConnection(dbconfig.getUrl(), dbconfig.getUserName(), dbconfig.getPwd());
Statement stat = conn.createStatement();
Expand Down Expand Up @@ -250,6 +252,7 @@ public static Instance runNum(Dbconfig dbconfig, String connectDriver, String co
throw new Exception("注册驱动失败");
}
Connection conn = null;
JdbcSecurityUtil.validate(dbconfig.getUrl());
try {
conn = DriverManager.getConnection(dbconfig.getUrl(), dbconfig.getUserName(), dbconfig.getPwd());
Statement stat = conn.createStatement();
Expand Down Expand Up @@ -358,6 +361,7 @@ private static Map<String, String> runProbJobPrimaryKey(Dbconfig dbconfig, Strin
throw new Exception("注册驱动失败");
}
Connection conn = null;
JdbcSecurityUtil.validate(dbconfig.getUrl());
try {
conn = DriverManager.getConnection(dbconfig.getUrl(), dbconfig.getUserName(), dbconfig.getPwd());
Statement stat = conn.createStatement();
Expand Down Expand Up @@ -388,6 +392,7 @@ private static List<LinkedHashMap<String, String>> runProbJobField(Dbconfig dbco
throw new Exception("注册驱动失败");
}
Connection conn = null;
JdbcSecurityUtil.validate(dbconfig.getUrl());
try {
conn = DriverManager.getConnection(dbconfig.getUrl(), dbconfig.getUserName(), dbconfig.getPwd());
Statement stat = conn.createStatement();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import com.vince.xq.framework.web.page.TableDataInfo;
import com.vince.xq.project.system.dbconfig.domain.Dbconfig;
import com.vince.xq.project.system.dbconfig.service.IDbconfigService;
import com.vince.xq.common.utils.security.JdbcSecurityUtil;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
Expand Down Expand Up @@ -89,6 +90,11 @@ public String add(ModelMap mmap) {
@PostMapping("/add")
@ResponseBody
public AjaxResult addSave(@Validated Dbconfig dbconfig) {
try {
JdbcSecurityUtil.validate(dbconfig.getUrl());
} catch (IllegalArgumentException e) {
return error("连接地址安全校验失败:" + e.getMessage());
}
if (UserConstants.DBCONFIG_NAME_NOT_UNIQUE.equals(dbconfigService.checkConnectNameUnique(dbconfig))) {
return error("新增数据库连接名称'" + dbconfig.getConnectName() + "'失败,数据库连接名称已存在");
}
Expand All @@ -115,6 +121,11 @@ public String edit(@PathVariable("id") Long id, ModelMap mmap) {
@PostMapping("/edit")
@ResponseBody
public AjaxResult editSave(@Validated Dbconfig dbconfig) {
try {
JdbcSecurityUtil.validate(dbconfig.getUrl());
} catch (IllegalArgumentException e) {
return error("连接地址安全校验失败:" + e.getMessage());
}
if (UserConstants.POST_NAME_NOT_UNIQUE.equals(dbconfigService.checkConnectNameUnique(dbconfig))) {
return error("修改数据库连接名称'" + dbconfig.getConnectName() + "'失败,数据库连接名称已存在");
}
Expand All @@ -132,7 +143,10 @@ public String checkConnectNameUnique(Dbconfig dbconfig) {
@ResponseBody
public AjaxResult testConnection(Dbconfig dbconfig) {
try {
JdbcSecurityUtil.validate(dbconfig.getUrl());
dbconfigService.testConnection(dbconfig);
} catch (IllegalArgumentException e) {
return error("连接地址安全校验失败:" + e.getMessage());
} catch (Exception e) {
e.printStackTrace();
return error("错误信息:" + e.getMessage());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import com.vince.xq.project.common.DbTypeEnum;
import com.vince.xq.project.system.dbconfig.domain.Dbconfig;
import com.vince.xq.project.system.dbconfig.mapper.DbconfigMapper;
import com.vince.xq.common.utils.security.JdbcSecurityUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

Expand Down Expand Up @@ -137,6 +138,7 @@ private void testConnectionDriver(Dbconfig dbconfig, String connectDriver) throw
} catch (ClassNotFoundException e) {
throw new Exception("注册驱动失败");
}
JdbcSecurityUtil.validate(dbconfig.getUrl());
Connection conn = null;
try {
conn = DriverManager.getConnection(dbconfig.getUrl(), dbconfig.getUserName(), dbconfig.getPwd());
Expand Down