+ * sql注入过滤处理,遇到注入关键字抛异常
+ *
+ * @param table
+ */
+ private static Pattern tableNamePattern = Pattern.compile("^[a-zA-Z][a-zA-Z0-9_\\$]{0,63}$");
+ public static String getSqlInjectTableName(String table) {
+ if(oConvertUtils.isEmpty(table)){
+ return table;
+ }
+
+ table = table.trim();
+ /**
+ * 检验表名是否合法
+ *
+ * 表名只能由字母、数字和下划线组成。
+ * 表名必须以字母开头。
+ * 表名长度通常有限制,例如最多为 64 个字符。
+ */
+ boolean isValidTableName = tableNamePattern.matcher(table).matches();
+ if (!isValidTableName) {
+ String errorMsg = "表名不合法,存在SQL注入风险!--->" + table;
+ log.error(errorMsg);
+ throw new JeecgSqlInjectionException(errorMsg);
+ }
+
+ //进一步验证是否存在SQL注入风险
+ filterContent(table);
+ return table;
+ }
+
+
+ /**
+ * 返回查询字段
+ *
+ * sql注入过滤处理,遇到注入关键字抛异常
+ *
+ * @param field
+ */
+ static final Pattern fieldPattern = Pattern.compile("^[a-zA-Z0-9_]+$");
+ public static String getSqlInjectField(String field) {
+ if(oConvertUtils.isEmpty(field)){
+ return field;
+ }
+
+ field = field.trim();
+
+ if (field.contains(SymbolConstant.COMMA)) {
+ return getSqlInjectField(field.split(SymbolConstant.COMMA));
+ }
+
+ /**
+ * 校验表字段是否有效
+ *
+ * 字段定义只能是是字母 数字 下划线的组合(不允许有空格、转义字符串等)
+ */
+ boolean isValidField = fieldPattern.matcher(field).matches();
+ if (!isValidField) {
+ String errorMsg = "字段不合法,存在SQL注入风险!--->" + field;
+ log.error(errorMsg);
+ throw new JeecgSqlInjectionException(errorMsg);
+ }
+
+ //进一步验证是否存在SQL注入风险
+ filterContent(field);
+ return field;
+ }
+
+ /**
+ * 获取多个字段
+ * 返回: 逗号拼接
+ *
+ * @param fields
+ * @return
+ */
+ public static String getSqlInjectField(String... fields) {
+ for (String s : fields) {
+ getSqlInjectField(s);
+ }
+ return String.join(SymbolConstant.COMMA, fields);
+ }
+
+
+ /**
+ * 获取排序字段
+ * 返回:字符串
+ *
+ * 1.将驼峰命名转化成下划线
+ * 2.限制sql注入
+ * @param sortField 排序字段
+ * @return
+ */
+ public static String getSqlInjectSortField(String sortField) {
+ String field = SqlInjectionUtil.getSqlInjectField(oConvertUtils.camelToUnderline(sortField));
+ return field;
+ }
+
+ /**
+ * 获取多个排序字段
+ * 返回:数组
+ *
+ * 1.将驼峰命名转化成下划线
+ * 2.限制sql注入
+ * @param sortFields 多个排序字段
+ * @return
+ */
+ public static List getSqlInjectSortFields(String... sortFields) {
+ List list = new ArrayList();
+ for (String sortField : sortFields) {
+ list.add(getSqlInjectSortField(sortField));
+ }
+ return list;
+ }
+
+ /**
+ * 获取 orderBy type
+ * 返回:字符串
+ *
+ * 1.检测是否为 asc 或 desc 其中的一个
+ * 2.限制sql注入
+ *
+ * @param orderType
+ * @return
+ */
+ public static String getSqlInjectOrderType(String orderType) {
+ if (orderType == null) {
+ return null;
+ }
+ orderType = orderType.trim();
+ if (CommonConstant.ORDER_TYPE_ASC.equalsIgnoreCase(orderType)) {
+ return CommonConstant.ORDER_TYPE_ASC;
+ } else {
+ return CommonConstant.ORDER_TYPE_DESC;
+ }
+ }
+
}
diff --git a/jeecg-boot-base-core/src/main/java/org/jeecg/common/util/TokenUtils.java b/jeecg-boot-base-core/src/main/java/org/jeecg/common/util/TokenUtils.java
index 4b7a14d..7d1e611 100644
--- a/jeecg-boot-base-core/src/main/java/org/jeecg/common/util/TokenUtils.java
+++ b/jeecg-boot-base-core/src/main/java/org/jeecg/common/util/TokenUtils.java
@@ -34,6 +34,21 @@ public class TokenUtils {
}
return token;
}
+
+ /**
+ * 获取 request 里传递的 token
+ * @return
+ */
+ public static String getTokenByRequest() {
+ String token = null;
+ try {
+ HttpServletRequest request = SpringContextUtils.getHttpServletRequest();
+ token = TokenUtils.getTokenByRequest(request);
+ } catch (Exception e) {
+ //e.printStackTrace();
+ }
+ return token;
+ }
/**
* 获取 request 里传递的 tenantId (租户ID)
diff --git a/jeecg-boot-base-core/src/main/java/org/jeecg/common/util/dynamic/db/FreemarkerParseFactory.java b/jeecg-boot-base-core/src/main/java/org/jeecg/common/util/dynamic/db/FreemarkerParseFactory.java
index f59f405..8f49769 100644
--- a/jeecg-boot-base-core/src/main/java/org/jeecg/common/util/dynamic/db/FreemarkerParseFactory.java
+++ b/jeecg-boot-base-core/src/main/java/org/jeecg/common/util/dynamic/db/FreemarkerParseFactory.java
@@ -169,7 +169,7 @@ public class FreemarkerParseFactory {
//"where and"
String whereAnd = DataBaseConstant.SQL_WHERE+" and";
//", where"
- String commaWhere = SymbolConstant.COMMA+" "+ DataBaseConstant.SQL_WHERE;
+ String commaWhere = SymbolConstant.COMMA+" "+DataBaseConstant.SQL_WHERE;
//", "
String commaSpace = SymbolConstant.COMMA + " ";
if (sql.endsWith(DataBaseConstant.SQL_WHERE) || sql.endsWith(whereSpace)) {
diff --git a/jeecg-boot-base-core/src/main/java/org/jeecg/common/util/filter/FileTypeFilter.java b/jeecg-boot-base-core/src/main/java/org/jeecg/common/util/filter/SsrfFileTypeFilter.java
similarity index 71%
rename from jeecg-boot-base-core/src/main/java/org/jeecg/common/util/filter/FileTypeFilter.java
rename to jeecg-boot-base-core/src/main/java/org/jeecg/common/util/filter/SsrfFileTypeFilter.java
index cc0ce9d..1a78fc5 100644
--- a/jeecg-boot-base-core/src/main/java/org/jeecg/common/util/filter/FileTypeFilter.java
+++ b/jeecg-boot-base-core/src/main/java/org/jeecg/common/util/filter/SsrfFileTypeFilter.java
@@ -4,27 +4,72 @@ import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.web.multipart.MultipartFile;
+import java.io.IOException;
import java.io.InputStream;
+import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
+import java.util.List;
/**
- * @Description: 校验上传文件敏感后缀
+ * @Description: 校验文件敏感后缀
* @author: lsq
- * @date: 2021年08月09日 15:29
+ * @date: 2023年09月12日 15:29
*/
@Slf4j
-public class FileTypeFilter {
-
- /**文件后缀*/
- private static String[] forbidType = {"jsp","php"};
+public class SsrfFileTypeFilter {
+ /**
+ * 允许操作文件类型白名单
+ */
+ private final static List FILE_TYPE_WHITE_LIST = new ArrayList<>();
/**初始化文件头类型,不够的自行补充*/
final static HashMap FILE_TYPE_MAP = new HashMap<>();
-
static {
+ //图片文件
+ FILE_TYPE_WHITE_LIST.add("jpg");
+ FILE_TYPE_WHITE_LIST.add("jpeg");
+ FILE_TYPE_WHITE_LIST.add("png");
+ FILE_TYPE_WHITE_LIST.add("gif");
+ FILE_TYPE_WHITE_LIST.add("bmp");
+ FILE_TYPE_WHITE_LIST.add("svg");
+ FILE_TYPE_WHITE_LIST.add("ico");
+
+ //文本文件
+ FILE_TYPE_WHITE_LIST.add("txt");
+ FILE_TYPE_WHITE_LIST.add("doc");
+ FILE_TYPE_WHITE_LIST.add("docx");
+ FILE_TYPE_WHITE_LIST.add("pdf");
+ FILE_TYPE_WHITE_LIST.add("csv");
+// FILE_TYPE_WHITE_LIST.add("xml");
+
+ //音视频文件
+ FILE_TYPE_WHITE_LIST.add("mp4");
+ FILE_TYPE_WHITE_LIST.add("avi");
+ FILE_TYPE_WHITE_LIST.add("mov");
+ FILE_TYPE_WHITE_LIST.add("wmv");
+ FILE_TYPE_WHITE_LIST.add("mp3");
+ FILE_TYPE_WHITE_LIST.add("wav");
+
+ //表格文件
+ FILE_TYPE_WHITE_LIST.add("xls");
+ FILE_TYPE_WHITE_LIST.add("xlsx");
+
+ //压缩文件
+ FILE_TYPE_WHITE_LIST.add("zip");
+ FILE_TYPE_WHITE_LIST.add("rar");
+ FILE_TYPE_WHITE_LIST.add("7z");
+ FILE_TYPE_WHITE_LIST.add("tar");
+
+ //app文件后缀
+ FILE_TYPE_WHITE_LIST.add("apk");
+ FILE_TYPE_WHITE_LIST.add("wgt");
+
+ //设置禁止文件的头部标记
FILE_TYPE_MAP.put("3c25402070616765206c", "jsp");
FILE_TYPE_MAP.put("3c3f7068700a0a2f2a2a0a202a205048", "php");
+ FILE_TYPE_MAP.put("cafebabe0000002e0041", "class");
+ FILE_TYPE_MAP.put("494e5345525420494e54", "sql");
/* fileTypeMap.put("ffd8ffe000104a464946", "jpg");
fileTypeMap.put("89504e470d0a1a0a0000", "png");
fileTypeMap.put("47494638396126026f01", "gif");
@@ -89,17 +134,38 @@ public class FileTypeFilter {
return fileName.substring(fileName.lastIndexOf(".") + 1, fileName.length());
}
+
/**
- * 文件类型过滤
+ * 下载文件类型过滤
+ *
+ * @param filePath
+ */
+ public static void checkDownloadFileType(String filePath) throws IOException {
+ //文件后缀
+ String suffix = getFileTypeBySuffix(filePath);
+ log.info("suffix:{}", suffix);
+ boolean isAllowExtension = FILE_TYPE_WHITE_LIST.contains(suffix.toLowerCase());
+ //是否允许下载的文件
+ if (!isAllowExtension) {
+ throw new IOException("下载失败,存在非法文件类型:" + suffix);
+ }
+ }
+
+
+ /**
+ * 上传文件类型过滤
*
* @param file
*/
- public static void fileTypeFilter(MultipartFile file) throws Exception {
+ public static void checkUploadFileType(MultipartFile file) throws Exception {
+ //获取文件真是后缀
String suffix = getFileType(file);
- for (String type : forbidType) {
- if (type.contains(suffix)) {
- throw new Exception("上传失败,非法文件类型:" + suffix);
- }
+
+ log.info("suffix:{}", suffix);
+ boolean isAllowExtension = FILE_TYPE_WHITE_LIST.contains(suffix.toLowerCase());
+ //是否允许下载的文件
+ if (!isAllowExtension) {
+ throw new Exception("上传失败,存在非法文件类型:" + suffix);
}
}
diff --git a/jeecg-boot-base-core/src/main/java/org/jeecg/common/util/oConvertUtils.java b/jeecg-boot-base-core/src/main/java/org/jeecg/common/util/oConvertUtils.java
index 14be215..0643592 100644
--- a/jeecg-boot-base-core/src/main/java/org/jeecg/common/util/oConvertUtils.java
+++ b/jeecg-boot-base-core/src/main/java/org/jeecg/common/util/oConvertUtils.java
@@ -168,6 +168,17 @@ public class oConvertUtils {
}
}
+ public static Integer getInteger(Object object, Integer defval) {
+ if (isEmpty(object)) {
+ return (defval);
+ }
+ try {
+ return (Integer.parseInt(object.toString()));
+ } catch (NumberFormatException e) {
+ return (defval);
+ }
+ }
+
public static Integer getInt(Object object) {
if (isEmpty(object)) {
return null;
@@ -702,9 +713,20 @@ public class oConvertUtils {
if (isArray(oldVal)) {
return equalityOfArrays((Object[]) oldVal, (Object[]) newVal);
}else if(oldVal instanceof JSONArray){
- return equalityOfJSONArray((JSONArray) oldVal, (JSONArray) newVal);
+ if(newVal instanceof JSONArray){
+ return equalityOfJSONArray((JSONArray) oldVal, (JSONArray) newVal);
+ }else{
+ if (isEmpty(newVal) && (oldVal == null || ((JSONArray) oldVal).size() == 0)) {
+ return true;
+ }
+ List