不能直接在CI里跑sqlmap,因其会发真实请求触发WAF、写脏数据、锁表,返回无明确退出码且默认--level=3耗时长,易拖慢流水线。

为什么不能直接在CI里跑sqlmap
sqlmap 是渗透测试工具,不是 CI 友好型检查器。它会在运行时发真实 HTTP 请求,可能:触发 WAF 封 IP、写脏数据进测试库、锁表导致后续构建失败;返回结果是概率性提示(如 possible SQL injection),没有明确退出码,CI 无法做 if 判断;默认 --level=3 耗时长,拖慢整条流水线。所以别在 .gitlab-ci.yml 里写 sqlmap --batch -u "https://test.example.com/api?id=1"——这不是集成,是给流水线埋雷。
semgrep 抓拼接模式的关键配置
semgrep 基于 AST 匹配,不依赖编译,适合代码提交前拦截 SQL 拼接。但默认配置几乎必然误报或漏报,必须显式指定参数:
-
--error:匹配到规则就返回非 0 码,CI 自动标红失败 -
--exclude=tests/ --exclude=migrations/:否则SELECT * FROM user_test这类测试 SQL 会误报 -
--config=p/python.lang.security.insecure-sql-string-concatenation:必须写完整规则 ID,只写p/python不生效 -
--json --output=semgrep.json:输出结构化结果,方便后续解析或归档
GitLab CI 示例命令:
semgrep --config=p/python.lang.security.insecure-sql-string-concatenation \ --error \ --exclude=tests/ \ --exclude=migrations/ \ --json --output=semgrep.json \ .
SonarQube 验语义上下文的三要素
SonarQube 能识别 @Query("SELECT * FROM u WHERE name = '" + name + "'") 这类 JPA 场景,但 Java 安全规则默认关闭,且缺一不可:
-
sonar.java.rule.jdbc=security:必须显式启用 JDBC 安全规则,否则Statement.executeUpdate("UPDATE t SET v = " + input)静默通过 -
sonar.java.binaries=target/classes:没这个路径,AST 分析跑不起来,所有安全规则失效 -
sonar.sources=src/main/java:源码路径不对,上下文识别失败,@Query注解就漏掉
GitLab CI 中推荐设为环境变量,避免硬编码路径变化导致扫描失效。
真正可落地的组合策略
semgrep 和 SonarQube 不是二选一,而是分层互补:
- semgrep 在 PR 阶段快速拦截明显拼接(如
cursor.execute("SELECT * FROM " + table)),响应快、无副作用 - SonarQube 在构建后阶段分析编译产物,验证带框架语义的调用(如 MyBatis
${param}、JPA@Query),需要完整 classpath - 两者都必须卡在“代码合并前”:semgrep 放 pre-merge hook 或 CI 的 lint 阶段;SonarQube 放 build 后、deploy 前
复杂点在于:二阶注入、ORM 动态查询、存储过程调用这些场景,静态工具仍会漏报。这类问题必须靠人工代码审计补位,不能全指望自动化。

















