From 94bd1e3b467aa8f0a66f890ef283fe41e605d2d6 Mon Sep 17 00:00:00 2001 From: cwchen <1048842385@qq.com> Date: Mon, 8 Sep 2025 15:34:02 +0800 Subject: [PATCH] =?UTF-8?q?XSS=20=E9=85=8D=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- bonus-common/pom.xml | 6 + .../interceptor/ParamSecureHandler.java | 4 +- .../interceptor/XssRequestWrapper.java | 126 ++++++++++++++++++ 3 files changed, 134 insertions(+), 2 deletions(-) diff --git a/bonus-common/pom.xml b/bonus-common/pom.xml index f3fa39b..9e51a60 100644 --- a/bonus-common/pom.xml +++ b/bonus-common/pom.xml @@ -147,6 +147,12 @@ 1.9.7 + + org.json + json + 20231013 + + \ No newline at end of file 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 e59688a..592c384 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 @@ -70,13 +70,13 @@ public class ParamSecureHandler implements AsyncHandlerInterceptor { /** * 校验参数是否合法 */ - /*if (!requestWrapper.isChecked()) { + if (!requestWrapper.isChecked()) { log.error("输入值非法: queryString={}, body={}", StringUtils.defaultString(requestWrapper.getQueryString(), "null"), StringUtils.defaultString(requestWrapper.getReaderParam(), "null")); returnJson(response, "输入值非法", 500); return false; - }*/ + } // System.err.println(JSON.toJSONString(request.getParameterMap())); /** 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 747f52a..9da844f 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 @@ -1,6 +1,9 @@ package com.bonus.framework.interceptor; import lombok.extern.slf4j.Slf4j; +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; import javax.servlet.ReadListener; import javax.servlet.ServletInputStream; @@ -195,6 +198,12 @@ public class XssRequestWrapper extends HttpServletRequestWrapper { return true; } + // 首先检查是否为JSON格式 + if (isJsonString(value)) { + // 对JSON字符串进行特殊处理:检查值部分是否包含XSS + return isJsonSafe(value); + } + List patterns = new ArrayList<>(); patterns.add(Pattern.compile(regex1, Pattern.CASE_INSENSITIVE)); patterns.add(Pattern.compile(regex2, Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL)); @@ -216,6 +225,123 @@ public class XssRequestWrapper extends HttpServletRequestWrapper { return true; // 安全 } + // 检查字符串是否为JSON格式 + private boolean isJsonString(String str) { + try { + // 尝试解析为JSON对象 + new JSONObject(str); + return true; + } catch (JSONException e1) { + try { + // 尝试解析为JSON数组 + new JSONArray(str); + return true; + } catch (JSONException e2) { + return false; + } + } + } + + // 检查JSON字符串中的值是否安全 + private boolean isJsonSafe(String jsonStr) { + try { + // 处理JSON对象 + if (jsonStr.trim().startsWith("{")) { + JSONObject jsonObject = new JSONObject(jsonStr); + return isJsonObjectSafe(jsonObject); + } + // 处理JSON数组 + else if (jsonStr.trim().startsWith("[")) { + JSONArray jsonArray = new JSONArray(jsonStr); + return isJsonArraySafe(jsonArray); + } + return true; + } catch (JSONException e) { + // 解析失败,回退到普通字符串检查 + return xssCleanNewFallback(jsonStr); + } + } + + // 递归检查JSON对象的安全性 + private boolean isJsonObjectSafe(JSONObject jsonObject) throws JSONException { + Iterator keys = jsonObject.keys(); + while (keys.hasNext()) { + String key = keys.next(); + Object value = jsonObject.get(key); + + // 检查key的安全性 + if (!xssCleanNewFallback(key)) { + return false; + } + + // 检查value的安全性 + if (value instanceof String) { + if (!xssCleanNewFallback((String) value)) { + return false; + } + } else if (value instanceof JSONObject) { + if (!isJsonObjectSafe((JSONObject) value)) { + return false; + } + } else if (value instanceof JSONArray) { + if (!isJsonArraySafe((JSONArray) value)) { + return false; + } + } + } + return true; + } + + // 递归检查JSON数组的安全性 + private boolean isJsonArraySafe(JSONArray jsonArray) throws JSONException { + for (int i = 0; i < jsonArray.length(); i++) { + Object value = jsonArray.get(i); + + if (value instanceof String) { + if (!xssCleanNewFallback((String) value)) { + return false; + } + } else if (value instanceof JSONObject) { + if (!isJsonObjectSafe((JSONObject) value)) { + return false; + } + } else if (value instanceof JSONArray) { + if (!isJsonArraySafe((JSONArray) value)) { + return false; + } + } + } + return true; + } + + // 回退到原始的模式匹配(避免递归调用) + private boolean xssCleanNewFallback(String value) { + if (value == null) { + return true; + } + + List patterns = new ArrayList<>(); + // 这里添加你的所有XSS模式... + patterns.add(Pattern.compile(regex1, Pattern.CASE_INSENSITIVE)); + patterns.add(Pattern.compile(regex2, Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL)); + patterns.add(Pattern.compile(regex3, Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL)); + patterns.add(Pattern.compile(regex4, Pattern.CASE_INSENSITIVE)); + patterns.add(Pattern.compile(regex5, Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL)); + patterns.add(Pattern.compile(regex6, Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL)); + patterns.add(Pattern.compile(regex7, Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL)); + patterns.add(Pattern.compile(regex8, Pattern.CASE_INSENSITIVE)); + patterns.add(Pattern.compile(regex9, Pattern.CASE_INSENSITIVE)); + patterns.add(Pattern.compile(regex10, Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL)); + patterns.add(Pattern.compile(SAFE_SCRIPT_PATTERN, Pattern.CASE_INSENSITIVE)); + + for (Pattern pattern : patterns) { + if (match(pattern, value)) { + return false; + } + } + return true; + } + /** * 执行正则表达式匹配 */