3. 审查对象与代码资产梳理

代码安全审查的第一步不是打开某个文件找漏洞,而是先回答一个更基础的问题:这个系统里到底有哪些东西需要审?如果审查对象没有盘清,后续的规则配置、工具选型和人力分配都会失焦——要么漏审关键资产,要么把大量时间花在低风险文件上。本节围绕六类典型审查对象展开:源代码、二进制、配置、依赖、IaC(基础设施即代码)和 CI/CD 脚本,并给出仓库结构分析、资产清单与优先级排序的可落地方法。

六类审查对象及其识别特征

源代码是最直观的对象,但识别时要注意区分业务代码、框架代码、自动生成代码和第三方内嵌代码。自动生成的代码(如 protobuf 生成文件、ORM 映射文件)通常不应作为人工审查重点,但需要在清单中标注来源,避免误判为“未覆盖”。

二进制包括编译产物、预编译库、容器镜像中的可执行文件。审查重点不是逐字节逆向,而是确认其来源可信、版本可追溯、是否包含已知漏洞组件。识别信号包括文件扩展名(.so、.dll、.exe、.jar)、构建产物目录(target/、dist/、build/)以及镜像层中的可执行文件。

配置涵盖应用配置、中间件配置、密钥与凭据文件。典型对象有 application.yml、nginx.conf、.env、settings.py 中的敏感项。配置审查的核心是“是否泄露、是否过宽、是否可被外部覆盖”。

依赖指直接与间接引入的第三方包。识别依据是包管理文件:pom.xml、package.json、requirements.txt、go.mod、Cargo.toml 等,以及对应的锁文件(package-lock.json、poetry.lock)。锁文件比声明文件更能反映真实运行时依赖。

IaC 包括 Terraform、CloudFormation、Kubernetes YAML、Ansible Playbook 等。它们描述的是基础设施与部署形态,一旦配置不当,风险等级往往高于单个应用漏洞,例如公开的 S3 桶、过宽的 IAM 策略、特权容器。

CI/CD 脚本包括 .github/workflows/、.gitlab-ci.yml、Jenkinsfile、构建脚本等。它们掌握着构建、测试、发布链路的权限,是供应链攻击的高价值目标,需要重点检查密钥引用方式、第三方 Action 版本固定情况、脚本注入风险。

代码资产梳理:从仓库到审查优先级 代码仓库 src/ 业务源码 config/ 配置文件 pom.xml / package.json infra/ IaC 模板 .github/ CI 脚本 dist/ 二进制产物 .env / 密钥文件 vendor/ 内嵌第三方 识别与分类 源代码 人工审查 + SAST 二进制 来源核验 + SCA 配置 密钥扫描 + 基线核查 依赖 SCA + 锁文件比对 IaC 策略即代码 + 合规检查 CI/CD 脚本 权限审计 + 注入检查 审查优先级排序 P0 最高优先 CI/CD 密钥 · 公开 IaC · 认证授权代码 P1 高优先 外部输入处理 · 依赖高危组件 · 配置泄露 P2 中优先 内部业务逻辑 · 日志与错误处理 P3 低优先 自动生成代码 · 测试代码 · 文档 排序依据 暴露面 × 权限 × 数据敏感度 × 变更频率 资产清单需记录:路径 · 类型 · 责任人 · 最近变更 · 审查状态 · 风险等级

代码仓库结构分析

拿到一个仓库后,先看顶层目录结构,再逐层下钻。常见的结构信号包括:src/ 或 app/ 通常是业务代码;config/、conf/、settings/ 是配置集中区;infra/、deploy/、k8s/ 是 IaC 所在;.github/workflows/、.gitlab-ci.yml、Jenkinsfile 是 CI/CD 脚本;vendor/、third_party/、node_modules/ 是第三方代码;dist/、build/、target/ 是构建产物。

分析时建议同时关注多模块仓库和单模块仓库的差异。多模块仓库(如 Maven 多模块、Gradle 多项目)需要先读根 pom.xml 或 settings.gradle,理清模块依赖关系,再决定审查顺序。单模块仓库则重点看入口文件和路由配置,快速定位对外暴露面。

一个容易被忽略的点是历史遗留目录。很多仓库里存在 legacy/、old/、backup/ 等目录,它们可能仍被部署脚本引用,也可能包含硬编码密钥。审查时不能因为名字带“old”就直接跳过,而应确认其是否仍在构建或部署链路中。

资产清单的字段设计

资产清单不是简单的文件列表,而是一张可追踪、可排序、可复核的工作表。建议至少包含以下字段:

字段说明示例
资产路径仓库内相对路径src/main/java/com/acme/auth/LoginController.java
资产类型六类之一源代码
责任人模块负责人或团队认证组
最近变更最近一次提交时间2025-03-12
暴露面是否对外可访问是(HTTP 接口)
数据敏感度是否处理敏感数据高(凭据、令牌)
审查状态未审 / 审查中 / 已审未审
风险等级P0~P3P0

清单的粒度需要权衡。按文件逐条登记会产生大量低价值条目,按目录登记又可能漏掉关键文件。折中做法是:P0/P1 资产按文件登记,P2/P3 资产按目录或模块登记。这样既保证关键资产可追踪,又控制清单规模。

审查优先级排序方法

优先级排序的核心是四个维度的乘积:暴露面 × 权限 × 数据敏感度 × 变更频率。暴露面指是否可被外部访问;权限指该资产在系统中的执行权限;数据敏感度指是否接触凭据、个人信息或核心业务数据;变更频率指近期提交活跃度——频繁变更的代码更容易引入新问题。

以某电商系统为例,排序结果可能是:CI/CD 脚本中的密钥引用(P0,因为掌握发布权限且可能泄露凭据)、公开的 IaC 模板(P0,可能直接暴露存储桶或数据库)、认证授权代码(P0,直接决定访问控制)、外部输入处理代码(P1,存在注入风险)、依赖中的高危组件(P1,已知漏洞可直接利用)、内部业务逻辑(P2)、自动生成代码(P3)。

优先级不是一次定死的。随着审查推进,如果发现某个 P2 资产实际上被 P0 资产直接调用,应动态上调其优先级。建议每完成一轮审查后复核一次排序。

实操示例:从仓库到清单

假设拿到一个 Spring Boot 项目,仓库根目录如下:

acme-order-service/
├── src/main/java/          # 业务源码
├── src/main/resources/
│   ├── application.yml     # 应用配置
│   └── application-prod.yml
├── pom.xml                 # 依赖声明
├── infra/
│   ├── main.tf             # Terraform
│   └── k8s/deployment.yaml
├── .github/workflows/
│   └── deploy.yml          # CI/CD
├── .env                    # 本地环境变量
└── target/                 # 构建产物

梳理步骤:先执行 find . -maxdepth 3 -type f | head -100 快速浏览文件分布;再用 grep -r "password\|secret\|token" --include="*.yml" --include="*.tf" --include="*.yml" . 定位潜在敏感配置;然后读取 pom.xml 确认依赖清单,读取 deploy.yml 确认发布流程中是否引用密钥;最后按上表字段逐条登记,并给出 P0~P3 排序。

完成后的清单应能回答三个问题:哪些资产必须人工审、哪些可以工具扫、哪些可以暂时不审。如果清单无法支撑这三个判断,说明字段设计或排序依据还需要调整。

不要用“文件数量”衡量梳理完成度。一个 5000 文件的仓库,真正需要人工审查的可能只有 80 个文件;而一个 200 文件的仓库,如果包含 CI/CD 和 IaC,关键资产密度可能更高。梳理的目标是找到关键资产,不是穷举所有文件。

资产梳理完成后,后续的规则配置、工具选型和审查排期才有依据。下一阶段的工作将围绕这些已识别的资产展开具体审查,而清单本身也会在审查过程中持续更新。