非法值校验

This commit is contained in:
cwchen 2025-09-29 17:04:05 +08:00
parent 09970538bb
commit 83478dfffa
2 changed files with 270 additions and 29 deletions

View File

@ -68,9 +68,19 @@ public class ParamSecureHandler implements AsyncHandlerInterceptor {
// 过滤文件上传功能-只对参数进行校验
if (isFileUpload(request)) {
String params = request.getParameter("params");
boolean flag = XssCheck.xssCleanNew(params);
if(!flag){
returnJson(response, "输入值非法", 500,null);
// boolean flag = XssCheck.xssCleanNew(params);
XssCheck.XssCheckResult xssCheckResult = XssCheck.xssCheckWithResult(null, params, null, null);
if(!xssCheckResult.isSafe()){
Map<String, Object> map = new HashMap<>(16);
// returnJson(response, "输入值非法", 500,null);
List<XssCheck.IllegalParameter> illegalParameters = xssCheckResult.getIllegalParameters();
if(CollectionUtils.isNotEmpty(illegalParameters)){
log.error("非法参数{}",illegalParameters);
XssCheck.IllegalParameter illegalParameter = illegalParameters.get(0);
map.put("paramName",illegalParameter.getParamName().replace("null.",""));
map.put("originalValue",illegalParameter.getOriginalValue());
}
returnJson(response, "输入值非法", 500,map);
return false;
}
return true;

View File

@ -1,26 +1,36 @@
package com.bonus.framework.interceptor;
import lombok.Data;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.*;
import java.util.regex.Pattern;
/**
* @className:XxlCheck
* @author:cwchen
* @date:2025-09-17-16:33
* @version:1.0
* @description:
* @className: XssCheck
* @author: cwchen
* @date: 2025-09-17-16:33
* @version: 1.0
* @description: XSS安全检查工具类
*/
public class XssCheck {
// 预编译所有正则表达式模式以提高性能
public static final List<Pattern> XSS_PATTERNS = new ArrayList<>();
// 攻击类型常量
public static final String ATTACK_TYPE_SCRIPT_TAG = "SCRIPT_TAG";
public static final String ATTACK_TYPE_JAVASCRIPT_URL = "JAVASCRIPT_URL";
public static final String ATTACK_TYPE_EVENT_HANDLER = "EVENT_HANDLER";
public static final String ATTACK_TYPE_ALERT = "ALERT";
public static final String ATTACK_TYPE_SPECIAL_CHARS = "SPECIAL_CHARS";
public static final String ATTACK_TYPE_URL_ENCODING = "URL_ENCODING";
public static final String ATTACK_TYPE_HEX_ENCODING = "HEX_ENCODING";
public static final String ATTACK_TYPE_DATA_PROTOCOL = "DATA_PROTOCOL";
public static final String ATTACK_TYPE_DOM_ACCESS = "DOM_ACCESS";
static {
// 初始化所有XSS模式
XSS_PATTERNS.add(Pattern.compile("<script>(.*?)</script>", Pattern.CASE_INSENSITIVE));
@ -79,7 +89,187 @@ public class XssCheck {
XSS_PATTERNS.add(Pattern.compile("cookie", Pattern.CASE_INSENSITIVE));
}
static boolean xssCleanNew(String value) {
/**
* 非法参数信息类
*/
@Data
public static class IllegalParameter {
private String paramName; // 参数名
private String originalValue; // 原始值
private String cleanedValue; // 清理后的值可能为null
private String attackType; // 攻击类型
private Date detectedTime; // 检测时间
private String requestUrl; // 请求URL
private String clientIp; // 客户端IP
}
/**
* XSS检查结果类
*/
@Data
public static class XssCheckResult {
private boolean isSafe; // 是否安全
private List<IllegalParameter> illegalParameters; // 非法参数列表
public XssCheckResult(boolean isSafe) {
this.isSafe = isSafe;
this.illegalParameters = new ArrayList<>();
}
public XssCheckResult(boolean isSafe, List<IllegalParameter> illegalParameters) {
this.isSafe = isSafe;
this.illegalParameters = illegalParameters != null ? illegalParameters : new ArrayList<>();
}
/**
* 添加非法参数
*/
public void addIllegalParameter(IllegalParameter illegalParameter) {
if (illegalParameter != null) {
this.illegalParameters.add(illegalParameter);
}
}
/**
* 检查是否有非法参数
*/
public boolean hasIllegalParameters() {
return !illegalParameters.isEmpty();
}
}
/**
* 增强的XSS检查方法返回检查结果包含boolean和非法参数列表
*/
public static XssCheckResult xssCheckWithResult(String paramName, String value, String requestUrl, String clientIp) {
if (value == null) {
return new XssCheckResult(true);
}
List<IllegalParameter> illegalParameters = new ArrayList<>();
// 首先检查是否为JSON格式
if (isJsonString(value)) {
// 对JSON字符串进行特殊处理检查值部分是否包含XSS
collectJsonIllegalParameters(paramName, value, requestUrl, clientIp, illegalParameters);
} else {
// 使用预编译的模式进行检查
IllegalParameter illegalParam = checkPatternsWithDetail(paramName, value, requestUrl, clientIp);
if (illegalParam != null) {
illegalParameters.add(illegalParam);
}
}
boolean isSafe = illegalParameters.isEmpty();
return new XssCheckResult(isSafe, illegalParameters);
}
/**
* 批量检查多个参数
*/
public static XssCheckResult xssCheckBatch(Map<String, String> params, String requestUrl, String clientIp) {
List<IllegalParameter> illegalParameters = new ArrayList<>();
for (Map.Entry<String, String> entry : params.entrySet()) {
String paramName = entry.getKey();
String value = entry.getValue();
if (value != null) {
// 首先检查是否为JSON格式
if (isJsonString(value)) {
collectJsonIllegalParameters(paramName, value, requestUrl, clientIp, illegalParameters);
} else {
IllegalParameter illegalParam = checkPatternsWithDetail(paramName, value, requestUrl, clientIp);
if (illegalParam != null) {
illegalParameters.add(illegalParam);
}
}
}
}
boolean isSafe = illegalParameters.isEmpty();
return new XssCheckResult(isSafe, illegalParameters);
}
/**
* 收集JSON中的非法参数
*/
private static void collectJsonIllegalParameters(String paramName, String jsonStr, String requestUrl, String clientIp, List<IllegalParameter> illegalParameters) {
try {
// 处理JSON对象
if (jsonStr.trim().startsWith("{")) {
JSONObject jsonObject = new JSONObject(jsonStr);
collectJsonObjectIllegalParameters(paramName, jsonObject, requestUrl, clientIp, illegalParameters);
}
// 处理JSON数组
else if (jsonStr.trim().startsWith("[")) {
JSONArray jsonArray = new JSONArray(jsonStr);
collectJsonArrayIllegalParameters(paramName, jsonArray, requestUrl, clientIp, illegalParameters);
}
} catch (JSONException e) {
// 解析失败回退到普通字符串检查
IllegalParameter illegalParam = checkPatternsWithDetail(paramName, jsonStr, requestUrl, clientIp);
if (illegalParam != null) {
illegalParameters.add(illegalParam);
}
}
}
/**
* 收集JSON对象中的非法参数
*/
private static void collectJsonObjectIllegalParameters(String parentKey, JSONObject jsonObject, String requestUrl, String clientIp, List<IllegalParameter> illegalParameters) throws JSONException {
Iterator<String> keys = jsonObject.keys();
while (keys.hasNext()) {
String key = keys.next();
Object value = jsonObject.get(key);
// 检查key的安全性
IllegalParameter keyIllegalParam = checkPatternsWithDetail(parentKey + "." + key, key, requestUrl, clientIp);
if (keyIllegalParam != null) {
illegalParameters.add(keyIllegalParam);
}
// 检查value的安全性
if (value instanceof String) {
IllegalParameter valueIllegalParam = checkPatternsWithDetail(parentKey + "." + key, (String) value, requestUrl, clientIp);
if (valueIllegalParam != null) {
illegalParameters.add(valueIllegalParam);
}
} else if (value instanceof JSONObject) {
collectJsonObjectIllegalParameters(parentKey + "." + key, (JSONObject) value, requestUrl, clientIp, illegalParameters);
} else if (value instanceof JSONArray) {
collectJsonArrayIllegalParameters(parentKey + "." + key, (JSONArray) value, requestUrl, clientIp, illegalParameters);
}
// 其他类型数字布尔值等视为安全
}
}
/**
* 收集JSON数组中的非法参数
*/
private static void collectJsonArrayIllegalParameters(String parentKey, JSONArray jsonArray, String requestUrl, String clientIp, List<IllegalParameter> illegalParameters) throws JSONException {
for (int i = 0; i < jsonArray.length(); i++) {
Object value = jsonArray.get(i);
if (value instanceof String) {
IllegalParameter illegalParam = checkPatternsWithDetail(parentKey + "[" + i + "]", (String) value, requestUrl, clientIp);
if (illegalParam != null) {
illegalParameters.add(illegalParam);
}
} else if (value instanceof JSONObject) {
collectJsonObjectIllegalParameters(parentKey + "[" + i + "]", (JSONObject) value, requestUrl, clientIp, illegalParameters);
} else if (value instanceof JSONArray) {
collectJsonArrayIllegalParameters(parentKey + "[" + i + "]", (JSONArray) value, requestUrl, clientIp, illegalParameters);
}
// 其他类型数字布尔值等视为安全
}
}
/**
* 基本的XSS检查方法保持原有逻辑- 只返回boolean
*/
public static boolean xssCleanNew(String value) {
if (value == null) {
return true;
}
@ -99,7 +289,62 @@ public class XssCheck {
return true; // 安全
}
// 检查字符串是否为JSON格式
/**
* 带详细信息的模式检查
*/
private static IllegalParameter checkPatternsWithDetail(String paramName, String value, String requestUrl, String clientIp) {
for (int i = 0; i < XSS_PATTERNS.size(); i++) {
Pattern pattern = XSS_PATTERNS.get(i);
if (match(pattern, value)) {
IllegalParameter illegalParam = new IllegalParameter();
illegalParam.setParamName(paramName);
illegalParam.setOriginalValue(value);
illegalParam.setAttackType(getAttackTypeByPatternIndex(i));
illegalParam.setRequestUrl(requestUrl);
illegalParam.setClientIp(clientIp);
// 尝试生成清理后的值
illegalParam.setCleanedValue(cleanXssContent(value));
return illegalParam;
}
}
return null;
}
/**
* 根据模式索引获取攻击类型
*/
private static String getAttackTypeByPatternIndex(int index) {
if (index <= 5) return ATTACK_TYPE_SCRIPT_TAG;
if (index <= 8) return ATTACK_TYPE_JAVASCRIPT_URL;
if (index <= 13) return ATTACK_TYPE_EVENT_HANDLER;
if (index == 14) return ATTACK_TYPE_ALERT;
if (index <= 19) return ATTACK_TYPE_SPECIAL_CHARS;
if (index <= 30) return ATTACK_TYPE_URL_ENCODING;
if (index <= 35) return ATTACK_TYPE_HEX_ENCODING;
if (index <= 41) return ATTACK_TYPE_DATA_PROTOCOL;
return ATTACK_TYPE_DOM_ACCESS;
}
/**
* 清理XSS内容基础实现
*/
private static String cleanXssContent(String value) {
if (value == null) return null;
String cleaned = value;
// 移除script标签
cleaned = cleaned.replaceAll("(?i)<script.*?>.*?</script>", "");
// 移除javascript:协议
cleaned = cleaned.replaceAll("(?i)javascript:", "");
// 移除事件处理器
cleaned = cleaned.replaceAll("(?i)on\\w+\\s*=", "");
// 移除危险的HTML标签
cleaned = cleaned.replaceAll("(?i)</?(script|iframe|object|embed).*?>", "");
return cleaned.length() < value.length() ? cleaned : null;
}
// 以下原有方法保持不变...
public static boolean isJsonString(String str) {
if (str == null || str.trim().isEmpty()) {
return false;
@ -109,12 +354,10 @@ public class XssCheck {
if ((trimmed.startsWith("{") && trimmed.endsWith("}")) ||
(trimmed.startsWith("[") && trimmed.endsWith("]"))) {
try {
// 尝试解析为JSON对象
new JSONObject(trimmed);
return true;
} catch (JSONException e1) {
try {
// 尝试解析为JSON数组
new JSONArray(trimmed);
return true;
} catch (JSONException e2) {
@ -125,39 +368,31 @@ public class XssCheck {
return false;
}
// 检查JSON字符串中的值是否安全
public static boolean isJsonSafe(String jsonStr) {
try {
// 处理JSON对象
if (jsonStr.trim().startsWith("{")) {
JSONObject jsonObject = new JSONObject(jsonStr);
return isJsonObjectSafe(jsonObject);
}
// 处理JSON数组
else if (jsonStr.trim().startsWith("[")) {
} else if (jsonStr.trim().startsWith("[")) {
JSONArray jsonArray = new JSONArray(jsonStr);
return isJsonArraySafe(jsonArray);
}
return true;
} catch (JSONException e) {
// 解析失败回退到普通字符串检查
return xssCleanNewFallback(jsonStr);
}
}
// 递归检查JSON对象的安全性
public static boolean isJsonObjectSafe(JSONObject jsonObject) throws JSONException {
Iterator<String> 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;
@ -171,12 +406,10 @@ public class XssCheck {
return false;
}
}
// 其他类型数字布尔值等视为安全
}
return true;
}
// 递归检查JSON数组的安全性
public static boolean isJsonArraySafe(JSONArray jsonArray) throws JSONException {
for (int i = 0; i < jsonArray.length(); i++) {
Object value = jsonArray.get(i);
@ -194,12 +427,10 @@ public class XssCheck {
return false;
}
}
// 其他类型数字布尔值等视为安全
}
return true;
}
// 回退到原始的模式匹配避免递归调用
public static boolean xssCleanNewFallback(String value) {
if (value == null) {
return true;
@ -219,4 +450,4 @@ public class XssCheck {
public static boolean match(Pattern pattern, String str) {
return pattern.matcher(str).find();
}
}
}