Selaa lähdekoodia

[task-4339]深圳三院金通医学实验室标准化数智化管理平台渗透测试报告

gaozl 11 kuukautta sitten
vanhempi
sitoutus
a35716d54a

+ 1 - 1
ibps-base-root/modules/base-cloud/src/main/java/com/lc/ibps/cloud/provider/GenericProvider.java

@@ -256,7 +256,7 @@ public class GenericProvider {
 	 * @since 2.8.12
 	 */
 	protected <T> APIResult<T> setExceptionResult(APIResult<T> result, int state, String message, Exception e) {
-		return ResultUtil.setExceptionResult(result, state, message, e);
+		return ResultUtil.setExceptionResult(result, state, message, null);
 	}
 	
 	/**

+ 32 - 0
ibps-base-root/modules/base-web/src/main/java/com/lc/ibps/base/web/util/RequestUtil.java

@@ -251,6 +251,38 @@ public class RequestUtil {
 		return str;
 	}
 
+	// 预编译正则表达式,提升性能
+	private static final Pattern SQL_INJECT_PATTERN;
+	static {
+		// 扩展SQL关键字和危险符号(按长度降序排列,避免部分匹配)
+		String[] sqlKeywords = {
+				"\\bexec\\b", "\\binsert\\b", "\\bdelete\\b", "\\bupdate\\b",
+				"\\bdrop\\b", "\\bcreate\\b", "\\balter\\b", "\\btruncate\\b",
+				"\\bchar\\b", "\\bchr\\b", "\\bxp_cmdshell\\b"
+		};
+//		String[] sqlKeywords = {
+//				"\\bexec\\b", "\\binsert\\b", "\\bselect\\b", "\\bdelete\\b", "\\bupdate\\b",
+//				"\\bdrop\\b", "\\bcreate\\b", "\\balter\\b", "\\btruncate\\b", "\\bunion\\b",
+//				"\\bchar\\b", "\\bchr\\b", "\\bcount\\b", "\\bfrom\\b", "\\bwhere\\b",
+//				";", "--", "/\\*", "\\*/", "\"", "'", "\\|", "\\%", "\\=", "\\bxp_cmdshell\\b"
+//		};
+		String regex = String.join("|", sqlKeywords);
+		SQL_INJECT_PATTERN = Pattern.compile(regex, Pattern.CASE_INSENSITIVE | Pattern.UNICODE_CASE);
+	}
+
+	public static String filterInjectQuery(String input) {
+		if (input == null || input.isEmpty()) {
+			return input;
+		}
+		// 移除SQL注入特征
+		Matcher matcher = SQL_INJECT_PATTERN.matcher(input);
+		String filtered = matcher.replaceAll("");
+		// 转义特殊字符(根据数据库类型调整)
+//		filtered = filtered.replace("'", "''");
+		filtered = filtered.replace("\\", "\\\\");
+		return filtered;
+	}
+
 	/**
 	 * 从Request中取得指定的小写值
 	 * 

+ 24 - 14
ibps-basic-root/modules/basic-response/src/main/java/com/lc/ibps/cloud/util/AESUtil.java

@@ -19,20 +19,20 @@ public class AESUtil {
     private static final String USERKEY = "49PBou+TREIOzSHj";
     private static final String USERIV = "5lDsNRe&UduJ97uS";
 
-    public static String decrypt(String encryptedText)
-            throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidAlgorithmParameterException, InvalidKeyException,
-            IllegalBlockSizeException, BadPaddingException {
-        byte[] encryptedData = Base64.getDecoder().decode(encryptedText);
-
-        SecretKeySpec secretKeySpec = new SecretKeySpec(KEY.getBytes(StandardCharsets.UTF_8), "AES");
-        IvParameterSpec ivParameterSpec = new IvParameterSpec(IV.getBytes(StandardCharsets.UTF_8));
-
-        Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); // 使用CBC模式和PKCS5Padding填充
-        cipher.init(Cipher.DECRYPT_MODE, secretKeySpec, ivParameterSpec);
-
-        byte[] decryptedBytes = cipher.doFinal(encryptedData);
-        return new String(decryptedBytes, StandardCharsets.UTF_8).trim(); // 去除末尾空格
-    }
+//    public static String decrypt(String encryptedText)
+//            throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidAlgorithmParameterException, InvalidKeyException,
+//            IllegalBlockSizeException, BadPaddingException {
+//        byte[] encryptedData = Base64.getDecoder().decode(encryptedText);
+//
+//        SecretKeySpec secretKeySpec = new SecretKeySpec(KEY.getBytes(StandardCharsets.UTF_8), "AES");
+//        IvParameterSpec ivParameterSpec = new IvParameterSpec(IV.getBytes(StandardCharsets.UTF_8));
+//
+//        Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); // 使用CBC模式和PKCS5Padding填充
+//        cipher.init(Cipher.DECRYPT_MODE, secretKeySpec, ivParameterSpec);
+//
+//        byte[] decryptedBytes = cipher.doFinal(encryptedData);
+//        return new String(decryptedBytes, StandardCharsets.UTF_8).trim(); // 去除末尾空格
+//    }
 
     public static String decryptUser(String encryptedText)
             throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidAlgorithmParameterException, InvalidKeyException,
@@ -49,4 +49,14 @@ public class AESUtil {
         return new String(decryptedBytes, StandardCharsets.UTF_8).trim(); // 去除末尾空格
     }
 
+    public static String decryptByIv(String encryptedText,String iv)throws NoSuchPaddingException, NoSuchAlgorithmException,
+            InvalidAlgorithmParameterException, InvalidKeyException,IllegalBlockSizeException, BadPaddingException {
+        byte[] ivBytes = Base64.getDecoder().decode(iv);
+        byte[] encryptedBytes = Base64.getDecoder().decode(encryptedText);
+
+        Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
+        cipher.init(Cipher.DECRYPT_MODE,new SecretKeySpec(KEY.getBytes(StandardCharsets.UTF_8), "AES"),new IvParameterSpec(ivBytes));
+        byte[] decrypted = cipher.doFinal(encryptedBytes);
+        return new String(decrypted, StandardCharsets.UTF_8);
+    }
 }

+ 1 - 1
ibps-basis-root/modules/basis-zuul/src/main/java/com/lc/ibps/cloud/gateway/filter/SignFilter.java

@@ -132,7 +132,7 @@ public class SignFilter extends ZuulFilter {
                     }
                     List<String> arrayList = new ArrayList<>();
                     Map<String, List<String>> qp = new HashMap<>();
-                    String aes_decodedStr = AESUtil.decrypt(name);
+                    String aes_decodedStr = AESUtil.decryptUser(name);
                     JSONObject map = JSONObject.fromObject(aes_decodedStr);/*转换成map*/
                     Map<String, List<String>> finalRequestQueryParams = requestQueryParams;
                     map.forEach((k, v)->{

+ 2 - 4
ibps-provider-root/modules/provider-business/src/main/java/com/lc/ibps/aop/IDataTemplateMsgAop.java

@@ -54,8 +54,6 @@ import java.util.regex.Pattern;
 @Component
 public class IDataTemplateMsgAop {
 
-    private static final String TABLE_NAME = "t_business_log";
-
     private static final String REMOVE_METHOD = "removeFormData";
 
     private static final String SAVE_METHOD = "saveFormDataVo";
@@ -197,7 +195,7 @@ public class IDataTemplateMsgAop {
             map.put("table_name" , tableName);
             map.put("table_comment" , tableComment);
             map.put("data_" , oldData);
-            String sql = SqlUtil.buildInsertSql(map,TABLE_NAME);
+            String sql = SqlUtil.buildInsertSql(map,LogAopUtil.TABLE_NAME);
             try {
                 commonDao.execute(sql);
             }catch (Exception e){
@@ -212,7 +210,7 @@ public class IDataTemplateMsgAop {
             map.put("table_name" , tableName);
             map.put("table_comment" , tableComment);
             map.put("data_" , oldData);
-            String sql = SqlUtil.buildInsertSql(map,TABLE_NAME);
+            String sql = SqlUtil.buildInsertSql(map,LogAopUtil.TABLE_NAME);
             try {
                 commonDao.execute(sql);
             }catch (Exception e){

+ 58 - 83
ibps-provider-root/modules/provider-business/src/main/java/com/lc/ibps/sysdata/controller/UpdateDataTableController.java

@@ -10,9 +10,10 @@ import com.aliyuncs.dysmsapi.model.v20170525.SendSmsRequest;
 import com.aliyuncs.dysmsapi.model.v20170525.SendSmsResponse;
 import com.aliyuncs.profile.DefaultProfile;
 import com.lc.ibps.api.base.constants.StateEnum;
+import com.lc.ibps.api.form.sql.util.BeanUtils;
+import com.lc.ibps.base.core.util.Collections;
 import com.lc.ibps.base.framework.id.UniqueIdUtil;
 import com.lc.ibps.cloud.entity.APIResult;
-import com.lc.ibps.cloud.util.AESUtil;
 import com.lc.ibps.components.querybuilder.utils.StringUtils;
 import com.lc.ibps.config.JcjdConfig;
 import com.lc.ibps.sysdata.entity.Smsconfig;
@@ -83,44 +84,36 @@ public class UpdateDataTableController {
     @PostMapping("/batchDelete")
     APIResult<Void> batchDelete(@RequestBody String data){
         APIResult<Void> apiResult = new APIResult<>();
-        /*鉴权,当前接口只允许pc端发送请求 */
-//        if(data.isEmpty() || !updateDataTableService.sigVerify(data)){
-//            apiResult.setState(StateEnum.ERROR.getCode());
-//            apiResult.setMessage("非法的签名,接口请求失败!");
-//            return apiResult;
-//        }
         String tableName = "";
         String paramWhere = "";
-        Map map = JSONObject.parseObject(data);
-        String ciphertext = (String)map.get("ciphertext");
         try{
-            String decrypt = AESUtil.decrypt(ciphertext);
+            String decrypt = updateDataTableService.checkParameters(data);
             JSONObject sqlMap = JSONObject.parseObject(decrypt);
-
-        tableName = sqlMap.getString("tableName");
-        paramWhere =  sqlMap.getString("paramWhere");
+            tableName = sqlMap.getString("tableName");
+            paramWhere =  sqlMap.getString("paramWhere");
         } catch (Exception e) {
+            log.warn("操作失败", e);
             apiResult.setState(StateEnum.ERROR.getCode());
             apiResult.setMessage("参数类型错误");
             return apiResult;
         }
-//        if (StringUtils.isEmpty(tableName) &&  StringUtils.isEmpty(paramWhere)) {
-//            apiResult.setState(StateEnum.ERROR.getCode());
-//            apiResult.setMessage("注意:所有参数均不能为空");
-//            return apiResult;
-//        }
-        // 解决 不传where 条件的时候 报错  不传where的时候 删除所有数据
-        if (StringUtils.isEmpty(tableName)) {
+        if (BeanUtils.isEmpty(tableName)) {
             apiResult.setState(StateEnum.ERROR.getCode());
             apiResult.setMessage("注意:tableName不能为空");
             return apiResult;
         }
-        if (StringUtils.isEmpty(paramWhere)){
+        if (BeanUtils.isEmpty(paramWhere)){
             apiResult.setState(StateEnum.ERROR.getCode());
             apiResult.setMessage("注意:ID不能为空");
             return apiResult;
         }else {
-            updateDataTableService.batchDelete(tableName,paramWhere);
+            try{
+                updateDataTableService.batchDelete(tableName,paramWhere);
+            }catch (Exception e) {
+                apiResult.setState(StateEnum.ERROR.getCode());
+                apiResult.setMessage("操作失败");
+                return apiResult;
+            }
         }
         return apiResult;
     }
@@ -166,32 +159,22 @@ public class UpdateDataTableController {
     @PostMapping("/updateDatasContextTable")
     APIResult<Void> updatesDatasContextTable(@RequestBody String data) {
         APIResult<Void> apiResult = new APIResult<>();
-
-        /*鉴权,当前接口只允许pc端发送请求 */
-//        if(data.isEmpty() || !updateDataTableService.sigVerify(data)){
-//            apiResult.setState(StateEnum.ERROR.getCode());
-//            apiResult.setMessage("调用接口时,签名不合法!");
-//            return apiResult;
-//        }
-
-        Map mapData = JSONObject.parseObject(data); /*转换成map*/
-        String ciphertext =(String) mapData.get("ciphertext");
         String tableName = null;
         Map paramCond = null;
-        List<Map<String, String>> paramWhere = null; /*条件 : 值*/
+        List<Map<String, String>> paramWhere = null;
         try {
-            String decrypt = AESUtil.decrypt(ciphertext);
+            String decrypt = updateDataTableService.checkParameters(data);
             Map jsonMap = JSONObject.parseObject(decrypt);
             tableName = (String) jsonMap.get("tableName");
             paramCond = (Map) jsonMap.get("paramCond");
             paramWhere = (List<Map<String, String>>) jsonMap.get("paramWhere");
         } catch (Exception e) {
-            e.printStackTrace();
+            log.warn("操作失败", e);
             apiResult.setState(StateEnum.ERROR.getCode());
             apiResult.setMessage("参数类型错误");
             return apiResult;
         }
-        if (StringUtils.isEmpty(tableName) && /*非空判断 表名*/ StringUtils.isEmpty(paramWhere) && /*条件*/ StringUtils.isEmpty(paramCond)) { /*参数*/
+        if (BeanUtils.isEmpty(tableName) || Collections.isEmpty(paramWhere) || BeanUtils.isEmpty(paramCond)) {
             apiResult.setState(StateEnum.ERROR.getCode());
             apiResult.setMessage("注意:所有参数均不能为空");
             return apiResult;
@@ -208,31 +191,21 @@ public class UpdateDataTableController {
     @PostMapping("/updatesBatchContextTable")
     APIResult<Void> updatesBatchContextTable(@RequestBody String data) {
         APIResult<Void> apiResult = new APIResult<>();
-
-        /*鉴权,当前接口只允许pc端发送请求 */
-//        if(data.isEmpty() || !updateDataTableService.sigVerify(data)){
-//            apiResult.setState(StateEnum.ERROR.getCode());
-//            apiResult.setMessage("调用接口时,签名不合法!");
-//            return apiResult;
-//        }
-
-        Map mapData = JSONObject.parseObject(data); /*转换成map*/
-        String ciphertext =(String) mapData.get("ciphertext");
         String tableName = null;
-        List<Map<String,String>> updList = new ArrayList<>();
+        List<Map<String,String>> updList;
         try {
-            String decrypt = AESUtil.decrypt(ciphertext);
+            String decrypt = updateDataTableService.checkParameters(data);
             Map jsonMap = JSONObject.parseObject(decrypt);
             tableName = (String) jsonMap.get("tableName");
             updList = (List<Map<String, String>>) jsonMap.get("updList");
         } catch (Exception e) {
-            e.printStackTrace();
+            log.warn("操作失败", e);
             apiResult.setState(StateEnum.ERROR.getCode());
             apiResult.setMessage("参数类型错误");
             apiResult.setMessage(e.getMessage());
             return apiResult;
         }
-        if (StringUtils.isEmpty(tableName) && /*非空判断 表名*/ StringUtils.isEmpty(updList) ) { /*参数*/
+        if (BeanUtils.isEmpty(tableName) || Collections.isEmpty(updList) ) {
             apiResult.setState(StateEnum.ERROR.getCode());
             apiResult.setMessage("注意:所有参数均不能为空");
             return apiResult;
@@ -391,31 +364,24 @@ public class UpdateDataTableController {
     }
 
     @ApiOperation("添加接口")
-    @ApiImplicitParams({@ApiImplicitParam(name = "tableName", value = "添加的表名", required = true), @ApiImplicitParam(name = "paramWhere", value = "添加的字段值[{}]", required = true),})
+    @ApiImplicitParams({
+            @ApiImplicitParam(name = "tableName", value = "添加的表名", required = true),
+            @ApiImplicitParam(name = "paramWhere", value = "添加的字段值[{}]", required = true)
+    })
     @PostMapping("/addDataContextTable")
     APIResult<Void> addDataContextTable(@RequestBody String data) {
         APIResult<Void> apiResult = new APIResult<>();
-
-        /*鉴权,当前接口只允许pc端发送请求 */
-//        if(data.isEmpty() || !updateDataTableService.sigVerify(data)){
-//            apiResult.setState(StateEnum.ERROR.getCode());
-//            apiResult.setMessage("非法的签名,接口请求失败!");
-//            return apiResult;
-//        }
-        Map jsonMap = JSONObject.parseObject(data);/*转换成map*/
-        String sql =(String) jsonMap.get("ciphertext");
         String tableName = null;
         String defKey = null;
-        String formKey = null; /*表名*/
-        String type = null; /*类型*/
-        List<LinkedHashMap> paramWhere = null; /*条件 : 值*/
+        String formKey = null;
+        String type = null;
+        List<LinkedHashMap> paramWhere = null;
         try {
-            String decrypt = AESUtil.decrypt(sql);
-            JSONObject map = JSONObject.parseObject(decrypt);/*转换成map*/
-            tableName =(String) map.get("tableName");/*获取表名*/
-            type = StringUtils.isEmpty(map.getString("type")) ? null:map.getString("type");/*获取类型*/
-            String paramWhere1 = map.getString("paramWhere");/*获取参数数组*/
-
+            String decrypt = updateDataTableService.checkParameters(data);
+            JSONObject map = JSONObject.parseObject(decrypt);
+            tableName = map.getString("tableName");
+            type = StringUtils.isEmpty(map.getString("type")) ? null : map.getString("type");
+            String paramWhere1 = map.getString("paramWhere");
             paramWhere = JSONObject.parseArray(paramWhere1, LinkedHashMap.class);
             defKey = map.getString("defKey");
             formKey = map.getString("formKey");
@@ -424,24 +390,33 @@ public class UpdateDataTableController {
             apiResult.setMessage("参数类型错误");
             return apiResult;
         }
-        if (StringUtils.isEmpty(tableName) && /*非空判断 表名*/ StringUtils.isEmpty(paramWhere)) { /*条件*/
+        if (BeanUtils.isEmpty(tableName) || Collections.isEmpty(paramWhere)) {
             apiResult.setState(StateEnum.ERROR.getCode());
-            apiResult.setMessage("注意:所有参数均不能为空");
+            apiResult.setMessage("所有参数均不能为空");
             return apiResult;
         }
-        List<LinkedHashMap> retrunData = null;
-        if (null != defKey && null != formKey && type==null) {
-            retrunData = updateDataTableService.addDataContextTable(tableName, paramWhere, defKey, formKey);/*查询*/
-        }else if(null != defKey && null != formKey && type != null){
-            retrunData = updateDataTableService.addDataContextTable(tableName, paramWhere, defKey, formKey,type);/*查询*/
-        }
-        else retrunData = updateDataTableService.addDataContextTable(tableName, paramWhere);/*查询*/
-        if (null != retrunData) {
-            apiResult.setState(StateEnum.SUCCESS.getCode());
-            apiResult.addVariable("cont", retrunData);
-        } else {
+        try {
+            List<LinkedHashMap> retrunData;
+            if (defKey != null && formKey != null) {
+                if (type != null) {
+                    retrunData = updateDataTableService.addDataContextTable(tableName, paramWhere, defKey, formKey, type);
+                } else {
+                    retrunData = updateDataTableService.addDataContextTable(tableName, paramWhere, defKey, formKey);
+                }
+            } else {
+                retrunData = updateDataTableService.addDataContextTable(tableName, paramWhere);
+            }
+            if (retrunData != null) {
+                apiResult.setState(StateEnum.SUCCESS.getCode());
+                apiResult.addVariable("cont", retrunData);
+            } else {
+                apiResult.setState(StateEnum.ERROR.getCode());
+                apiResult.setMessage("数据操作失败");
+            }
+        } catch (Exception e) {
+            log.error("添加数据异常", e);
             apiResult.setState(StateEnum.ERROR.getCode());
-            apiResult.setMessage("数据开启错误!");
+            apiResult.setMessage("操作失败,请稍后重试");
         }
         return apiResult;
     }

+ 2 - 3
ibps-provider-root/modules/provider-business/src/main/java/com/lc/ibps/sysdata/services/UpdateDataTableService.java

@@ -1,10 +1,7 @@
 package com.lc.ibps.sysdata.services;
 
 import com.alibaba.fastjson.JSONObject;
-import com.lc.ibps.cloud.entity.APIPageList;
-import com.lc.ibps.cloud.entity.APIRequest;
 import com.lc.ibps.cloud.entity.APIResult;
-import com.lc.ibps.sysdata.entity.Material;
 import org.springframework.web.bind.annotation.RequestBody;
 
 import java.util.LinkedHashMap;
@@ -84,4 +81,6 @@ public interface UpdateDataTableService {
 
     APIResult<Void> encipher(String data) throws Exception;
 
+    String checkParameters(String data);
+
 }

+ 98 - 12
ibps-provider-root/modules/provider-business/src/main/java/com/lc/ibps/sysdata/services/impl/UpdateDataTableImpl.java

@@ -12,14 +12,15 @@ import com.lc.ibps.base.core.util.I18nUtil;
 import com.lc.ibps.base.framework.id.UniqueIdUtil;
 import com.lc.ibps.base.framework.table.ICommonDao;
 import com.lc.ibps.base.web.context.ContextUtil;
+import com.lc.ibps.base.web.util.RequestUtil;
 import com.lc.ibps.bpmn.api.service.BpmProcInstService;
 import com.lc.ibps.bpmn.provider.BpmInstProvider;
 import com.lc.ibps.cloud.entity.APIPageList;
 import com.lc.ibps.cloud.entity.APIPageResult;
 import com.lc.ibps.cloud.entity.APIResult;
 import com.lc.ibps.cloud.provider.GenericProvider;
+import com.lc.ibps.cloud.redis.utils.RedisUtil;
 import com.lc.ibps.cloud.util.AESUtil;
-import com.lc.ibps.config.JcjdConfig;
 import com.lc.ibps.config.JsonUtilConfig;
 import com.lc.ibps.config.SerialConfig;
 import com.lc.ibps.sysdata.dao.UpdateDataTableDao;
@@ -34,9 +35,14 @@ import org.springframework.transaction.annotation.Transactional;
 import org.springframework.util.DigestUtils;
 import org.springframework.web.bind.annotation.RequestBody;
 
+import java.time.Duration;
+import java.time.Instant;
 import javax.annotation.Resource;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
 import java.text.SimpleDateFormat;
 import java.util.*;
+import java.util.concurrent.TimeUnit;
 
 import static com.lc.ibps.api.base.constants.StateEnum.ERROR;
 import static com.lc.ibps.api.base.constants.StateEnum.SUCCESS;
@@ -511,26 +517,106 @@ public class UpdateDataTableImpl extends GenericProvider implements UpdateDataTa
     @Override
     public APIResult<Void> encipher(String data) throws Exception {
         APIResult<Void> apiResult = new APIResult<>();
-        Map mapData = JSONObject.parseObject(data);
-        String ciphertext =(String) mapData.get("ciphertext");
         try{
-            String decryptedText = AESUtil.decrypt(ciphertext);
-            //转map
-            Map mapSql = JSONObject.parseObject(decryptedText); /*转换成map*/
+            String decryptedText = checkParameters(data);
+            Map mapSql = JSONObject.parseObject(decryptedText);
             String sql = (String) mapSql.get("sql");
-            if (null != sql && !"".equals(sql) && "select".equals(sql.substring(0, 6))) {
+            if (null != sql && !sql.isEmpty() && "select".equals(sql.substring(0, 6))) {
+                sql = RequestUtil.filterInjectQuery(sql);
                 apiResult.addVariable("data", updateDataTableDao.inputSqlSelectData(sql));
                 apiResult.setState(StateEnum.SUCCESS.getCode());
                 return apiResult;
             }
             apiResult.setState(StateEnum.ERROR.getCode());
-            apiResult.setMessage("参数错误! 必须为select!!!");
+            apiResult.setMessage("参数错误!");
             return apiResult;
         }catch (Exception e){
-            e.printStackTrace();
-            apiResult.setMessage(e.getMessage());
-            apiResult.setState(JcjdConfig.error);
-            throw new Exception(JcjdConfig.EXCEPTION);
+            log.warn("操作失败", e);
+            apiResult.setMessage("操作失败!");
+            apiResult.setState(StateEnum.ERROR.getCode());
+            throw new Exception(StateEnum.ERROR.getText());
+        }
+    }
+
+
+    public String checkParameters(String data){
+        String decryptedText = "";
+        try {
+            Map mapData = JSONObject.parseObject(data);
+            String ciphertext =(String) mapData.get("ciphertext");
+            String ivBase64 = (String) mapData.get("iv");
+            // 1. 验证IV时效性(5分钟内)
+            if (!validateDynamicIV(ivBase64, 5)) {
+                log.warn("IV已过期");
+                throw new RuntimeException("IV已过期");
+            }else {
+                String redisIv = RedisUtil.redisTemplateString.opsForValue().get(ivBase64);
+                if (BeanUtils.isNotEmpty(redisIv)){
+                    log.warn("请求失败,存在已经用过的IV");
+                    throw new RuntimeException("请求失败");
+                }
+            }
+            decryptedText = AESUtil.decryptByIv(ciphertext,ivBase64);
+            RedisUtil.redisTemplateString.opsForValue().set(ivBase64,ivBase64,5 , TimeUnit.MINUTES);
+        } catch (Exception e) {
+            log.warn("解密失败", e);
+            throw new RuntimeException("请求失败");
         }
+        return decryptedText;
     }
+
+    /**
+     * 从动态IV中提取时间戳并验证时效性
+     * @param ivBase64 前端传来的Base64编码的IV
+     * @param timeWindowMinutes 允许的时间窗口(分钟)
+     * @return 是否在有效时间内
+     */
+    public static boolean validateDynamicIV(String ivBase64, long timeWindowMinutes) {
+        try {
+            // 1. Base64解码
+            byte[] ivBytes = Base64.getDecoder().decode(ivBase64);
+            if (ivBytes.length != 16) {
+                return false; // IV必须是16字节
+            }
+            // 2. 转换为ByteBuffer(大端序)
+            ByteBuffer buffer = ByteBuffer.wrap(ivBytes).order(ByteOrder.BIG_ENDIAN);
+            // 3. 解析IV结构(前8字节随机数,后8字节时间戳)
+            // 跳过前8字节随机数(位置4-7是时间戳高4字节)
+            buffer.position(4);
+            int timestampHigh = buffer.getInt();
+            // 跳过接下来4字节随机数(位置12-15是时间戳低4字节)
+            buffer.position(12);
+            int timestampLow = buffer.getInt();
+            // 4. 合并时间戳(64位长整型)
+            long timestamp = ((long) timestampHigh << 32) | (timestampLow & 0xFFFFFFFFL);
+            // 5. 验证时间戳是否在允许的时间窗口内
+            long currentTime = Instant.now().toEpochMilli();
+            return Math.abs(currentTime - timestamp) <= Duration.ofMinutes(timeWindowMinutes).toMillis();
+        } catch (Exception e) {
+            log.warn("ivBase64解析异常",e);
+            return false;
+        }
+    }
+
+    /**
+     * 从IV中提取时间戳(不验证时效性)
+     * @param ivBase64 Base64编码的IV
+     * @return 时间戳(毫秒),解析失败返回-1
+     */
+    public static long extractTimestampFromIV(String ivBase64) {
+        try {
+            byte[] ivBytes = Base64.getDecoder().decode(ivBase64);
+            ByteBuffer buffer = ByteBuffer.wrap(ivBytes).order(ByteOrder.BIG_ENDIAN);
+            buffer.position(4);
+            int timestampHigh = buffer.getInt();
+            buffer.position(12);
+            int timestampLow = buffer.getInt();
+            return ((long) timestampHigh << 32) | (timestampLow & 0xFFFFFFFFL);
+        } catch (Exception e) {
+            return -1;
+        }
+    }
+
+
+
 }

+ 58 - 2
ibps-provider-root/modules/provider-business/src/main/java/com/lc/ibps/untils/LogAopUtil.java

@@ -2,6 +2,7 @@ package com.lc.ibps.untils;
 
 import cn.hutool.core.date.StopWatch;
 import cn.hutool.json.JSONUtil;
+import com.alibaba.fastjson.JSONObject;
 import com.fasterxml.jackson.databind.JsonNode;
 import com.fasterxml.jackson.databind.ObjectMapper;
 import com.lc.ibps.base.web.context.ContextUtil;
@@ -14,6 +15,11 @@ import javax.servlet.ServletResponse;
 import javax.servlet.http.HttpServletRequest;
 import java.io.PrintWriter;
 import java.io.StringWriter;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.time.Duration;
+import java.time.Instant;
+import java.util.Base64;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
@@ -25,6 +31,7 @@ import java.util.stream.Stream;
  */
 public class LogAopUtil {
 
+    public static final String TABLE_NAME = "t_business_log";
 
     public static String filterParam(Object[] pointArgs){
         ObjectMapper objectMapper = new ObjectMapper();
@@ -32,8 +39,8 @@ public class LogAopUtil {
             try {
                 JsonNode jsonNode = objectMapper.readTree(pointArg.toString());
                 if (jsonNode.has("ciphertext") && !jsonNode.get("ciphertext").isNull()) {
-                    String ciphertext = jsonNode.get("ciphertext").asText();
-                    pointArgs = new String[]{AESUtil.decrypt(ciphertext)};
+                    //String ciphertext = jsonNode.get("ciphertext").asText();
+                    pointArgs = new String[]{checkParameters(pointArg.toString())};
                 }
             } catch (Exception e) {}
         }
@@ -75,4 +82,53 @@ public class LogAopUtil {
         return map;
     }
 
+    public static String checkParameters(String data){
+        String decryptedText = "";
+        try {
+            Map mapData = JSONObject.parseObject(data);
+            String ciphertext =(String) mapData.get("ciphertext");
+            String ivBase64 = (String) mapData.get("iv");
+            // 1. 验证IV时效性(5分钟内)
+            if (!validateDynamicIV(ivBase64, 5)) {
+                throw new RuntimeException("IV已过期");
+            }
+            decryptedText = AESUtil.decryptByIv(ciphertext,ivBase64);
+        } catch (Exception e) {
+            throw new RuntimeException("请求失败");
+        }
+        return decryptedText;
+    }
+
+    /**
+     * 从动态IV中提取时间戳并验证时效性
+     * @param ivBase64 前端传来的Base64编码的IV
+     * @param timeWindowMinutes 允许的时间窗口(分钟)
+     * @return 是否在有效时间内
+     */
+    public static boolean validateDynamicIV(String ivBase64, long timeWindowMinutes) {
+        try {
+            // 1. Base64解码
+            byte[] ivBytes = Base64.getDecoder().decode(ivBase64);
+            if (ivBytes.length != 16) {
+                return false; // IV必须是16字节
+            }
+            // 2. 转换为ByteBuffer(大端序)
+            ByteBuffer buffer = ByteBuffer.wrap(ivBytes).order(ByteOrder.BIG_ENDIAN);
+            // 3. 解析IV结构(前8字节随机数,后8字节时间戳)
+            // 跳过前8字节随机数(位置4-7是时间戳高4字节)
+            buffer.position(4);
+            int timestampHigh = buffer.getInt();
+            // 跳过接下来4字节随机数(位置12-15是时间戳低4字节)
+            buffer.position(12);
+            int timestampLow = buffer.getInt();
+            // 4. 合并时间戳(64位长整型)
+            long timestamp = ((long) timestampHigh << 32) | (timestampLow & 0xFFFFFFFFL);
+            // 5. 验证时间戳是否在允许的时间窗口内
+            long currentTime = Instant.now().toEpochMilli();
+            return Math.abs(currentTime - timestamp) <= Duration.ofMinutes(timeWindowMinutes).toMillis();
+        } catch (Exception e) {
+            return false;
+        }
+    }
+
 }