上线前做了一次全量静态审查。
本文只讲方法和结论分布。审查报告本身不入库,也不在这里复述——那份报告带内网拓扑、密钥存放位置和尚未修复问题的文件行号证据,公开它就等于公开一份攻击者的地图。
一、审查怎么进行
三个部分:
- 人工列清单。 先按「一个系统可能从哪些地方被打穿」列出检查面,而不是按目录扫。
- 四个并行只读探查代理。 每个代理负责一组检查面,只读,不允许改任何文件。
- 关键证据人工逐条复核。 代理解释现象可以,但「这条算不算风险、算多重」由人定。
第三步是必要的。代理很容易把「写法不理想」报成「高危」,也很容易漏掉需要跨文件才能看出的问题。它适合做的是穷举和取证,不适合定级。
审查方式记为:静态审查(人工 + 4 个并行只读探查代理)+ 关键证据人工逐条复核。
二、只读约束的作用
让探查代理只能读,有两个好处。
一是没有副作用。审查过程中仓库保持原样,报告的结论可以对着同一个 commit 复现。
二是省掉了「代理顺手改一下」的干扰。审查和修改混在一起,会出现「报告说有问题的地方已经被改过」的状态,后续复核就无法对着证据走。
修改是审查之后单独一轮的事。
三、20 条与四个级别
产出 20 条风险,编号 R01 到 R20。每一条有:位置、触发条件、影响、修复优先级。
按修复优先级分四档:
| 优先级 | 条数 | 排期 |
|---|---|---|
| P0 | 2 | 本周内 |
| P1 | 6 | 两周内 |
| P2 | 5 | 一个月内 |
| P3 | 7 | 一个月内 |
另外有一个独立的「严重级别」列,按严重 / 高 / 中 / 低分:1 / 4 / 7 / 8。两列不对应是有意的——「有多严重」和「该多快修」是两件事。一条严重但需要停机才能修的问题,排期上反而不能放在本周。
整体评级:高。
四、结论里最值得记的一句
未发现 SQL 注入、越权与 IDOR、存储型 XSS 等直接可利用的应用漏洞。
这一句和「整体评级高」摆在一起看,是这个月里最值得记的一条工程结论。
风险分布和直觉不一致。业务代码那一侧没查出可直接利用的漏洞——那部分每天在改、每天在跑、每天有人看。问题更多集中在业务代码之外:构建、部署、配置、凭据流转、依赖引入、运行时加固。
这些东西的共同点是平时不跑。部署脚本一天执行几次,Dockerfile 改一次放很久,集群配置是照着文档抄的。没有日常反馈的东西,问题会一直留在那里,而且不会有人因为「它今天没出事」而去核对它。
五、修复的排期方式
路线图按三档排:P0 本周、P1 两周内、P2/P3 一个月内。
排期依据不是严重级别,是两件事:能不能立即修,和修它会不会动到线上。一条严重但需要停机或改基础设施配置的问题,得等一个发布窗口;一条中等但改动只在一处代码里的问题,可以马上做。P2/P3 是加固项,攒到下一个版本一起走。
这样做的好处是排期可执行。「两个月内修完 20 条」听起来完整,实际会卡在第一条需要停机的问题上。
六、报告为什么不入库
仓库的忽略规则里专门有一条:
# 安全审查报告:含内网拓扑、密钥存放路径与未修复漏洞的 file:line 证据,绝不入库
三条理由,最后一条最关键:
- 内网拓扑
- 密钥存放位置
- 未修复漏洞的精确定位
前两条是常识。第三条是这类文档的特例:一份「待修复清单」在修完之前,本身就是攻击说明书。而它又必须有精确定位,否则修不动。
所以这份文档的流转方式和代码相反。代码进仓库、留历史;它不进仓库,修完一条删一条,修完的结论改记到提交信息里。
七、审查之后,同一天修的东西
审查和修复放在同一天做,这是这次的一个做法。
当天修的一批,主题集中在一类:不报错的失败。队列投递端断线后不重连、依赖返回的包装形状读错导致判定恒为假、入队不带权重插到最前面、参数格式不对被上游全部拒收、重试链被自己的去重压短、管理操作的幂等键缺失、用户可控的文件名直接进对象存储键、唯一漏掉来源校验的 IPC handler、并发删除后返回假成功、过期验证码被复活、临时文件不清理。
这些已经有单独一篇记录,这里只提它们的共性:都不抛异常。
审查报告里那些「不进仓库」的条目和这些「当天修完」的条目,其实是同一批检查过出来的。区别只在于前者需要动基础设施、要等窗口,后者可以立刻改。
八、静态审查的边界
这一轮做的是静态审查,能覆盖和不能覆盖的东西都比较明确。
能覆盖:
- 配置与依赖:镜像标签、依赖来源、加密参数、权限配置。
- 错误处理:异常的吞掉与上抛、失败路径有没有留痕。
- 凭据流转:什么地方读、什么地方写、会不会进构建产物。
- 部署清单:运行用户、资源限制、网络策略、滚动更新参数。
- 代码层面的模式:路径拼接、命令拼接、输入校验的缺失。
覆盖不到:
- 运行时竞态。两个请求同时到、并发删除、租约过期,这些要在真实并发下才暴露。
- 真实的流量特征。哪些入口真的被外部打到、参数实际长什么样,静态看只能推测。
- 业务逻辑漏洞。越权取数据这类问题需要理解「这个人该不该看到这条」,而业务意图不在代码里。
- 组合链。单看每一步都合规,串起来才是问题——这类要动态测试或者真实对抗。
第三类是最容易被静态审查漏掉的:代码里所有校验都写了,但校验的规则和业务规则不一致。
所以静态审查的产出不是「系统安全了」,而是「在它能看见的那一面里,还剩哪些要做」。
九、一次审查真正留下的东西
审完当天修掉的那批,留下的是代码。报告里那些没修的,留下的是三样东西:
- 一份带精确定位和优先级的清单,不进仓库,逐条消掉。
- 一个判断:风险集中的地方和日常注意力集中的地方不一样。业务代码天天改,反而干净;构建部署配置平时没人动。
- 一次复核的习惯:审查的结论要能对着一个 commit 复现,所以探查只读、修改单独一轮。
第 2 条比第 1 条重要。清单会修完,但「平时不跑的东西没人核对」这件事不会自己消失。
■