mirror of
http://192.168.1.205:9980/cf_devdept2/cf_imes_server.git
synced 2026-08-12 21:02:08 +08:00
1、性别校验器空不校验;2、报表sql相关入参新增支持注入校验;
This commit is contained in:
+2
@@ -1,5 +1,6 @@
|
||||
package com.cf.imes.module.report.controller.admin.dataset.vo;
|
||||
|
||||
import com.cf.imes.module.report.validation.datasource.SqlParamInjectionValid;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
@@ -37,5 +38,6 @@ public class ReportDatasetParameterVO implements Serializable {
|
||||
* 默认值
|
||||
*/
|
||||
@Schema(description = "参数默认值")
|
||||
@SqlParamInjectionValid
|
||||
private String defaultValue;
|
||||
}
|
||||
|
||||
+2
@@ -1,5 +1,6 @@
|
||||
package com.cf.imes.module.report.controller.admin.dataset.vo;
|
||||
|
||||
import com.cf.imes.module.report.validation.datasource.SqlIllegalValid;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
@@ -42,6 +43,7 @@ public class ReportDatasetSaveReqVO implements Serializable {
|
||||
private Long datasourceId;
|
||||
|
||||
@Schema(description = "动态查询SQL")
|
||||
@SqlIllegalValid
|
||||
private String sql;
|
||||
|
||||
@Schema(description = "bean数据源方法名")
|
||||
|
||||
+2
@@ -1,5 +1,6 @@
|
||||
package com.cf.imes.module.report.controller.admin.datasource.vo;
|
||||
|
||||
import com.cf.imes.module.report.validation.datasource.SqlParamInjectionValid;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
@@ -38,5 +39,6 @@ public class ReportDatasourceParameterVO implements Serializable {
|
||||
* 默认值
|
||||
*/
|
||||
@Schema(description = "参数默认值")
|
||||
@SqlParamInjectionValid
|
||||
private String defaultValue;
|
||||
}
|
||||
|
||||
+2
@@ -1,5 +1,6 @@
|
||||
package com.cf.imes.module.report.controller.admin.datasource.vo;
|
||||
|
||||
import com.cf.imes.module.report.validation.datasource.SqlIllegalValid;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
@@ -29,6 +30,7 @@ public class ReportDatasourcePreviewReqVO {
|
||||
|
||||
@Schema(description = "查询语句")
|
||||
@NotBlank(message = "查询语句不能为空")
|
||||
@SqlIllegalValid
|
||||
private String sql;
|
||||
|
||||
@Schema(description = "查询参数列表")
|
||||
|
||||
+32
@@ -0,0 +1,32 @@
|
||||
package com.cf.imes.module.report.validation.datasource;
|
||||
|
||||
import javax.validation.Constraint;
|
||||
import javax.validation.Payload;
|
||||
import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* 非法sql校验注解
|
||||
*
|
||||
* @author Gqr
|
||||
* @since 2024/10/21 18:42
|
||||
*/
|
||||
@Target({
|
||||
ElementType.FIELD,
|
||||
ElementType.PARAMETER,
|
||||
})
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Documented
|
||||
@Constraint(
|
||||
validatedBy = {SqlIllegalValidator.class}
|
||||
)
|
||||
public @interface SqlIllegalValid {
|
||||
String message() default "sql语句非法输入,请检查";
|
||||
|
||||
Class<?>[] groups() default {};
|
||||
|
||||
Class<? extends Payload>[] payload() default {};
|
||||
}
|
||||
+137
@@ -0,0 +1,137 @@
|
||||
package com.cf.imes.module.report.validation.datasource;
|
||||
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import javax.validation.ConstraintValidator;
|
||||
import javax.validation.ConstraintValidatorContext;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
* 非法sql校验器
|
||||
*
|
||||
* @author Gqr
|
||||
* @since 2024/10/21 18:44
|
||||
*/
|
||||
public class SqlIllegalValidator implements ConstraintValidator<SqlIllegalValid, String> {
|
||||
|
||||
private static final Pattern annotationPattern = Pattern.compile("/\\*[\\s\\S]*\\*/");
|
||||
|
||||
private static final String[] someKeywordPattern = new String[]{"chr\\s*\\(", "mid\\s*\\(", " char\\s*\\(", "sleep\\s*\\(", "user\\s*\\(", "show\\s+tables", "user[\\s]*\\([\\s]*\\)", "show\\s+databases", "sleep\\(\\d*\\)", "sleep\\(.*\\)"};
|
||||
|
||||
private static final List<String> specialSymbolList = new ArrayList<>();
|
||||
|
||||
static {
|
||||
specialSymbolList.add(";");
|
||||
specialSymbolList.add("+");
|
||||
specialSymbolList.add("--");
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isValid(String sql, ConstraintValidatorContext context) {
|
||||
if (StringUtils.isEmpty(sql)) {
|
||||
return true;
|
||||
}
|
||||
// 校验注释
|
||||
if (hasAnnotation(sql)) {
|
||||
context.disableDefaultConstraintViolation(); // 禁用默认的 message 的值
|
||||
context.buildConstraintViolationWithTemplate("SQL中不允许包含注释,存在安全风险").addConstraintViolation();
|
||||
return false;
|
||||
}
|
||||
sql = sql.toLowerCase();
|
||||
sql = sql.replaceAll("/\\*.*\\*/", "");
|
||||
// 敏感关键字数组
|
||||
String[] arrayOfSensitiveKey = "exec |peformance_schema|information_schema|extractvalue|updatexml|geohash|gtid_subset|gtid_subtract|insert |alter |delete |grant |update |drop |master |truncate |declare |--|".split("\\|");
|
||||
// 校验敏感关键字
|
||||
for (byte b = 0; b < arrayOfSensitiveKey.length; b++) {
|
||||
if (checkSensitiveKey(sql, arrayOfSensitiveKey[b])) {
|
||||
context.disableDefaultConstraintViolation(); // 禁用默认的 message 的值
|
||||
context.buildConstraintViolationWithTemplate("SQL不合法,存在注入风险").addConstraintViolation();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
// 校验一些函数关键字
|
||||
for (String skw : someKeywordPattern) {
|
||||
String someKeywordStr = ".*" + skw + ".*";
|
||||
if (Pattern.matches(someKeywordStr, sql)) {
|
||||
context.disableDefaultConstraintViolation(); // 禁用默认的 message 的值
|
||||
context.buildConstraintViolationWithTemplate("SQL不合法,存在注入风险").addConstraintViolation();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查敏感关键字
|
||||
*
|
||||
* @param sql
|
||||
* @param sensitiveKey
|
||||
* @return true:带敏感关键字,反之不带
|
||||
*/
|
||||
private boolean checkSensitiveKey(String sql, String sensitiveKey) {
|
||||
if (sql.startsWith(sensitiveKey.trim())) {
|
||||
return true;
|
||||
}
|
||||
if (sql.contains(sensitiveKey)) {
|
||||
String sk1 = " " + sensitiveKey;
|
||||
if (specialSymbolList.contains(sensitiveKey)) {
|
||||
sk1 = sensitiveKey;
|
||||
}
|
||||
if (sql.contains(sk1)) {
|
||||
return true;
|
||||
}
|
||||
String sk2 = "\\s+\\S+" + sensitiveKey;
|
||||
List<String> list = matchInjectKeyword(sk2, sql);
|
||||
for (String keyword : list) {
|
||||
if (keyword.contains("%") || keyword.contains("+") || keyword.contains("#") || keyword.contains("/") || keyword.contains(")")) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 校验注释
|
||||
*
|
||||
* @param sql
|
||||
* @return
|
||||
*/
|
||||
private boolean hasAnnotation(String sql) {
|
||||
// 不允许存在注释
|
||||
if (sql.contains("--")) {
|
||||
return true;
|
||||
} else {
|
||||
Matcher var1 = annotationPattern.matcher(sql);
|
||||
if (var1.find()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 匹配注入关键字
|
||||
*
|
||||
* @param sensitiveKey
|
||||
* @param sql
|
||||
* @return
|
||||
*/
|
||||
public List<String> matchInjectKeyword(String sensitiveKey, CharSequence sql) {
|
||||
Pattern paramPattern = Pattern.compile(sensitiveKey, 32);
|
||||
List<String> paramT = new ArrayList<>();
|
||||
if (ObjectUtil.isAllNotEmpty(paramPattern, sql)) {
|
||||
Matcher matcher = paramPattern.matcher(sql);
|
||||
while (matcher.find()) {
|
||||
paramT.add(matcher.group(0));
|
||||
}
|
||||
}
|
||||
return paramT;
|
||||
}
|
||||
}
|
||||
+32
@@ -0,0 +1,32 @@
|
||||
package com.cf.imes.module.report.validation.datasource;
|
||||
|
||||
import javax.validation.Constraint;
|
||||
import javax.validation.Payload;
|
||||
import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* sql参数注入攻击校验注解
|
||||
*
|
||||
* @author Gqr
|
||||
* @since 2024/10/25 10:30
|
||||
*/
|
||||
@Target({
|
||||
ElementType.FIELD,
|
||||
ElementType.PARAMETER,
|
||||
})
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Documented
|
||||
@Constraint(
|
||||
validatedBy = {SqlParamInjectionValidator.class}
|
||||
)
|
||||
public @interface SqlParamInjectionValid {
|
||||
String message() default "sql查询参数默认值非法输入,请检查";
|
||||
|
||||
Class<?>[] groups() default {};
|
||||
|
||||
Class<? extends Payload>[] payload() default {};
|
||||
}
|
||||
+24
@@ -0,0 +1,24 @@
|
||||
package com.cf.imes.module.report.validation.datasource;
|
||||
|
||||
import com.baomidou.mybatisplus.core.toolkit.sql.SqlInjectionUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import javax.validation.ConstraintValidator;
|
||||
import javax.validation.ConstraintValidatorContext;
|
||||
|
||||
/**
|
||||
* sql参数注入攻击校验器
|
||||
*
|
||||
* @author Gqr
|
||||
* @since 2024/10/25 10:30
|
||||
*/
|
||||
public class SqlParamInjectionValidator implements ConstraintValidator<SqlParamInjectionValid, String> {
|
||||
@Override
|
||||
public boolean isValid(String value, ConstraintValidatorContext context) {
|
||||
if (StringUtils.isEmpty(value)) {
|
||||
return true;
|
||||
}
|
||||
// mybatisplus工具校验注入攻击
|
||||
return !SqlInjectionUtils.check(value);
|
||||
}
|
||||
}
|
||||
+4
@@ -1,5 +1,6 @@
|
||||
package com.cf.imes.module.system.validation.user;
|
||||
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import com.cf.imes.module.system.enums.common.SexEnum;
|
||||
|
||||
import javax.validation.ConstraintValidator;
|
||||
@@ -16,6 +17,9 @@ public class SexValidator implements ConstraintValidator<SexValid, Integer> {
|
||||
|
||||
@Override
|
||||
public boolean isValid(Integer value, ConstraintValidatorContext context) {
|
||||
if (ObjectUtil.isNull(value)) {
|
||||
return true;
|
||||
}
|
||||
for (SexEnum sexEnum : SexEnum.values()) {
|
||||
if (Objects.equals(sexEnum.getSex(), value)) {
|
||||
return true;
|
||||
|
||||
Reference in New Issue
Block a user