|
去年秋天,弥补漏洞我参与了一个中型电商平台的弥补漏洞后端重构项目。上线前三天,弥补漏洞测试组报了一个诡异的弥补漏洞问题:用户下单后,订单状态偶尔会卡在“支付确认中”,弥补漏洞既不成功也不失败。弥补漏洞查了两天日志,弥补漏洞最后定位到一段三年前写的弥补漏洞回调代码——它假设支付网关永远会在5秒内返回结果,超时就丢弃响应。弥补漏洞没人记得这个假设,弥补漏洞也没人补过超时重试的弥补漏洞逻辑。 这个坑不复杂,弥补漏洞但藏得深。弥补漏洞它不在主流程里,弥补漏洞不在文档里,弥补漏洞只在某个离职同事的脑子里。代码能跑,测试能过,线上大部分时候也正常。可只要网络抖动一下,订单就悬在那里,像一只脚踩空楼梯。 修补它花了不到二十行代码。真正费劲的是找到它。这让我开始琢磨一件事:我们说的“漏洞”,很多时候不是技术上的未知难题,而是已知信息在传递过程中掉了链子。写代码的人知道那个5秒假设,但没写注释;读代码的人默认回调是可靠的,没去翻旧提交记录。信息断层,比逻辑错误更常见。 后来我养成一个习惯:每次修完bug,不急着关工单,先问一句——这个漏洞为什么之前没被发现?答案往往指向流程里的某个盲区。比如那次回调问题,根本原因是支付模块的监控只统计成功率,不统计“悬挂订单数”。指标选错了,漏洞就在雷达盲区里待了三年。 补漏洞这件事,分两层。一层是补代码,另一层是补认知。代码补丁可能就几行,认知补丁得改监控、改评审清单、改交接文档。只做第一层,同类问题换个马甲还会回来。我见过一个团队,同一个空指针异常在半年内修了四次,每次都是加个if判断了事。第五次的时候,有人终于去查了上游数据源,发现是某个字段在特定条件下会返回null,而接口文档里压根没提。这才是根。 说个反直觉的观察:漏洞往往不是被“发现”的,而是被“撞上”的。你没法证明一个系统没有漏洞,只能证明你试过的路径都通了。所以修补的终点不是“修好了”,而是“知道哪里可能还没修好”。这话听着绕,但实际工作中,能说清楚“这个补丁的边界在哪”的人,比只会说“修好了”的人靠谱得多。 我现在看一个系统的健壮性,不太看它有多少测试用例,更看它怎么处理“意外”。意外包括:超时、重试、部分失败、顺序错乱。这些场景在正常流程里很少出现,但一旦出现,就是漏洞的温床。修补它们不需要多高深的技术,需要的是对“事情可能不按预期走”的持续警惕。 回到那个电商项目。上线后我们加了一条监控:任何订单在“支付确认中”停留超过30秒,自动告警。告警响过两次,都是支付网关那边的问题。但至少,我们知道了。知道,就是修补的开始。 |