sonarqube通过数据流分析识别sql注入:判定变量是否来自用户输入、是否未经参数化直接拼接、是否流向sql执行函数,三者链路闭合即触发java:s2077等规则告警。

SonarQube 能直接识别拼接 SQL 的危险模式,但不会运行代码——它靠语法结构和上下文规则标记风险点,关键在配置对的规则集和语言插件。
SQL 字符串拼接被标记为“SQL Injection”漏洞的判定逻辑
SonarQube 不是靠正则简单匹配 "SELECT * FROM" 这类字面量,而是结合三方面做推断:
- 变量是否来自用户可控输入(如
HttpServletRequest.getParameter()、@RequestParam、req.query等常见入口) - 该变量是否未经转义/参数化,直接参与字符串拼接(如 Java 中的
+、String.format()、StringBuilder.append();JS 中的模板字符串`SELECT * FROM users WHERE id = ${id}`) - 拼接结果是否流向已知的 SQL 执行函数(如
Statement.execute()、JdbcTemplate.query()、knex.raw()、sequelize.query())
只要这三条链路被检测到,就会触发 java:S2077(Java)、javascript:S2077(JS)等规则告警。注意:它不分析运行时值,所以硬编码的 "WHERE name = 'admin'" 不会报,但 "WHERE name = '" + name + "'" 一定会报。
为什么启用了规则却没扫出已知的 SQL 拼接问题
常见原因不是规则失效,而是扫描环境缺失关键信息:
- 项目未正确声明语言类型:Maven 多模块中子模块没配
<packaging>jar</packaging>,或 JS 项目缺少package.json,导致 SonarScanner 跳过该目录 - 使用了非标准 SQL 执行方式(如自研 ORM、反射调用 JDBC),SonarQube 默认规则无法识别执行点,需手动配置
sonar.java.libraries或启用sonar.javascript.sqale增强规则 - SQL 拼接发生在测试代码(
src/test/)中,默认被排除,需显式添加-Dsonar.exclusions=**/test/**反向取消排除 - Spring Boot 项目用了
@Select("...")注解写 SQL,但 MyBatis 插件未启用——必须安装并启用MyBatis Plugin for SonarQube,否则注解内 SQL 完全不可见
修复建议优先级:从堵漏洞到改习惯
别只改一行代码,要切断整个风险路径:
- Java 场景下,把
"SELECT * FROM user WHERE id = " + id改成jdbcTemplate.query("SELECT * FROM user WHERE id = ?", ...)或 MyBatis 的<select><where><if test="id != null">id = #{id}</if></where></select> - Node.js/Knex 场景下,禁用
knex.raw("SELECT * FROM users WHERE id = " + req.query.id),改用knex('users').where('id', req.query.id)或参数化knex.raw("SELECT * FROM users WHERE id = ?", [req.query.id]) - 前端 JS 若真需动态 SQL(极不推荐),至少用
sqlstring.escape()包裹每个变量,且确保后端有二次校验——SonarQube 会警告sqlstring.escape不是银弹,仅作临时缓解 - 所有修复后,加一条单元测试:传入
id="1 OR 1=1 --",验证返回结果是否为空或抛异常,而非返回全部用户
容易被忽略的“伪安全”写法
这些写法看似用了预编译,实则仍可能绕过防护:
-
PreparedStatement ps = conn.prepareStatement("SELECT * FROM " + tableName + " WHERE id = ?");—— 表名不能参数化,tableName必须白名单校验 -
String sql = "SELECT * FROM users WHERE " + condition;后续再用ps.setString(1, value)——condition是拼进去的,参数化只覆盖了 value 部分 - MyBatis 中混用
${}和#{}:ORDER BY ${sortBy}即使sortBy来自枚举,也要确认枚举值未被反射篡改;#{}才真正参数化
这类问题 SonarQube 的 java:S2077 会标红,但开发常误以为“用了 PreparedStatement 就安全”,实际漏洞仍在字符串拼接环节。










