4. SAST 实战

首次 SAST 扫描的目标不是“把工具跑起来”,而是建立一条可复现的扫描基线:明确扫什么、用什么规则、排除什么、结果如何判读。下面以一个典型的 Spring Boot 多模块 Maven 项目为例,走完从配置到报告解读的完整过程。示例中的路径、规则 ID 和告警数量均为教学假设,用于说明判断逻辑,不代表任何真实项目的实测结果。

一、确定扫描目标与项目结构

假设项目结构如下:

spring-demo/
├── pom.xml
├── demo-web/          # Controller、DTO
├── demo-service/      # 业务逻辑、事务
├── demo-dao/          # MyBatis Mapper、SQL
├── demo-common/       # 工具类、常量
└── src/test/          # 单元测试

扫描目标应覆盖全部生产源码目录(demo-web、demo-service、demo-dao、demo-common),但不应把 src/test、target/、generated-sources/ 纳入。原因很直接:测试代码中的硬编码口令、target 中的编译产物和生成代码,都会制造大量无意义告警,稀释真正需要修复的问题。

二、规则集选择:先窄后宽

首次扫描不建议直接启用全部规则。推荐先启用与 Java/Spring 强相关的高置信度规则集,例如:

  • 注入类:SQL 注入、命令注入、SpEL 表达式注入、LDAP 注入;
  • Web 安全类:XSS、CSRF、开放重定向、路径穿越;
  • 敏感信息类:硬编码密钥、明文密码、日志泄露敏感字段;
  • 反序列化与组件类:不安全的 ObjectInputStream、已知漏洞依赖。

规则集过宽会带来大量低价值告警,过窄则可能漏掉真实缺陷。首次扫描后,再根据误报率逐步调整规则开关和严重级别阈值。

三、排除路径配置

排除路径要写在扫描配置中,而不是靠人工过滤报告。典型排除项包括:

exclude:
  - "**/target/**"
  - "**/generated-sources/**"
  - "**/src/test/**"
  - "**/*.min.js"
  - "**/node_modules/**"

注意:demo-common 中的工具类不要整体排除,因为其中可能包含加密、序列化等高风险逻辑。排除应针对“非生产、非手写、非运行时代码”,而不是针对“看起来不重要的模块”。

四、执行扫描与报告解读

假设扫描完成后,报告给出 37 条告警,按严重级别分布为:高危 6 条、中危 14 条、低危 17 条。此时不要直接按数量排序修复,而要先做三件事:

  1. 看数据流:告警是否给出了从 source 到 sink 的完整路径。例如 @RequestParam 接收的参数是否未经校验就拼进 SQL。
  2. 看上下文:同一段代码是否已有全局过滤器、参数化查询或白名单校验。
  3. 看可达性:该接口是否对外暴露、是否需要认证、是否在真实调用链上。

下面这张图展示了一条典型 SQL 注入告警从输入到判定的完整信号链,以及误报与漏报的分叉点:

SQL 注入告警的信号链与误报/漏报判定 Source @RequestParam("name") 外部可控输入 传播路径 Controller → Service 字符串拼接未净化 Sink Statement.executeQuery 动态 SQL 拼接 扫描报告 高危 · SQL 注入 CWE-89 人工判定:是否真实可达且未净化? 结合认证、过滤器、参数化查询、调用链综合判断 真实缺陷(TP) 拼接 SQL + 无白名单 接口对外暴露 → 修复:改用 PreparedStatement 误报(FP) 已有全局参数化封装 或输入来自内部常量 → 标记忽略并记录原因 漏报(FN) 规则未覆盖 MyBatis ${} 或跨模块污点未追踪 → 补充规则/自定义规则 首次扫描的核心产出:一份带判定结论的告警清单 + 规则/排除路径的调整依据 误报要记录忽略原因,漏报要转化为规则补充或人工审计项

五、误报与漏报的处理原则

误报不是“工具错了”就结束。每条误报都应记录:告警 ID、判定理由、忽略依据(如已有全局过滤器、参数化封装、内部常量来源)。这样下次扫描时才能区分“新出现的误报”和“已知误报”。

漏报更危险,因为它不会出现在报告里。常见漏报来源包括:

  • 规则未覆盖框架特有写法,例如 MyBatis 的 ${} 拼接;
  • 污点追踪在跨模块、跨线程或反射调用处中断;
  • 扫描目标排除了实际参与运行的模块或生成代码。

发现漏报后,应优先补充自定义规则或调整污点传播配置,而不是仅靠人工审计兜底。人工审计可以作为补充,但不能替代规则覆盖。

六、首次扫描的可交付成果

一次合格的首次扫描,至少应产出以下内容:

交付项内容要求示例
扫描配置目标路径、规则集、排除路径4 个生产模块,启用注入/Web/敏感信息规则
告警清单按严重级别 + 可达性排序高危 6 条,其中 4 条确认为真实缺陷
误报记录告警 ID + 忽略理由2 条因已有参数化封装而忽略
漏报线索未覆盖的写法或路径MyBatis ${} 需补充规则
修复优先级按可达性 + 影响面排序先修对外接口的 SQL 注入
首次扫描不要追求“零告警”。目标是建立基线:知道项目当前有哪些真实风险、哪些是噪声、规则和排除路径还需要怎么调。基线稳定后,后续扫描才能通过增量对比发现新引入的问题。
不要把“扫描通过”等同于“没有漏洞”。SAST 只能覆盖它能识别的模式;业务逻辑漏洞、权限绕过、配置错误等往往需要结合人工审计和 DAST 补充。首次扫描的价值在于暴露已知模式下的问题,并建立持续治理的起点。