mirror of https://github.com/jeecgboot/jeecg-boot
修复v3.8.0 存在绕过sql黑名单限制sql注入漏洞 #8335
修复minidao `getQueryTableInfo`无法解析带括号的表名、增加数据库名解析能力pull/8358/head
parent
4042579167
commit
ddf0f61ae5
|
@ -5,6 +5,7 @@ import lombok.extern.slf4j.Slf4j;
|
||||||
import org.jeecg.common.constant.CommonConstant;
|
import org.jeecg.common.constant.CommonConstant;
|
||||||
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 java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.regex.Matcher;
|
import java.util.regex.Matcher;
|
||||||
|
@ -17,6 +18,12 @@ import java.util.regex.Pattern;
|
||||||
*/
|
*/
|
||||||
@Slf4j
|
@Slf4j
|
||||||
public class SqlInjectionUtil {
|
public class SqlInjectionUtil {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* sql注入黑名单数据库名
|
||||||
|
*/
|
||||||
|
public final static String XSS_STR_TABLE = "peformance_schema|information_schema";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 默认—sql注入关键词
|
* 默认—sql注入关键词
|
||||||
*/
|
*/
|
||||||
|
@ -168,6 +175,27 @@ public class SqlInjectionUtil {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 判断是否存在SQL注入关键词字符串
|
||||||
|
*
|
||||||
|
* @param keyword
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("AlibabaUndefineMagicConstant")
|
||||||
|
private static boolean isExistSqlInjectTableKeyword(String sql, String keyword) {
|
||||||
|
// 需要匹配的,sql注入关键词
|
||||||
|
String[] matchingTexts = new String[]{"`" + keyword, "(" + keyword, "(`" + keyword};
|
||||||
|
for (String matchingText : matchingTexts) {
|
||||||
|
String[] checkTexts = new String[]{" " + matchingText, "from" + matchingText};
|
||||||
|
for (String checkText : checkTexts) {
|
||||||
|
if (sql.contains(checkText)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* sql注入过滤处理,遇到注入关键字抛异常
|
* sql注入过滤处理,遇到注入关键字抛异常
|
||||||
*
|
*
|
||||||
|
@ -208,6 +236,14 @@ public class SqlInjectionUtil {
|
||||||
throw new JeecgSqlInjectionException(SqlInjectionUtil.SQL_INJECTION_TIP + value);
|
throw new JeecgSqlInjectionException(SqlInjectionUtil.SQL_INJECTION_TIP + value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
String[] xssTableArr = XSS_STR_TABLE.split("\\|");
|
||||||
|
for (String xssTableStr : xssTableArr) {
|
||||||
|
if (isExistSqlInjectTableKeyword(value, xssTableStr)) {
|
||||||
|
log.error(SqlInjectionUtil.SQL_INJECTION_KEYWORD_TIP, xssTableStr);
|
||||||
|
log.error(SqlInjectionUtil.SQL_INJECTION_TIP_VARIABLE, value);
|
||||||
|
throw new JeecgSqlInjectionException(SqlInjectionUtil.SQL_INJECTION_TIP + value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// 三、SQL注入检测存在绕过风险 (正则校验)
|
// 三、SQL注入检测存在绕过风险 (正则校验)
|
||||||
for (String regularOriginal : XSS_REGULAR_STR_ARRAY) {
|
for (String regularOriginal : XSS_REGULAR_STR_ARRAY) {
|
||||||
|
@ -244,6 +280,14 @@ public class SqlInjectionUtil {
|
||||||
throw new JeecgSqlInjectionException(SqlInjectionUtil.SQL_INJECTION_TIP + value);
|
throw new JeecgSqlInjectionException(SqlInjectionUtil.SQL_INJECTION_TIP + value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
String[] xssTableArr = XSS_STR_TABLE.split("\\|");
|
||||||
|
for (String xssTableStr : xssTableArr) {
|
||||||
|
if (isExistSqlInjectTableKeyword(value, xssTableStr)) {
|
||||||
|
log.error(SqlInjectionUtil.SQL_INJECTION_KEYWORD_TIP, xssTableStr);
|
||||||
|
log.error(SqlInjectionUtil.SQL_INJECTION_TIP_VARIABLE, value);
|
||||||
|
throw new JeecgSqlInjectionException(SqlInjectionUtil.SQL_INJECTION_TIP + value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// 三、SQL注入检测存在绕过风险 (正则校验)
|
// 三、SQL注入检测存在绕过风险 (正则校验)
|
||||||
for (String regularOriginal : XSS_REGULAR_STR_ARRAY) {
|
for (String regularOriginal : XSS_REGULAR_STR_ARRAY) {
|
||||||
|
|
|
@ -3,6 +3,8 @@ package org.jeecg.common.util.security;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.apache.commons.lang.StringUtils;
|
import org.apache.commons.lang.StringUtils;
|
||||||
import org.jeecg.common.exception.JeecgSqlInjectionException;
|
import org.jeecg.common.exception.JeecgSqlInjectionException;
|
||||||
|
import org.jeecg.common.util.SqlInjectionUtil;
|
||||||
|
import org.jeecg.common.util.oConvertUtils;
|
||||||
|
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.regex.Matcher;
|
import java.util.regex.Matcher;
|
||||||
|
@ -66,6 +68,8 @@ public abstract class AbstractQueryBlackListHandler {
|
||||||
if(flag == false){
|
if(flag == false){
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
Set<String> xssTableSet = new HashSet<>(Arrays.asList(SqlInjectionUtil.XSS_STR_TABLE.split("\\|")));
|
||||||
|
|
||||||
for (QueryTable table : list) {
|
for (QueryTable table : list) {
|
||||||
String name = table.getName();
|
String name = table.getName();
|
||||||
String fieldRule = ruleMap.get(name);
|
String fieldRule = ruleMap.get(name);
|
||||||
|
@ -81,6 +85,16 @@ public abstract class AbstractQueryBlackListHandler {
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
// 判断是否调用了黑名单数据库
|
||||||
|
String dbName = table.getDbName();
|
||||||
|
if (oConvertUtils.isNotEmpty(dbName)) {
|
||||||
|
dbName = dbName.toLowerCase().trim();
|
||||||
|
if (xssTableSet.contains(dbName)) {
|
||||||
|
flag = false;
|
||||||
|
log.warn("sql黑名单校验,数据库【" + dbName + "】禁止查询");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 返回黑名单校验结果(不合法直接抛出异常)
|
// 返回黑名单校验结果(不合法直接抛出异常)
|
||||||
|
@ -135,6 +149,8 @@ public abstract class AbstractQueryBlackListHandler {
|
||||||
* 查询的表的信息
|
* 查询的表的信息
|
||||||
*/
|
*/
|
||||||
protected class QueryTable {
|
protected class QueryTable {
|
||||||
|
//数据库名
|
||||||
|
private String dbName;
|
||||||
//表名
|
//表名
|
||||||
private String name;
|
private String name;
|
||||||
//表的别名
|
//表的别名
|
||||||
|
@ -158,6 +174,14 @@ public abstract class AbstractQueryBlackListHandler {
|
||||||
this.fields.add(field);
|
this.fields.add(field);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getDbName() {
|
||||||
|
return dbName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDbName(String dbName) {
|
||||||
|
this.dbName = dbName;
|
||||||
|
}
|
||||||
|
|
||||||
public String getName() {
|
public String getName() {
|
||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
|
|
|
@ -57,7 +57,7 @@
|
||||||
|
|
||||||
<!-- 积木报表-->
|
<!-- 积木报表-->
|
||||||
<jimureport-spring-boot-starter.version>1.9.5.1</jimureport-spring-boot-starter.version>
|
<jimureport-spring-boot-starter.version>1.9.5.1</jimureport-spring-boot-starter.version>
|
||||||
<minidao.version>1.10.7</minidao.version>
|
<minidao.version>1.10.10</minidao.version>
|
||||||
<!-- 持久层 -->
|
<!-- 持久层 -->
|
||||||
<mybatis-plus.version>3.5.3.2</mybatis-plus.version>
|
<mybatis-plus.version>3.5.3.2</mybatis-plus.version>
|
||||||
<dynamic-datasource-spring-boot-starter.version>4.1.3</dynamic-datasource-spring-boot-starter.version>
|
<dynamic-datasource-spring-boot-starter.version>4.1.3</dynamic-datasource-spring-boot-starter.version>
|
||||||
|
|
Loading…
Reference in New Issue