非法值校验
This commit is contained in:
parent
09970538bb
commit
83478dfffa
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue