sonarqube能发现sql注入隐患,但仅当完整追踪到“用户输入→未过滤拼接→已知执行函数”污点链路;硬编码字符串无变量参与不触发分析,mybatis注解需专用插件支持,漏报多因污点传播中断或扫描配置缺失。

SonarQube 能发现 SQL 注入隐患,但前提是「污点链路」必须完整:用户输入 → 未过滤拼接 → 流向已知执行函数。缺任一环,就静默跳过——不是工具失效,是上下文没对上。
为什么 req.getParameter("id") + " AND 1=1" 被标红,而 "WHERE id = 123" 完全不报
SonarQube 不看字符串内容是否像 SQL,只追踪变量来源和流向:
-
req.getParameter()、request.getQueryString()、pathVariable等被预定义为“污点源”,一旦参与字符串拼接(+、StringBuilder.append()),就标记为污染传播 - 硬编码字符串没有变量,AST 解析时直接归为常量字面量,不触发任何污点分析
- 只有当污染后的字符串传给
Statement.execute()、JdbcTemplate.query()、knex.raw()等已知“sink”函数,链路才闭合,触发java:S2077或javascript:S2077
MyBatis 注解或 XML 里的 ${id} 为啥总漏报
默认 Java 插件完全不解析 MyBatis 注解语法,@Select("SELECT * FROM user WHERE id = ${id}") 对扫描器来说就是一段普通字符串。
- 必须手动安装并启用 MyBatis Plugin for SonarQube(非官方插件,需下载
.jar放入extensions/plugins/) - 启用后,
${xxx}才会被识别为危险拼接;#{xxx}因走预编译参数化路径,不会告警 - XML 映射文件同理,还需配置
sonar.mybatis.mapper.location=src/main/resources/mapper/**/*.xml - Lombok 的
@Data或@Builder可能破坏 AST 结构,导致req.getParameter()参数无法被标记为污点源——临时禁用 Lombok 或改用显式 getter 可验证
CI/CD 中 Statement.executeUpdate("UPDATE t SET v = " + input) 静默通过的四大原因
这不是规则没起作用,而是扫描环境缺失关键要素。先查这四件事:
- 没开安全规则:
sonar.java.rule.jdbc=security没配 → 所有 JDBC 拼接类漏洞(含executeUpdate)直接跳过 - 没给字节码路径:
sonar.java.binaries=target/classes缺失 → AST 分析无法进行,所有 Java 安全规则失效 - 源码路径错或没声明语言:
sonar.sources=src/main/java错写成src/,或 Maven 子模块缺<packaging>jar</packaging>,导致 fallback 到通用解析器 - 测试代码被排除:
src/test/默认不扫;若风险逻辑在测试中,需加-Dsonar.exclusions=反向取消排除
修复时别只改拼接那行,要拆掉整条风险链
把 "WHERE name = '" + name + "'" 改成 "WHERE name = ?" 是必要但不充分的——如果 name 还是从 getAttribute() 或自研封装里来,且该入口不在默认污点源列表中,下一轮扫描仍可能漏。
- 优先用
PreparedStatement+ 占位符,确保数据与逻辑彻底分离 - 若必须动态拼表名/列名,改用白名单校验(如
if (!ALLOWED_TABLES.contains(table)) throw ...),并在代码旁加// NOSONAR注释说明 - 对自定义参数获取方式(如
HttpServletRequest.getAttribute()),需扩展污点源规则或统一迁移到getParameter()等标准入口
真正卡住扫描结果的,往往不是规则本身,而是字节码路径、污点源定义、插件启用这三者有没有对齐。一个没配的 sonar.java.binaries,比十个误报更难排查。











