You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

242 lines
7.8 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

package com.utils;
import org.apache.commons.lang3.StringUtils;
import com.entity.EIException;
/**
* SQL注入过滤工具类
*
* 核心职责防止SQL注入攻击确保输入数据的安全性
*
* 安全特性:
* 1. 过滤危险字符:单引号、双引号、分号、反斜杠
* 2. 检测SQL关键字防止SQL语句拼接
* 3. 抛出明确异常:发现非法字符时立即中断处理
*
* 使用场景:
* - 用户输入的参数验证
* - 动态SQL拼接前的参数过滤
* - 排序字段和排序方向的安全验证
*
* 注意事项:
* - 主要用于简单的字符串参数过滤
* - 对于复杂查询建议使用参数化查询或ORM框架
*/
public class SQLFilter {
/**
* SQL注入过滤
* 对输入的字符串进行SQL注入检测和过滤
*
* @param str 待验证的字符串
* @return 过滤后的安全字符串如果输入为空返回null
* @throws EIException 当检测到SQL注入攻击时抛出异常
*/
public static String sqlInject(String str) {
// 检查输入是否为空
if (StringUtils.isBlank(str)) {
return null;
}
// 第一步:移除危险字符
// 移除单引号,防止字符串逃逸
str = StringUtils.replace(str, "'", "");
// 移除双引号,防止字符串逃逸
str = StringUtils.replace(str, "\"", "");
// 移除分号,防止多语句执行
str = StringUtils.replace(str, ";", "");
// 移除反斜杠,防止转义字符攻击
str = StringUtils.replace(str, "\\", "");
// 第二步:统一转换为小写,便于关键字检测
str = str.toLowerCase();
// 第三步定义SQL关键字黑名单
String[] keywords = {
"master", // 数据库主表操作
"truncate", // 清空表数据
"insert", // 插入数据
"select", // 查询数据
"delete", // 删除数据
"update", // 更新数据
"declare", // 声明变量
"alter", // 修改表结构
"drop" // 删除表
};
// 第四步检测是否包含非法SQL关键字
for (String keyword : keywords) {
if (str.indexOf(keyword) != -1) {
// 发现非法字符,抛出安全异常
throw new EIException("包含非法字符");
}
}
// 返回过滤后的安全字符串
return str;
}
// 可以添加的增强方法:
/**
* 严格的SQL注入过滤增强版
* 使用更严格的关键字检测和字符过滤
*
* @param str 待验证的字符串
* @param fieldName 字段名(用于错误提示)
* @return 过滤后的安全字符串
* @throws EIException 当检测到SQL注入攻击时抛出异常
*/
public static String strictSqlInject(String str, String fieldName) {
if (StringUtils.isBlank(str)) {
return null;
}
// 移除更多危险字符
str = StringUtils.replace(str, "'", "");
str = StringUtils.replace(str, "\"", "");
str = StringUtils.replace(str, ";", "");
str = StringUtils.replace(str, "\\", "");
str = StringUtils.replace(str, "--", ""); // SQL注释
str = StringUtils.replace(str, "/*", ""); // 多行注释开始
str = StringUtils.replace(str, "*/", ""); // 多行注释结束
str = StringUtils.replace(str, "#", ""); // MySQL注释
// 转换为小写进行检测
String lowerStr = str.toLowerCase();
// 扩展的关键字黑名单
String[] extendedKeywords = {
"master", "truncate", "insert", "select", "delete", "update",
"declare", "alter", "drop", "create", "exec", "execute",
"union", "join", "where", "having", "group by", "order by",
"script", "javascript", "vbscript", "onload", "onerror"
};
// 检测关键字
for (String keyword : extendedKeywords) {
if (lowerStr.contains(keyword)) {
throw new EIException("字段[" + fieldName + "]包含非法字符: " + keyword);
}
}
// 检测常见的SQL注入模式
if (containsSqlInjectionPattern(lowerStr)) {
throw new EIException("字段[" + fieldName + "]检测到SQL注入模式");
}
return str;
}
/**
* 检测SQL注入模式
*
* @param str 待检测字符串
* @return 是否包含SQL注入模式
*/
private static boolean containsSqlInjectionPattern(String str) {
// 检测常见的SQL注入攻击模式
String[] patterns = {
"1=1", "1=2", "or 1=1", "or 1=2",
"and 1=1", "and 1=2", "' or '1'='1",
"union select", "union all select"
};
for (String pattern : patterns) {
if (str.contains(pattern)) {
return true;
}
}
return false;
}
/**
* 仅允许字母数字和下划线的安全过滤
* 适用于表名、字段名等标识符
*
* @param str 待验证字符串
* @return 过滤后的安全字符串
* @throws EIException 当包含非法字符时抛出异常
*/
public static String safeIdentifier(String str) {
if (StringUtils.isBlank(str)) {
return null;
}
// 只允许字母、数字、下划线
if (!str.matches("^[a-zA-Z0-9_]+$")) {
throw new EIException("标识符包含非法字符,只允许字母、数字和下划线");
}
return str;
}
/**
* 数字参数安全验证
*
* @param str 待验证字符串
* @return 验证后的数字字符串
* @throws EIException 当不是纯数字时抛出异常
*/
public static String safeNumber(String str) {
if (StringUtils.isBlank(str)) {
return null;
}
// 验证是否为纯数字
if (!str.matches("^[0-9]+$")) {
throw new EIException("参数必须为纯数字");
}
return str;
}
/**
* 排序方向安全验证
* 只允许ASC和DESC
*
* @param order 排序方向
* @return 安全的排序方向
* @throws EIException 当排序方向不合法时抛出异常
*/
public static String safeOrder(String order) {
if (StringUtils.isBlank(order)) {
return "ASC"; // 默认升序
}
order = order.toUpperCase();
if ("ASC".equals(order) || "DESC".equals(order)) {
return order;
}
throw new EIException("排序方向不合法只允许ASC或DESC");
}
/**
* 批量SQL注入过滤
*
* @param params 参数Map
* @return 过滤后的参数Map
*/
public static Map<String, Object> batchSqlInject(Map<String, Object> params) {
if (params == null || params.isEmpty()) {
return params;
}
Map<String, Object> safeParams = new HashMap<>();
for (Map.Entry<String, Object> entry : params.entrySet()) {
Object value = entry.getValue();
if (value instanceof String) {
// 对字符串参数进行过滤
safeParams.put(entry.getKey(), sqlInject((String) value));
} else {
// 非字符串参数直接保留
safeParams.put(entry.getKey(), value);
}
}
return safeParams;
}
}