位置:首页 > SQL > 如何编写单元测试验证 SQL 注入防护

如何编写单元测试验证 SQL 注入防护

时间:2026-08-23  |  作者:清风无痕  |  阅读:0

要想测试真正有效,就必须让恶意输入穿透校验层、拼接逻辑以及DAO调用,从而触发业务层异常(比如IllegalArgumentException),而不能仅仅验证不报错。而且,还需要覆盖${}拼接、二次注入等高危路径,并对审计日志进行检查。

如何编写单元测试验证SQL注入防护

测试必须传真实恶意字符串,不能 mock DAO 返回值

不少测试之所以失败,并非防护措施没做好,而是测试过程中绕过了关键路径。比如说,在service层对userRepository.findByUsername的返回值进行了mock,然而却并未将"admin'--"真正传入方法体,这无异于测试了一个虚假的流程。

真正有效的测试要让输入穿透校验层、拼接逻辑(如果有)、DAO 调用,直到触发异常或安全执行。否则你测的不是“防护是否生效”,而是“mock 是否配对成功”。

  • userService.findByUsername("admin'--") 调用,而不是 when(userRepository.findByUsername(any())).thenReturn(...)
  • 如果底层是 MyBatis,确保测试走的是 select * from users where name = #{name} 路径,而非 ${name} 拼接分支
  • 对 JSON 接口,测试 body 原始内容含 %27(URL 编码单引号),确认解码后仍被拦截

断言目标不是“不报错”,而是“抛指定业务异常”

看到测试通过就以为安全?错。很多框架默认允许单引号,仅靠数据库驱动语法校验不可靠——MySQL 可能直接报 MySQLSyntaxErrorException,PostgreSQL 却可能静默截断或返回空结果。

真正要验证的是:防护逻辑是否在 DB 执行前就拦截了。所以 assert 必须明确指向业务层异常,比如 IllegalArgumentException 或自定义的 InvalidInputException

  • 正确:assertThatThrownBy(() -> service.login("root' OR '1'='1")) + .isInstanceOf(IllegalArgumentException.class)
  • 错误:assertThatCode(() -> service.login("...")).doesNotThrowAnyException() —— 这只说明没崩,不代表没进 DB
  • 若实际抛出 PSQLExceptionSQLServerException,说明防护失效,请求已抵达数据库

覆盖 ${} 和字符串拼接等危险写法

MyBatis 的 ${}、JPA 的 createNativeQuery、Ja va 的 String.format+ 拼接,都是高危点。单元测试必须显式构造这些分支并验证其行为。

尤其注意旧代码里藏得深的拼接逻辑:比如先从 DB 查出模板 SQL,再用用户输入填充字段名或表名——这种场景 #{} 也救不了你。

  • 对使用 ${tableName} 的 mapper,传入 "users; DROP TABLE admins--",验证是否抛出预期异常
  • String sql = "SELECT * FROM " + userInput; 这类代码,测试需触发运行时异常(如 SQLException)或记录非法日志
  • Hibernate 场景下,检查是否用了 @Param 绑定,而非 createNativeQuery("SELECT * FROM users WHERE name = '" + input + "'")

避免用 @Sql 或 H2 执行真实 SQL

用内存数据库跑一条带 ' OR 1=1 的查询,看它返回全表数据——这不是在测你的防护,是在测 H2 的 SQL 解析器是否够严。

真实防护逻辑发生在 Ja va 层:正则过滤、白名单校验、参数绑定调用。数据库只是最终执行者。把测试焦点放在 DB 层,等于把责任推给方言实现,而不同数据库对非法输入的响应差异极大。

  • 禁用 @Sql(scripts = "malicious-data.sql") 类测试,它无法验证你写的校验逻辑是否触发
  • 不要依赖 H2/hsqldb 的“报错即拦截”行为——它们不模拟 MySQL 的注释解析、PostgreSQL 的类型强转
  • 重点检查日志:当恶意输入进来时,是否记录了 "Blocked SQL injection attempt: ..." 这类审计日志

最常被忽略的一点:二次注入。测试不能只盯着即时接口,还要覆盖“先存后查”路径——比如注册时存入 "admin'; --",登录时再查这个字段触发拼接。这种延迟执行的漏洞,单元测试里最容易漏掉。

免责声明:文中图文均来自网络,如有侵权请联系删除,心愿游戏发布此文仅为传递信息,不代表心愿游戏认同其观点或证实其描述。

相关文章

更多

精选合集

更多

大家都在玩

热门话题

大家都在看

更多