mirror of https://github.com/jeecgboot/jeecg-boot
--重构表字典逻辑,深度解决SQL注入漏洞问题(修复导致的bug修复)--
parent
44952c79c2
commit
473875a9d2
|
@ -6,6 +6,7 @@ import com.baomidou.dynamic.datasource.spring.boot.autoconfigure.DynamicDataSour
|
||||||
import com.baomidou.mybatisplus.annotation.DbType;
|
import com.baomidou.mybatisplus.annotation.DbType;
|
||||||
import com.baomidou.mybatisplus.extension.toolkit.JdbcUtils;
|
import com.baomidou.mybatisplus.extension.toolkit.JdbcUtils;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.apache.commons.lang.StringUtils;
|
||||||
import org.jeecg.common.constant.CommonConstant;
|
import org.jeecg.common.constant.CommonConstant;
|
||||||
import org.jeecg.common.constant.DataBaseConstant;
|
import org.jeecg.common.constant.DataBaseConstant;
|
||||||
import org.jeecg.common.constant.ServiceNameConstants;
|
import org.jeecg.common.constant.ServiceNameConstants;
|
||||||
|
@ -26,6 +27,7 @@ import java.io.InputStream;
|
||||||
import java.sql.Connection;
|
import java.sql.Connection;
|
||||||
import java.sql.DatabaseMetaData;
|
import java.sql.DatabaseMetaData;
|
||||||
import java.sql.SQLException;
|
import java.sql.SQLException;
|
||||||
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.regex.Matcher;
|
import java.util.regex.Matcher;
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
|
@ -145,7 +147,7 @@ public class CommonUtils {
|
||||||
* @param bizPath 自定义路径
|
* @param bizPath 自定义路径
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
public static String uploadLocal(MultipartFile mf,String bizPath,String uploadpath){
|
public static String uploadLocal(MultipartFile mf, String bizPath, String uploadpath){
|
||||||
try {
|
try {
|
||||||
//update-begin-author:liusq date:20210809 for: 过滤上传文件类型
|
//update-begin-author:liusq date:20210809 for: 过滤上传文件类型
|
||||||
FileTypeFilter.fileTypeFilter(mf);
|
FileTypeFilter.fileTypeFilter(mf);
|
||||||
|
@ -272,7 +274,7 @@ public class CommonUtils {
|
||||||
if(db==null){
|
if(db==null){
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
DriverManagerDataSource ds = new DriverManagerDataSource ();
|
DriverManagerDataSource ds = new DriverManagerDataSource();
|
||||||
ds.setDriverClassName(db.getDriverClassName());
|
ds.setDriverClassName(db.getDriverClassName());
|
||||||
ds.setUrl(db.getUrl());
|
ds.setUrl(db.getUrl());
|
||||||
ds.setUsername(db.getUsername());
|
ds.setUsername(db.getUsername());
|
||||||
|
@ -392,4 +394,47 @@ public class CommonUtils {
|
||||||
return target;
|
return target;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将list集合以分割符的方式进行分割
|
||||||
|
* @param list String类型的集合文本
|
||||||
|
* @param separator 分隔符
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public static String getSplitText(List<String> list, String separator) {
|
||||||
|
if (null != list && list.size() > 0) {
|
||||||
|
return StringUtils.join(list, separator);
|
||||||
|
}
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 通过table的条件SQL
|
||||||
|
*
|
||||||
|
* @param tableSql sys_user where name = '1212'
|
||||||
|
* @return name = '1212'
|
||||||
|
*/
|
||||||
|
public static String getFilterSqlByTableSql(String tableSql) {
|
||||||
|
if (tableSql.toLowerCase().indexOf(DataBaseConstant.SQL_WHERE) > 0) {
|
||||||
|
String[] arr = tableSql.split(" (?i)where ");
|
||||||
|
if (arr != null && oConvertUtils.isNotEmpty(arr[1])) {
|
||||||
|
return arr[1];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 通过table获取表名
|
||||||
|
*
|
||||||
|
* @param tableSql sys_user where name = '1212'
|
||||||
|
* @return sys_user
|
||||||
|
*/
|
||||||
|
public static String getTableNameByTableSql(String tableSql) {
|
||||||
|
if (tableSql.toLowerCase().indexOf(DataBaseConstant.SQL_WHERE) > 0) {
|
||||||
|
String[] arr = tableSql.split(" (?i)where ");
|
||||||
|
return arr[0].trim();
|
||||||
|
} else {
|
||||||
|
return tableSql;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -18,6 +18,7 @@ import org.jeecg.common.system.util.ResourceUtil;
|
||||||
import org.jeecg.common.system.vo.DictModel;
|
import org.jeecg.common.system.vo.DictModel;
|
||||||
import org.jeecg.common.system.vo.DictModelMany;
|
import org.jeecg.common.system.vo.DictModelMany;
|
||||||
import org.jeecg.common.system.vo.DictQuery;
|
import org.jeecg.common.system.vo.DictQuery;
|
||||||
|
import org.jeecg.common.util.CommonUtils;
|
||||||
import org.jeecg.common.util.SqlInjectionUtil;
|
import org.jeecg.common.util.SqlInjectionUtil;
|
||||||
import org.jeecg.common.util.oConvertUtils;
|
import org.jeecg.common.util.oConvertUtils;
|
||||||
import org.jeecg.config.mybatis.MybatisPlusSaasConfig;
|
import org.jeecg.config.mybatis.MybatisPlusSaasConfig;
|
||||||
|
@ -456,18 +457,18 @@ public class SysDictServiceImpl extends ServiceImpl<SysDictMapper, SysDict> impl
|
||||||
// }
|
// }
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<DictModel> queryLittleTableDictItems(String table, String text, String code, String condition, String keyword, int pageSize) {
|
public List<DictModel> queryLittleTableDictItems(String tableSql, String text, String code, String condition, String keyword, int pageSize) {
|
||||||
Page<DictModel> page = new Page<DictModel>(1, pageSize);
|
Page<DictModel> page = new Page<DictModel>(1, pageSize);
|
||||||
page.setSearchCount(false);
|
page.setSearchCount(false);
|
||||||
|
|
||||||
//为了防止sql(jeecg提供了防注入的方法,可以在拼接 SQL 语句时自动对参数进行转义,避免SQL注入攻击)
|
//为了防止sql(jeecg提供了防注入的方法,可以在拼接 SQL 语句时自动对参数进行转义,避免SQL注入攻击)
|
||||||
// 1. 针对采用 ${}写法的表名和字段进行转义和check
|
// 1. 针对采用 ${}写法的表名和字段进行转义和check
|
||||||
table = SqlInjectionUtil.getSqlInjectTableName(table);
|
String table = SqlInjectionUtil.getSqlInjectTableName(CommonUtils.getTableNameByTableSql(tableSql));
|
||||||
text = SqlInjectionUtil.getSqlInjectField(text);
|
text = SqlInjectionUtil.getSqlInjectField(text);
|
||||||
code = SqlInjectionUtil.getSqlInjectField(code);
|
code = SqlInjectionUtil.getSqlInjectField(code);
|
||||||
|
|
||||||
// 2. 查询条件SQL (获取条件sql方法含sql注入校验)
|
// 2. 查询条件SQL (获取条件sql方法含sql注入校验)
|
||||||
String filterSql = getFilterSql(table, text, code, condition, keyword);
|
String filterSql = getFilterSql(tableSql, text, code, condition, keyword);
|
||||||
|
|
||||||
// 3. 返回表字典数据
|
// 3. 返回表字典数据
|
||||||
IPage<DictModel> pageList = baseMapper.queryPageTableDictWithFilter(page, table, text, code, filterSql);
|
IPage<DictModel> pageList = baseMapper.queryPageTableDictWithFilter(page, table, text, code, filterSql);
|
||||||
|
@ -475,21 +476,22 @@ public class SysDictServiceImpl extends ServiceImpl<SysDictMapper, SysDict> impl
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取条件语句
|
* 获取条件语句 (下拉搜索组件 支持传入排序信息 查询排序)
|
||||||
|
*
|
||||||
* @param text
|
* @param text
|
||||||
* @param code
|
* @param code
|
||||||
* @param condition
|
* @param condition
|
||||||
* @param keyword
|
* @param keyword
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
private String getFilterSql(String table, String text, String code, String condition, String keyword){
|
private String getFilterSql(String tableSql, String text, String code, String condition, String keyword){
|
||||||
String filterSql = "";
|
String filterSql = "";
|
||||||
String keywordSql = null;
|
String keywordSql = null;
|
||||||
String sqlWhere = "where ";
|
String sqlWhere = "where ";
|
||||||
|
|
||||||
//【JTC-631】判断如果 table 携带了 where 条件,那么就使用 and 查询,防止报错
|
//【JTC-631】判断如果 table 携带了 where 条件,那么就使用 and 查询,防止报错
|
||||||
if (table.toLowerCase().contains(sqlWhere)) {
|
if (tableSql.toLowerCase().contains(sqlWhere)) {
|
||||||
sqlWhere = " and ";
|
sqlWhere = CommonUtils.getFilterSqlByTableSql(tableSql) + " and ";
|
||||||
}
|
}
|
||||||
|
|
||||||
// 下拉搜索组件 支持传入排序信息 查询排序
|
// 下拉搜索组件 支持传入排序信息 查询排序
|
||||||
|
@ -532,13 +534,16 @@ public class SysDictServiceImpl extends ServiceImpl<SysDictMapper, SysDict> impl
|
||||||
filterSql += " order by " + orderField + " " + orderType;
|
filterSql += " order by " + orderField + " " + orderType;
|
||||||
}
|
}
|
||||||
|
|
||||||
// result.1 返回条件SQL(去掉 where 关键词)
|
// 处理返回条件
|
||||||
final String wherePattern = "(?i)where "; // (?i) 表示不区分大小写
|
// 1.1 返回条件SQL(去掉开头的 where )
|
||||||
String filterSqlString = filterSql.trim().replaceAll(wherePattern, "");
|
final String wherePrefix = "(?i)where "; // (?i) 表示不区分大小写
|
||||||
|
String filterSqlString = filterSql.trim().replaceAll(wherePrefix, "");
|
||||||
// result.2 条件SQL进行漏洞 check
|
// 1.2 条件SQL进行漏洞 check
|
||||||
SqlInjectionUtil.specialFilterContentForDictSql(filterSqlString);
|
SqlInjectionUtil.specialFilterContentForDictSql(filterSqlString);
|
||||||
|
// 1.3 判断如何返回条件是 order by开头则前面拼上 1=1
|
||||||
|
if (oConvertUtils.isNotEmpty(filterSqlString) && filterSqlString.trim().toUpperCase().startsWith("ORDER")) {
|
||||||
|
filterSqlString = " 1=1 " + filterSqlString;
|
||||||
|
}
|
||||||
return filterSqlString;
|
return filterSqlString;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue