sonarqube默认不报sql注入是因为安全规则(如sonar.java.rule.jdbc=security)被关闭,必须手动启用并确保字节码路径、源码上下文和规则激活三者齐备,否则statement.executeupdate("update t set v = " + input)等代码将静默通过。

默认不报 SQL 注入,不是工具不行,是安全规则被关着——必须手动开,且三要素缺一不可:规则启用、字节码路径正确、源码上下文可识别。
为什么 SonarQube 扫不出 Statement.executeUpdate("UPDATE t SET v = " + input)
因为 sonar.java.rule.jdbc=security 默认没开。SonarQube 把 quality 和 security 规则完全分开,Java 项目里所有 JDBC/HQL/MyBatis 层的拼接风险(比如 Statement.execute()、@Query("..."+name)、${table})全在 security 规则集里,不显式激活就等于没装模块。
常见失效组合:
-
sonar.java.rule.jdbc=security没配 →executeUpdate("UPDATE t SET v = " + input)静默通过 -
sonar.java.rule.hql=security没配 →@Query("SELECT * FROM u WHERE name = '" + name + "'")不告警 -
sonar.mybatis.mapper.location没设或路径错 → XML 里的<select>SELECT * FROM ${table}</select>直接跳过
GitLab CI / Jenkins 中 sonar-scanner 配置常踩的坑
参数传错位置,等于白配。SonarScanner 5.0+ 的 sonar.java.rule.* 类配置,不支持命令行 -D 方式,这是硬限制。
正确做法:
- GitLab CI:用
sonar-project.properties文件,或通过环境变量SONAR_SCANNER_OPTS="-Dsonar.java.rule.jdbc=security -Dsonar.java.rule.hql=security" - Jenkins Pipeline:
withSonarQubeEnv块内必须显式指定sonar.java.binaries=target/classes,否则没有字节码,AST 分析无法进行,所有 Java 安全规则失效 - Maven 多模块:父 pom 里配了
sonar-maven-plugin,但子模块没声明sonar.language=java,可能 fallback 到通用解析器,跳过 Hibernate/JPA 语义识别
semgrep 更轻量、更早介入的替代方案
如果不想等 SonarQube 走完编译+分析+上传整套流程,semgrep 可以在代码提交前就拦截。它不依赖字节码,纯靠语法树匹配,对 f"SELECT * FROM {table}" 或 cursor.execute(query + user_input) 这类模式识别率高。
CI 中关键配置项:
- 加
--error:匹配到规则时进程返回非 0 码,GitHub Actions / GitLab CI 自动标红失败 - 排除干扰路径:
--exclude=tests/ --exclude=migrations/,否则误报率飙升 - 用开源规则
python.lang.security.insecure-sql-string-concatenation,命中即阻断 - 注意:它抓不到运行时拼接(如 ORM 的
filter(**{dynamic_key: value})),需配合 Bandit 或 CodeQL 补位
本地预检比 CI 流水线早一个提交周期
别等 git push 触发 CI 才发现漏洞。VSCode 里装 CodeQL 插件,保存时自动跑 sql-injection.ql;或者用 semgrep CLI 绑定 pre-commit hook,git commit 前强制扫描。
真正容易被忽略的是:SQL 注入不止发生在 WHERE 条件里。表名、字段名、ORDER BY 子句、UNION 后的查询结构,只要来自用户输入且未校验白名单,就是高危点——而这些地方,PreparedStatement 根本不管用,静态扫描是唯一能提前暴露它们的方式。











