diff --git a/bonus-framework/src/main/java/com/bonus/framework/interceptor/ParamSecureHandler.java b/bonus-framework/src/main/java/com/bonus/framework/interceptor/ParamSecureHandler.java index e952aa4..6916db2 100644 --- a/bonus-framework/src/main/java/com/bonus/framework/interceptor/ParamSecureHandler.java +++ b/bonus-framework/src/main/java/com/bonus/framework/interceptor/ParamSecureHandler.java @@ -68,11 +68,9 @@ public class ParamSecureHandler implements AsyncHandlerInterceptor { // 过滤文件上传功能-只对参数进行校验 if (isFileUpload(request)) { String params = request.getParameter("params"); -// boolean flag = XssCheck.xssCleanNew(params); XssCheck.XssCheckResult xssCheckResult = XssCheck.xssCheckWithResult(null, params, null, null); if(!xssCheckResult.isSafe()){ Map map = new HashMap<>(16); -// returnJson(response, "输入值非法", 500,null); List illegalParameters = xssCheckResult.getIllegalParameters(); if(CollectionUtils.isNotEmpty(illegalParameters)){ log.error("非法参数{}",illegalParameters); @@ -87,19 +85,15 @@ public class ParamSecureHandler implements AsyncHandlerInterceptor { } XssRequestWrapper requestWrapper = new XssRequestWrapper(request); -// System.err.println(JSON.toJSONString(request.getParameterMap())); /** * 校验参数是否合法 */ if (!requestWrapper.isChecked()) { - /*log.error("输入值非法: queryString={}, body={}", - StringUtils.defaultString(requestWrapper.getQueryString(), "null"), - StringUtils.defaultString(requestWrapper.getReaderParam(), "null"));*/ Map map = new HashMap<>(16); List illegalParameters = requestWrapper.getIllegalParameters(); if(CollectionUtils.isNotEmpty(illegalParameters)){ - log.error("非法参数{}",illegalParameters); +// log.error("非法参数{}",illegalParameters); XssRequestWrapper.IllegalParameter illegalParameter = illegalParameters.get(0); map.put("paramName",illegalParameter.getParamName().replace("REQUEST_BODY.","")); map.put("originalValue",illegalParameter.getOriginalValue()); @@ -108,7 +102,6 @@ public class ParamSecureHandler implements AsyncHandlerInterceptor { returnJson(response, "输入值非法", 500,map); return false; } -// System.err.println(JSON.toJSONString(request.getParameterMap())); /** * 获取所有跳转路径参数,保留传入下个界面 @@ -123,7 +116,7 @@ public class ParamSecureHandler implements AsyncHandlerInterceptor { /** * 检查数据流参数 */ - String readerParam = requestWrapper.getReaderParam(); + /*String readerParam = requestWrapper.getReaderParam(); // 判断是否是文件上传,是不对流参数进行验证 String uplFile = "/upload", upImage = "/uploadFiles",path="/"; if (!requestUrl.contains(uplFile) && !requestUrl.contains(upImage) && !requestUrl.contains(path)) { @@ -132,7 +125,7 @@ public class ParamSecureHandler implements AsyncHandlerInterceptor { returnJson(response, "不安全参数", 500,null); return false; } - } + }*/ return true; } diff --git a/bonus-framework/src/main/java/com/bonus/framework/interceptor/XssRequestWrapper.java b/bonus-framework/src/main/java/com/bonus/framework/interceptor/XssRequestWrapper.java index d206694..b1ac961 100644 --- a/bonus-framework/src/main/java/com/bonus/framework/interceptor/XssRequestWrapper.java +++ b/bonus-framework/src/main/java/com/bonus/framework/interceptor/XssRequestWrapper.java @@ -35,7 +35,22 @@ public class XssRequestWrapper extends HttpServletRequestWrapper { // 预编译所有正则表达式模式以提高性能 private static final List XSS_PATTERNS = new ArrayList<>(); + // 需要忽略特殊字符校验的URL路径 + private static final Set IGNORE_SPECIAL_CHARS_URLS = new HashSet<>(); + + // 需要忽略的特殊字符模式(在修改密码时需要忽略的) + private static final List IGNORE_SPECIAL_PATTERNS = new ArrayList<>(); + static { + // 初始化忽略校验的URL路径 + IGNORE_SPECIAL_CHARS_URLS.add("/smartArchives/system/user/resetPwd"); + // 可以根据需要添加更多修改密码的URL + + // 初始化需要忽略的特殊字符模式 + IGNORE_SPECIAL_PATTERNS.add(Pattern.compile("@.*", Pattern.CASE_INSENSITIVE)); // @符号 + IGNORE_SPECIAL_PATTERNS.add(Pattern.compile("!.*", Pattern.CASE_INSENSITIVE)); // 感叹号 + IGNORE_SPECIAL_PATTERNS.add(Pattern.compile("%", Pattern.CASE_INSENSITIVE)); // % + // 初始化所有XSS模式 XSS_PATTERNS.add(Pattern.compile("", Pattern.CASE_INSENSITIVE)); XSS_PATTERNS.add(Pattern.compile("src[\r\n]*=[\r\n]*'(.*?)'", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL)); @@ -73,10 +88,7 @@ public class XssRequestWrapper extends HttpServletRequestWrapper { XSS_PATTERNS.add(Pattern.compile("%5b", Pattern.CASE_INSENSITIVE)); // [ 的URL编码 XSS_PATTERNS.add(Pattern.compile("%5d", Pattern.CASE_INSENSITIVE)); // ] 的URL编码 - // 其他特殊字符 - XSS_PATTERNS.add(Pattern.compile("@.*", Pattern.CASE_INSENSITIVE)); // @符号 - XSS_PATTERNS.add(Pattern.compile("!.*", Pattern.CASE_INSENSITIVE)); // 感叹号 - XSS_PATTERNS.add(Pattern.compile("%", Pattern.CASE_INSENSITIVE)); // % + // 注意:@、!、% 这三个模式被移到 IGNORE_SPECIAL_PATTERNS 中,不在 XSS_PATTERNS 中 // 十六进制编码 XSS_PATTERNS.add(Pattern.compile("\\\\x3c", Pattern.CASE_INSENSITIVE)); // < 的十六进制 @@ -271,11 +283,19 @@ public class XssRequestWrapper extends HttpServletRequestWrapper { } String cleanedValue = value; - // 使用预编译的模式 + + // 首先使用主要XSS模式进行清理 for (Pattern pattern : XSS_PATTERNS) { cleanedValue = pattern.matcher(cleanedValue).replaceAll(""); } + // 如果不是修改密码请求,才对特殊字符进行清理 + if (!isPasswordUpdateRequest()) { + for (Pattern pattern : IGNORE_SPECIAL_PATTERNS) { + cleanedValue = pattern.matcher(cleanedValue).replaceAll(""); + } + } + // 如果值被修改,记录非法参数 if (!cleanedValue.equals(value)) { recordIllegalParameter(paramName, value, cleanedValue, "XSS_ATTACK"); @@ -295,15 +315,42 @@ public class XssRequestWrapper extends HttpServletRequestWrapper { return isJsonSafe(paramName, value); } - // 使用预编译的模式进行检查 + boolean isSafe = true; + + // 使用预编译的模式进行检查(主要XSS模式) for (Pattern pattern : XSS_PATTERNS) { if (match(pattern, value)) { // 发现XSS攻击,记录非法参数 recordIllegalParameter(paramName, value, null, "XSS_PATTERN_" + pattern.pattern()); - return false; + isSafe = false; } } - return true; // 安全 + + // 如果不是修改密码请求,才对特殊字符进行检查 + if (!isPasswordUpdateRequest()) { + for (Pattern pattern : IGNORE_SPECIAL_PATTERNS) { + if (match(pattern, value)) { + recordIllegalParameter(paramName, value, null, "SPECIAL_CHAR_PATTERN_" + pattern.pattern()); + isSafe = false; + } + } + } + + return isSafe; + } + + /** + * 判断是否为修改密码请求 + */ + private boolean isPasswordUpdateRequest() { + String requestURI = ((HttpServletRequest) getRequest()).getRequestURI(); + for (String url : IGNORE_SPECIAL_CHARS_URLS) { + if (requestURI.contains(url)) { + log.debug("检测到修改密码请求,忽略特殊字符校验: {}", requestURI); + return true; + } + } + return false; } // 检查字符串是否为JSON格式 @@ -420,13 +467,25 @@ public class XssRequestWrapper extends HttpServletRequestWrapper { } boolean isSafe = true; + + // 检查主要XSS模式 for (Pattern pattern : XSS_PATTERNS) { if (match(pattern, value)) { recordIllegalParameter(paramName, value, null, "XSS_PATTERN_" + pattern.pattern()); isSafe = false; - // 继续检查其他模式,记录所有匹配的攻击模式 } } + + // 如果不是修改密码请求,才对特殊字符进行检查 + if (!isPasswordUpdateRequest()) { + for (Pattern pattern : IGNORE_SPECIAL_PATTERNS) { + if (match(pattern, value)) { + recordIllegalParameter(paramName, value, null, "SPECIAL_CHAR_PATTERN_" + pattern.pattern()); + isSafe = false; + } + } + } + return isSafe; } @@ -441,6 +500,11 @@ public class XssRequestWrapper extends HttpServletRequestWrapper { * 记录非法参数信息 */ private void recordIllegalParameter(String paramName, String originalValue, String cleanedValue, String attackType) { + // 如果是修改密码请求,且攻击类型是特殊字符,则不记录 + if (isPasswordUpdateRequest() && attackType.startsWith("SPECIAL_CHAR_PATTERN_")) { + return; // 忽略记录特殊字符攻击 + } + IllegalParameter illegalParam = new IllegalParameter(); illegalParam.setParamName(paramName); illegalParam.setOriginalValue(originalValue); @@ -452,11 +516,13 @@ public class XssRequestWrapper extends HttpServletRequestWrapper { illegalParameters.add(illegalParam); - // 记录警告日志 - /*log.warn("检测到XSS攻击尝试 - 参数: {}, 攻击类型: {}, 原始值: {}, 客户端IP: {}", - paramName, attackType, - originalValue.length() > 100 ? originalValue.substring(0, 100) + "..." : originalValue, - illegalParam.getClientIp());*/ + // 记录警告日志(特殊字符攻击在修改密码时不记录) + if (!(isPasswordUpdateRequest() && attackType.startsWith("SPECIAL_CHAR_PATTERN_"))) { + log.warn("检测到安全威胁 - 参数: {}, 攻击类型: {}, 原始值: {}, 客户端IP: {}", + paramName, attackType, + originalValue.length() > 100 ? originalValue.substring(0, 100) + "..." : originalValue, + illegalParam.getClientIp()); + } } /** @@ -527,6 +593,5 @@ public class XssRequestWrapper extends HttpServletRequestWrapper { private Date detectedTime; // 检测时间 private String requestUrl; // 请求URL private String clientIp; // 客户端IP - } } \ No newline at end of file