From 463a18f209f51b24a82b77669c8b15b14be2b54f Mon Sep 17 00:00:00 2001 From: 16358 <1635849544@qq.com> Date: Tue, 3 Jun 2025 11:20:06 +0800 Subject: [PATCH] =?UTF-8?q?components=E6=B7=BB=E5=8A=A0=E5=89=8D=E7=AB=AF?= =?UTF-8?q?=E7=BB=84=E4=BB=B6searchSelect?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/ruoyi/common/utils/sql/SqlUtil.java | 108 +++++++++++ .../generator/controller/GenController.java | 19 ++ .../com/ruoyi/generator/domain/GenTable.java | 12 ++ .../generator/domain/GenTableColumn.java | 10 + .../generator/mapper/GenTableMapper.java | 4 + .../service/GenTableServiceImpl.java | 6 + .../generator/service/IGenTableService.java | 2 + .../mapper/generator/GenTableMapper.xml | 17 ++ ruoyi-ui/src/api/tool/gen.js | 8 + .../src/components/SearchSelect/index.vue | 177 ++++++++++++++++++ 10 files changed, 363 insertions(+) create mode 100644 ruoyi-ui/src/components/SearchSelect/index.vue diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/utils/sql/SqlUtil.java b/ruoyi-common/src/main/java/com/ruoyi/common/utils/sql/SqlUtil.java index 48720dc..792a308 100644 --- a/ruoyi-common/src/main/java/com/ruoyi/common/utils/sql/SqlUtil.java +++ b/ruoyi-common/src/main/java/com/ruoyi/common/utils/sql/SqlUtil.java @@ -3,6 +3,9 @@ package com.ruoyi.common.utils.sql; import com.ruoyi.common.exception.UtilException; import com.ruoyi.common.utils.StringUtils; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + /** * sql操作工具类 * @@ -25,6 +28,25 @@ public class SqlUtil */ private static final int ORDER_BY_MAX_LENGTH = 500; + private final static String XSS_STR = "and |extractvalue|updatexml|geohash|gtid_subset|gtid_subtract|exec |insert |select |delete |update |drop |count |chr |mid |master |truncate |char |declare |;|or |+|user()"; + + /** + * 正则 user() 匹配更严谨 + */ + private final static String REGULAR_EXPRE_USER = "user[\\s]*\\([\\s]*\\)"; + /**正则 show tables*/ + private final static String SHOW_TABLES = "show\\s+tables"; + + /** + * sleep函数 + */ + private final static Pattern FUN_SLEEP = Pattern.compile("sleep\\(.*\\)", Pattern.CASE_INSENSITIVE); + + /** + * sql注释的正则 + */ + private final static Pattern SQL_ANNOTATION = Pattern.compile("/\\*[\\s\\S]*\\*/"); + /** * 检查字符,防止注入绕过 */ @@ -67,4 +89,90 @@ public class SqlUtil } } } + + /** + * 返回查询表名 + *
+ * sql注入过滤处理,遇到注入关键字抛异常
+ *
+ * @param table
+ */
+ private static Pattern tableNamePattern = Pattern.compile("^[a-zA-Z][a-zA-Z0-9_]{0,63}$");
+ public static String getSqlInjectTableName(String table) {
+ table = table.trim();
+ /**
+ * 检验表名是否合法
+ *
+ * 表名只能由字母、数字和下划线组成。
+ * 表名必须以字母开头。
+ * 表名长度通常有限制,例如最多为 64 个字符。
+ */
+ boolean isValidTableName = tableNamePattern.matcher(table).matches();
+ if (!isValidTableName) {
+ String errorMsg = "表名不合法,存在SQL注入风险!--->" + table;
+ throw new UtilException(errorMsg);
+ }
+
+ //进一步验证是否存在SQL注入风险
+ filterContent(table, null);
+ return table;
+ }
+
+ /**
+ * sql注入过滤处理,遇到注入关键字抛异常
+ *
+ * @param value
+ * @return
+ */
+ public static void filterContent(String value, String customXssString) {
+ if (value == null || "".equals(value)) {
+ return;
+ }
+ // 校验sql注释 不允许有sql注释
+ checkSqlAnnotation(value);
+ // 统一转为小写
+ value = value.toLowerCase();
+ //SQL注入检测存在绕过风险 https://gitee.com/jeecg/jeecg-boot/issues/I4NZGE
+ //value = value.replaceAll("/\\*.*\\*/","");
+
+ String[] xssArr = XSS_STR.split("\\|");
+ for (int i = 0; i < xssArr.length; i++) {
+ if (value.indexOf(xssArr[i]) > -1) {
+ throw new UtilException("请注意,值可能存在SQL注入风险!--->" + value);
+ }
+ }
+ //update-begin-author:taoyan date:2022-7-13 for: 除了XSS_STR这些提前设置好的,还需要额外的校验比如 单引号
+ if (customXssString != null) {
+ String[] xssArr2 = customXssString.split("\\|");
+ for (int i = 0; i < xssArr2.length; i++) {
+ if (value.indexOf(xssArr2[i]) > -1) {
+ throw new UtilException("请注意,值可能存在SQL注入风险!--->" + value);
+ }
+ }
+ }
+ //update-end-author:taoyan date:2022-7-13 for: 除了XSS_STR这些提前设置好的,还需要额外的校验比如 单引号
+ if(Pattern.matches(SHOW_TABLES, value) || Pattern.matches(REGULAR_EXPRE_USER, value)){
+ throw new UtilException("请注意,值可能存在SQL注入风险!--->" + value);
+ }
+ return;
+ }
+
+ /**
+ * 校验是否有sql注释
+ * @return
+ */
+ public static void checkSqlAnnotation(String str){
+ Matcher matcher = SQL_ANNOTATION.matcher(str);
+ if(matcher.find()){
+ String error = "请注意,值可能存在SQL注入风险---> \\*.*\\";
+ throw new UtilException(error);
+ }
+
+ // issues/4737 sys/duplicate/check SQL注入 #4737
+ Matcher sleepMatcher = FUN_SLEEP.matcher(str);
+ if(sleepMatcher.find()){
+ String error = "请注意,值可能存在SQL注入风险---> sleep";
+ throw new UtilException(error);
+ }
+ }
}
diff --git a/ruoyi-generator/src/main/java/com/ruoyi/generator/controller/GenController.java b/ruoyi-generator/src/main/java/com/ruoyi/generator/controller/GenController.java
index 1ef0d35..b044c5c 100644
--- a/ruoyi-generator/src/main/java/com/ruoyi/generator/controller/GenController.java
+++ b/ruoyi-generator/src/main/java/com/ruoyi/generator/controller/GenController.java
@@ -260,4 +260,23 @@ public class GenController extends BaseController
response.setContentType("application/octet-stream; charset=UTF-8");
IOUtils.write(data, response.getOutputStream());
}
+
+ /**
+ * 查询业务列表
+ */
+ @GetMapping("/getSearchSelectData")
+ public AjaxResult getSearchSelectData( String tableName, String value, String label, String where, String groupby, String orderby)
+ {
+ orderby = SqlUtil.escapeOrderBySql(orderby);
+ tableName = SqlUtil.getSqlInjectTableName(tableName);
+ Map