💖简介
业务场景经常会存在动态order by
入参情况,在处理动态 order by
参数时,需要防止SQL注入
攻击。SQL注入
是一种常见的安全漏洞,攻击者可以通过这种手段操纵查询来执行恶意代码。
📖措施
- 使用预编译语句(Prepared Statements):
预编译语句是防止SQL注入的有效方法之一。它们允许将SQL语句和参数分开发送到数据库服务器,这样数据库引擎就可以预先编译SQL语句,并确保参数作为数据而不是可执行代码被处理。 - 参数化查询:
使用参数化查询同样可以帮助防止SQL注入。在这种方式下,即使用户输入包含恶意的SQL代码,这些输入也会被视为纯文本而不是可执行的命令。 - 白名单验证:
限制 ORDER BY 子句中的列名只能是从一个已知的安全列表中选择。这意味着你需要有一个明确的列名列表,只有当用户的输入匹配这个列表中的某个值时,才允许使用它来排序。 - 正则表达式检查:
可以使用正则表达式来验证传入的列名是否符合预期格式。例如,只允许字母、数字以及特定的字符如下划线等。 - 框架或库提供的安全特性:
如果你正在使用某种编程语言的框架或ORM(对象关系映射),请利用其内置的安全特性来处理SQL查询。许多现代框架都提供了防止SQL注入的功能。 - 避免直接拼接SQL字符串:
不要直接将用户输入的数据拼接到SQL查询字符串中。这通常是导致SQL注入的主要原因之一。
🌟工具
通过正则表达式判断order by 入参是否符合预期
import org.apache.commons.lang3.StringUtils;
import java.util.regex.Pattern;
/**
* @program: ZK
* @description: order by 检查工具
* @author: zk
* @create: 2024-09-30 17:42
**/
public class OrderByCheckUtil {
/**
* 适用于 a-zA-Z0-9_.等限定字符 拼接asc/desc 及多个字段
* t.id desc, t.name
*/
private static final Pattern FILTER_PATTERN = Pattern.compile("^([a-zA-Z0-9_/\\.]+)(\\s+)?(asc|desc)?$");
private static final String COMMA= ",";
public static boolean check(String orderBy) {
if(StringUtils.isBlank(orderBy)){
return true;
}
String[] split = orderBy.split(COMMA);
for (String s : split) {
if(!FILTER_PATTERN.matcher(s.trim()).matches()){
return false;
}
}
return true;
}
}
⭐测试
- test
// 正常场景
System.out.println(OrderByCheckUtil.check("id"));
System.out.println(OrderByCheckUtil.check("id asc"));
System.out.println(OrderByCheckUtil.check("id desc"));
System.out.println(OrderByCheckUtil.check("id desc, name"));
System.out.println(OrderByCheckUtil.check("id desc, name asc"));
System.out.println(OrderByCheckUtil.check("t.id"));
System.out.println(OrderByCheckUtil.check("t.id asc"));
System.out.println(OrderByCheckUtil.check("t.id desc"));
System.out.println(OrderByCheckUtil.check("t.id desc, t.name"));
System.out.println(OrderByCheckUtil.check("t.id desc, t.name asc"));
System.out.println(OrderByCheckUtil.check("table_t.id"));
System.out.println(OrderByCheckUtil.check("table_t.id asc"));
System.out.println(OrderByCheckUtil.check("table_t.id desc"));
System.out.println(OrderByCheckUtil.check("table_t.id desc, table_t.name"));
System.out.println(OrderByCheckUtil.check("table_t.id desc, table_t.name asc"));
// 非法字符
System.out.println(OrderByCheckUtil.check("id; DROP TABLE users; --"));
System.out.println(OrderByCheckUtil.check("id, (SELECT * FROM information_schema.tables) --"));
System.out.println(OrderByCheckUtil.check("(id), (SELECT * FROM users WHERE 'x'='x')"));
System.out.println(OrderByCheckUtil.check("id; EXEC master..xp_cmdshell 'dir c:\\' --"));
System.out.println(OrderByCheckUtil.check("id ASC, CASE WHEN (1=1) THEN 1 ELSE 0 END"));
System.out.println(OrderByCheckUtil.check("id, CONCAT(username, ':', password)"));
- result
true
true
true
true
true
true
true
true
true
true
true
true
true
true
true
false
false
false
false
false
false
结束