处理jsqlparser兼容问题

pull/8125/head
EightMonth 2025-04-22 16:00:17 +08:00
parent b70e709e53
commit 748331d649
4 changed files with 303 additions and 274 deletions

View File

@ -19,7 +19,7 @@
<groupId>org.hibernate</groupId> <groupId>org.hibernate</groupId>
<artifactId>hibernate-core</artifactId> <artifactId>hibernate-core</artifactId>
</dependency> </dependency>
<!--<dependency> <!-- <dependency>
<groupId>org.jeecgframework.boot3</groupId> <groupId>org.jeecgframework.boot3</groupId>
<artifactId>hibernate-re</artifactId> <artifactId>hibernate-re</artifactId>
</dependency>--> </dependency>-->
@ -30,19 +30,31 @@
<artifactId>weixin4j</artifactId> <artifactId>weixin4j</artifactId>
</dependency> </dependency>
<!-- 积木报表 --> <!-- 积木报表 -->
<!--<dependency> <dependency>
<groupId>org.jeecgframework.jimureport</groupId> <groupId>org.jeecgframework.jimureport</groupId>
<artifactId>jimureport-spring-boot3-starter-fastjson2</artifactId> <artifactId>jimureport-spring-boot3-starter-fastjson2</artifactId>
<exclusions>
<exclusion>
<groupId>com.github.jsqlparser</groupId>
<artifactId>jsqlparser</artifactId>
</exclusion>
</exclusions>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.jeecgframework.jimureport</groupId> <groupId>org.jeecgframework.jimureport</groupId>
<artifactId>jimureport-nosql-starter</artifactId> <artifactId>jimureport-nosql-starter</artifactId>
</dependency> </dependency>
&lt;!&ndash; 积木BI &ndash;&gt; <!-- 积木BI -->
<dependency> <dependency>
<groupId>org.jeecgframework.jimureport</groupId> <groupId>org.jeecgframework.jimureport</groupId>
<artifactId>jimubi-spring-boot3-starter</artifactId> <artifactId>jimubi-spring-boot3-starter</artifactId>
</dependency>--> <exclusions>
<exclusion>
<groupId>com.github.jsqlparser</groupId>
<artifactId>jsqlparser</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies> </dependencies>
</project> </project>

View File

@ -1,6 +1,11 @@
package org.jeecg.config.firewall.SqlInjection.impl; package org.jeecg.config.firewall.SqlInjection.impl;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import net.sf.jsqlparser.JSQLParserException;
import net.sf.jsqlparser.parser.CCJSqlParserUtil;
import net.sf.jsqlparser.schema.Table;
import net.sf.jsqlparser.statement.select.PlainSelect;
import net.sf.jsqlparser.statement.select.Select;
import org.jeecg.common.constant.SymbolConstant; import org.jeecg.common.constant.SymbolConstant;
import org.jeecg.common.exception.JeecgSqlInjectionException; import org.jeecg.common.exception.JeecgSqlInjectionException;
import org.jeecg.common.util.oConvertUtils; import org.jeecg.common.util.oConvertUtils;
@ -12,8 +17,11 @@ import org.jeecg.config.firewall.interceptor.LowCodeModeInterceptor;
import org.jeecg.modules.system.entity.SysTableWhiteList; import org.jeecg.modules.system.entity.SysTableWhiteList;
import org.jeecg.modules.system.security.DictQueryBlackListHandler; import org.jeecg.modules.system.security.DictQueryBlackListHandler;
import org.jeecg.modules.system.service.ISysTableWhiteListService; import org.jeecg.modules.system.service.ISysTableWhiteListService;
import org.jeecgframework.minidao.sqlparser.AbstractSqlProcessor;
import org.jeecgframework.minidao.sqlparser.impl.JsqlparserSqlProcessor;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import org.jeecgframework.minidao.util.MiniDaoUtil;
import java.net.URLDecoder; import java.net.URLDecoder;
import java.util.*; import java.util.*;
@ -63,33 +71,41 @@ public class DictTableWhiteListHandlerImpl implements IDictTableWhiteListHandler
@Override @Override
public boolean isPassBySql(String sql) { public boolean isPassBySql(String sql) {
// Map<String, SelectSqlInfo> parsedMap = null; Select select = null;
// try {
// parsedMap = JSqlParserUtils.parseAllSelectTable(sql); try {
// } catch (Exception e) { select = (Select) CCJSqlParserUtil.parse(sql, (parser) -> {
// log.warn("校验sql语句解析报错{}", e.getMessage()); parser.withSquareBracketQuotation(true);
// } });
// // 如果sql有问题则肯定执行不了所以直接返回true } catch (JSQLParserException var10) {
// if (parsedMap == null) { JSQLParserException jsqlParserException = var10;
// return true; jsqlParserException.printStackTrace();
// } }
// log.info("获取select sql信息 {} ", parsedMap);
// // 遍历当前sql中的所有表名如果有其中一个表或表的字段不在白名单中则不通过 String tableName = ((Table)((PlainSelect)select.getSelectBody()).getFromItem()).getName();
// for (Map.Entry<String, SelectSqlInfo> entry : parsedMap.entrySet()) {
// SelectSqlInfo sqlInfo = entry.getValue(); List<Map<String, Object>> parsedMap = null;
// if (sqlInfo.isSelectAll()) { try {
// log.warn("查询语句中包含 * 字段,暂时先通过"); parsedMap = MiniDaoUtil.parseSqlFields(sql);
// continue; } catch (Exception e) {
// } log.warn("校验sql语句解析报错{}", e.getMessage());
// Set<String> queryFields = sqlInfo.getAllRealSelectFields(); }
// // 校验表名和字段是否允许查询 // 如果sql有问题则肯定执行不了所以直接返回true
// String tableName = entry.getKey(); if (parsedMap == null) {
// if (!this.checkWhiteList(tableName, queryFields)) {
// return false;
// }
// }
return true; return true;
} }
log.info("获取select sql信息 {} ", parsedMap);
// 遍历当前sql中的所有表名如果有其中一个表或表的字段不在白名单中则不通过
if (!this.checkWhiteList(tableName, parsedMap.get(0).keySet())) {
return false;
}
return true;
}
public static void main(String[] args) {
String sql = "select id,name,page from dual;";
System.out.println(MiniDaoUtil.parseSqlFields(sql));
}
@Override @Override
public boolean isPassByDict(String dictCodeString) { public boolean isPassByDict(String dictCodeString) {
@ -120,21 +136,22 @@ public class DictTableWhiteListHandlerImpl implements IDictTableWhiteListHandler
if (oConvertUtils.isEmpty(tableName)) { if (oConvertUtils.isEmpty(tableName)) {
return true; return true;
} }
// if (fields == null || fields.length == 0) { if (fields == null || fields.length == 0) {
// fields = new String[]{"*"}; fields = new String[]{"*"};
// } }
// String sql = "select " + String.join(",", fields) + " from " + tableName; String sql = "select " + String.join(",", fields) + " from " + tableName;
// log.info("字典拼接的查询SQL{}", sql); log.info("字典拼接的查询SQL{}", sql);
// try { try {
// // 进行SQL解析 // 进行SQL解析
MiniDaoUtil.parseSqlFields(sql);
// JSqlParserUtils.parseSelectSqlInfo(sql); // JSqlParserUtils.parseSelectSqlInfo(sql);
// } catch (Exception e) { } catch (Exception e) {
// // 如果SQL解析失败则通过字段名和表名进行校验 // 如果SQL解析失败则通过字段名和表名进行校验
// return checkWhiteList(tableName, new HashSet<>(Arrays.asList(fields))); return checkWhiteList(tableName, new HashSet<>(Arrays.asList(fields)));
// } }
// // 通过SQL解析进行校验可防止SQL注入 // 通过SQL解析进行校验可防止SQL注入
// return this.isPassBySql(sql); return this.isPassBySql(sql);
return true; // return true;
} }
/** /**

View File

@ -1,124 +1,124 @@
//package org.jeecg.config.jimureport; package org.jeecg.config.jimureport;
//
//import com.alibaba.fastjson.JSONObject; import com.alibaba.fastjson.JSONObject;
//import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
//import org.jeecg.common.api.dto.LogDTO; import org.jeecg.common.api.dto.LogDTO;
//import org.jeecg.common.system.api.ISysBaseAPI; import org.jeecg.common.system.api.ISysBaseAPI;
//import org.jeecg.common.system.vo.DictModel; import org.jeecg.common.system.vo.DictModel;
//import org.jeecg.common.util.oConvertUtils; import org.jeecg.common.util.oConvertUtils;
//import org.jeecg.modules.base.service.BaseCommonService; import org.jeecg.modules.base.service.BaseCommonService;
//import org.jeecg.modules.drag.service.IOnlDragExternalService; import org.jeecg.modules.drag.service.IOnlDragExternalService;
//import org.jeecg.modules.drag.vo.DragDictModel; import org.jeecg.modules.drag.vo.DragDictModel;
//import org.jeecg.modules.drag.vo.DragLogDTO; import org.jeecg.modules.drag.vo.DragLogDTO;
//import org.springframework.beans.BeanUtils; import org.springframework.beans.BeanUtils;
//import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
//import org.springframework.context.annotation.Lazy; import org.springframework.context.annotation.Lazy;
//import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
//import org.springframework.util.CollectionUtils; import org.springframework.util.CollectionUtils;
//
//import java.util.ArrayList; import java.util.ArrayList;
//import java.util.HashMap; import java.util.HashMap;
//import java.util.List; import java.util.List;
//import java.util.Map; import java.util.Map;
//
///** /**
// * @Description: 字典处理 * @Description:
// * @Author: lsq * @Author: lsq
// * @Date:2023-01-09 * @Date:2023-01-09
// * @Version:V1.0 * @Version:V1.0
// */ */
//@Slf4j @Slf4j
//@Service("onlDragExternalServiceImpl") @Service("onlDragExternalServiceImpl")
//public class JimuDragExternalServiceImpl implements IOnlDragExternalService { public class JimuDragExternalServiceImpl implements IOnlDragExternalService {
//
// @Autowired @Autowired
// @Lazy @Lazy
// private BaseCommonService baseCommonService; private BaseCommonService baseCommonService;
//
// @Autowired @Autowired
// @Lazy @Lazy
// private ISysBaseAPI sysBaseApi; private ISysBaseAPI sysBaseApi;
// /** /**
// * 根据多个字典code查询多个字典项 * code
// * @param codeList * @param codeList
// * @return key = dictCode value=对应的字典项 * @return key = dictCode value=
// */ */
// @Override @Override
// public Map<String, List<DragDictModel>> getManyDictItems(List<String> codeList, List<JSONObject> tableDictList) { public Map<String, List<DragDictModel>> getManyDictItems(List<String> codeList, List<JSONObject> tableDictList) {
// Map<String, List<DragDictModel>> manyDragDictItems = new HashMap<>(); Map<String, List<DragDictModel>> manyDragDictItems = new HashMap<>();
// if(!CollectionUtils.isEmpty(codeList)){ if(!CollectionUtils.isEmpty(codeList)){
// Map<String, List<DictModel>> dictItemsMap = sysBaseApi.getManyDictItems(codeList); Map<String, List<DictModel>> dictItemsMap = sysBaseApi.getManyDictItems(codeList);
// dictItemsMap.forEach((k,v)->{ dictItemsMap.forEach((k,v)->{
// List<DragDictModel> dictItems = new ArrayList<>(); List<DragDictModel> dictItems = new ArrayList<>();
// v.forEach(dictItem->{ v.forEach(dictItem->{
// DragDictModel dictModel = new DragDictModel(); DragDictModel dictModel = new DragDictModel();
// BeanUtils.copyProperties(dictItem,dictModel); BeanUtils.copyProperties(dictItem,dictModel);
// dictItems.add(dictModel); dictItems.add(dictModel);
// }); });
// manyDragDictItems.put(k,dictItems); manyDragDictItems.put(k,dictItems);
// }); });
// } }
//
// if(!CollectionUtils.isEmpty(tableDictList)){ if(!CollectionUtils.isEmpty(tableDictList)){
// tableDictList.forEach(item->{ tableDictList.forEach(item->{
// List<DragDictModel> dictItems = new ArrayList<>(); List<DragDictModel> dictItems = new ArrayList<>();
// JSONObject object = JSONObject.parseObject(item.toString()); JSONObject object = JSONObject.parseObject(item.toString());
// String dictField = object.getString("dictField"); String dictField = object.getString("dictField");
// String dictTable = object.getString("dictTable"); String dictTable = object.getString("dictTable");
// String dictText = object.getString("dictText"); String dictText = object.getString("dictText");
// String fieldName = object.getString("fieldName"); String fieldName = object.getString("fieldName");
// List<DictModel> dictItemsList = sysBaseApi.queryTableDictItemsByCode(dictTable,dictText,dictField); List<DictModel> dictItemsList = sysBaseApi.queryTableDictItemsByCode(dictTable,dictText,dictField);
// dictItemsList.forEach(dictItem->{ dictItemsList.forEach(dictItem->{
// DragDictModel dictModel = new DragDictModel(); DragDictModel dictModel = new DragDictModel();
// BeanUtils.copyProperties(dictItem,dictModel); BeanUtils.copyProperties(dictItem,dictModel);
// dictItems.add(dictModel); dictItems.add(dictModel);
// }); });
// manyDragDictItems.put(fieldName,dictItems); manyDragDictItems.put(fieldName,dictItems);
// }); });
// } }
// return manyDragDictItems; return manyDragDictItems;
// } }
//
// /** /**
// * *
// * @param dictCode * @param dictCode
// * @return * @return
// */ */
// @Override @Override
// public List<DragDictModel> getDictItems(String dictCode) { public List<DragDictModel> getDictItems(String dictCode) {
// List<DragDictModel> dictItems = new ArrayList<>(); List<DragDictModel> dictItems = new ArrayList<>();
// if(oConvertUtils.isNotEmpty(dictCode)){ if(oConvertUtils.isNotEmpty(dictCode)){
// List<DictModel> dictItemsList = sysBaseApi.getDictItems(dictCode); List<DictModel> dictItemsList = sysBaseApi.getDictItems(dictCode);
// dictItemsList.forEach(dictItem->{ dictItemsList.forEach(dictItem->{
// DragDictModel dictModel = new DragDictModel(); DragDictModel dictModel = new DragDictModel();
// BeanUtils.copyProperties(dictItem,dictModel); BeanUtils.copyProperties(dictItem,dictModel);
// dictItems.add(dictModel); dictItems.add(dictModel);
// }); });
// } }
// return dictItems; return dictItems;
// } }
//
// /** /**
// * 添加日志 *
// * @param dragLogDTO * @param dragLogDTO
// */ */
// @Override @Override
// public void addLog(DragLogDTO dragLogDTO) { public void addLog(DragLogDTO dragLogDTO) {
// if(oConvertUtils.isNotEmpty(dragLogDTO)){ if(oConvertUtils.isNotEmpty(dragLogDTO)){
// LogDTO dto = new LogDTO(); LogDTO dto = new LogDTO();
// BeanUtils.copyProperties(dragLogDTO,dto); BeanUtils.copyProperties(dragLogDTO,dto);
// baseCommonService.addLog(dto); baseCommonService.addLog(dto);
// } }
// } }
//
// /** /**
// * 保存日志 *
// * @param logMsg * @param logMsg
// * @param logType * @param logType
// * @param operateType * @param operateType
// */ */
// @Override @Override
// public void addLog(String logMsg, int logType, int operateType) { public void addLog(String logMsg, int logType, int operateType) {
// baseCommonService.addLog(logMsg,logType,operateType); baseCommonService.addLog(logMsg,logType,operateType);
// } }
//} }

View File

@ -1,107 +1,107 @@
//package org.jeecg.config.jimureport; package org.jeecg.config.jimureport;
//
//import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
//import org.jeecg.common.system.util.JwtUtil; import org.jeecg.common.system.util.JwtUtil;
//import org.jeecg.common.system.vo.SysUserCacheInfo; import org.jeecg.common.system.vo.SysUserCacheInfo;
//import org.jeecg.common.util.RedisUtil; import org.jeecg.common.util.RedisUtil;
//import org.jeecg.common.util.TokenUtils; import org.jeecg.common.util.TokenUtils;
//import org.jeecg.modules.jmreport.api.JmReportTokenServiceI; import org.jeecg.modules.jmreport.api.JmReportTokenServiceI;
//import org.jeecg.modules.system.service.impl.SysBaseApiImpl; import org.jeecg.modules.system.service.impl.SysBaseApiImpl;
//import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
//import org.springframework.context.annotation.Lazy; import org.springframework.context.annotation.Lazy;
//import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
//import org.springframework.util.CollectionUtils; import org.springframework.util.CollectionUtils;
//
//import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletRequest;
//import java.util.HashMap; import java.util.HashMap;
//import java.util.Map; import java.util.Map;
//import java.util.Set; import java.util.Set;
//
///** /**
// * 自定义积木报表鉴权(如果不进行自定义,则所有请求不做权限控制) * ()
// * * 1.自定义获取登录token * * 1.token
// * * 2.自定义获取登录用户 * * 2.
// * @author: jeecg-boot * @author: jeecg-boot
// */ */
//
//
//@Slf4j @Slf4j
//@Component @Component
//public class JimuReportTokenService implements JmReportTokenServiceI { public class JimuReportTokenService implements JmReportTokenServiceI {
// @Autowired @Autowired
// private SysBaseApiImpl sysBaseApi; private SysBaseApiImpl sysBaseApi;
// @Autowired @Autowired
// @Lazy @Lazy
// private RedisUtil redisUtil; private RedisUtil redisUtil;
//
// @Override @Override
// public String getToken(HttpServletRequest request) { public String getToken(HttpServletRequest request) {
// return TokenUtils.getTokenByRequest(request); return TokenUtils.getTokenByRequest(request);
// } }
//
// @Override @Override
// public String getUsername(String token) { public String getUsername(String token) {
// return JwtUtil.getUsername(token); return JwtUtil.getUsername(token);
// } }
//
// @Override @Override
// public String[] getRoles(String token) { public String[] getRoles(String token) {
// String username = JwtUtil.getUsername(token); String username = JwtUtil.getUsername(token);
// Set roles = sysBaseApi.getUserRoleSet(username); Set roles = sysBaseApi.getUserRoleSet(username);
// if(CollectionUtils.isEmpty(roles)){ if(CollectionUtils.isEmpty(roles)){
// return null; return null;
// } }
// return (String[]) roles.toArray(new String[roles.size()]); return (String[]) roles.toArray(new String[roles.size()]);
// } }
//
// @Override @Override
// public Boolean verifyToken(String token) { public Boolean verifyToken(String token) {
// return TokenUtils.verifyToken(token, sysBaseApi, redisUtil); return TokenUtils.verifyToken(token, sysBaseApi, redisUtil);
// } }
//
// @Override @Override
// public Map<String, Object> getUserInfo(String token) { public Map<String, Object> getUserInfo(String token) {
// Map<String, Object> map = new HashMap(5); Map<String, Object> map = new HashMap(5);
// String username = JwtUtil.getUsername(token); String username = JwtUtil.getUsername(token);
// //此处通过token只能拿到一个信息 用户账号 后面的就是根据账号获取其他信息 查询数据或是走redis 用户根据自身业务可自定义 //此处通过token只能拿到一个信息 用户账号 后面的就是根据账号获取其他信息 查询数据或是走redis 用户根据自身业务可自定义
// SysUserCacheInfo userInfo = null; SysUserCacheInfo userInfo = null;
// try { try {
// userInfo = sysBaseApi.getCacheUser(username); userInfo = sysBaseApi.getCacheUser(username);
// } catch (Exception e) { } catch (Exception e) {
// log.error("获取用户信息异常:"+ e.getMessage()); log.error("获取用户信息异常:"+ e.getMessage());
// return map; return map;
// } }
// //设置账号名 //设置账号名
// map.put(SYS_USER_CODE, userInfo.getSysUserCode()); map.put(SYS_USER_CODE, userInfo.getSysUserCode());
// //设置部门编码 //设置部门编码
// map.put(SYS_ORG_CODE, userInfo.getSysOrgCode()); map.put(SYS_ORG_CODE, userInfo.getSysOrgCode());
// // 将所有信息存放至map 解析sql/api会根据map的键值解析 // 将所有信息存放至map 解析sql/api会根据map的键值解析
// return map; return map;
// } }
//
// /** /**
// * 将jeecgboot平台的权限传递给积木报表 * jeecgboot
// * @param token * @param token
// * @return * @return
// */ */
// @Override @Override
// public String[] getPermissions(String token) { public String[] getPermissions(String token) {
// // 获取用户信息 // 获取用户信息
// String username = JwtUtil.getUsername(token); String username = JwtUtil.getUsername(token);
// SysUserCacheInfo userInfo = null; SysUserCacheInfo userInfo = null;
// try { try {
// userInfo = sysBaseApi.getCacheUser(username); userInfo = sysBaseApi.getCacheUser(username);
// } catch (Exception e) { } catch (Exception e) {
// log.error("获取用户信息异常:"+ e.getMessage()); log.error("获取用户信息异常:"+ e.getMessage());
// } }
// if(userInfo == null){ if(userInfo == null){
// return null; return null;
// } }
// // 查询权限 // 查询权限
// Set<String> userPermissions = sysBaseApi.getUserPermissionSet(userInfo.getSysUserId()); Set<String> userPermissions = sysBaseApi.getUserPermissionSet(userInfo.getSysUserId());
// if(CollectionUtils.isEmpty(userPermissions)){ if(CollectionUtils.isEmpty(userPermissions)){
// return null; return null;
// } }
// return userPermissions.toArray(new String[0]); return userPermissions.toArray(new String[0]);
// } }
//} }