采用@SafeSqlParam注解统一拦截SQL注入,聚焦参数参与SQL拼接的识别与安全校验,通过AOP切面执行白名单/黑名单策略,配套starter、预置策略和IDE模板实现开箱即用。

直接用注解统一拦截并处理 SQL 注入风险,比在每个 DAO 方法里手动写校验更可持续。核心不是“加一层装饰”,而是把参数校验、SQL 构造约束、执行上下文控制三者绑定到一个可声明、可继承、可测试的注解上。
明确注解要管什么,不越界
防注入注解只负责两件事:一是识别哪些方法参数参与了 SQL 拼接(比如 @SqlParam),二是强制这些参数必须经过安全检查后才能进入 JDBC 或 MyBatis 执行流程。它不替代 PreparedStatement,也不接管数据库连接或权限配置——那些属于数据源层和运维规范。
常见误判是把“输入过滤”全塞进注解里,结果导致注解逻辑臃肿、难以单元测试。真正该由注解驱动的是“是否允许该参数出现在 SQL 字符串中”,而不是“这个字符串里有没有 or 1=1”。
定义一个轻量但语义清晰的注解
以 Java 为例,设计一个 @SafeSqlParam:
- 标注在方法参数上,表示该参数将用于构造动态 SQL(如 MyBatis 的 ${} 场景、JDBC 动态表名/字段名)
- 支持指定校验策略:strategy = WhitelistPattern.class(白名单正则)、strategy = SqlKeywordBlocker.class(黑名单关键字拦截)
- 可选开启日志审计:audit = true,记录被拦截的原始值和调用栈
示例:
public User getUser(@SafeSqlParam(strategy = TableNameWhitelist.class) String tableName,
@SafeSqlParam(strategy = ColumnNameWhitelist.class) String columnName,
@RequestParam String id) {
return userMapper.selectByDynamicTable(tableName, columnName, id);
}
配套实现一个 AOP 切面来执行校验
注解本身只是标记,真正起作用的是切面。用 Spring AOP 监听所有带 @SafeSqlParam 的方法调用,在 ProceedingJoinPoint 中提取参数值,按 strategy 类执行校验:
- 白名单策略:预设合法表名集合或正则(如 ^[a-zA-Z][a-zA-Z0-9_]{2,30}$),不匹配则抛出 SqlInjectionRiskException
- 黑名单策略:检测是否含 UNION SELECT、; --、EXEC( 等典型注入特征,命中即阻断
- 校验失败时统一返回 400 错误,并记录审计日志(不暴露具体拦截规则,避免反向探测)
让团队能快速接入、不踩坑
光有注解和切面不够,还要配套三样东西:
- starter 包:封装好自动配置(@EnableAspectJAutoProxy + 注册切面 Bean),引入即生效,无需额外配置
- 开箱即用的策略类:如 PredefinedTableNameWhitelist(内置系统常用表名)、StrictKeywordBlocker(覆盖 OWASP Top 10 常见 payload)
- IDEA Live Template:设置快捷键如 ssq,自动补全带注解的参数声明,降低使用门槛
新成员第一天就能写出带防护的动态 SQL 调用,比反复 Code Review 更可靠。

















