去年十月,某头部电商平台凌晨崩溃了四个小时。产品订单系统卡死,和系支付回调全部超时,统漏用户看到的自身责任是白屏和“服务暂不可用”。事后复盘,产品根因是和系一段三年前写的优惠券计算逻辑——一个没做边界检查的除法,在某个特定满减组合下除数为零,统漏直接让整个订单模块抛异常。自身责任而更讽刺的产品是,这段代码的和系单元测试覆盖率是100%,测试用例里唯独漏了“满减金额等于订单金额”这一种情况。统漏
没人能说这是自身责任用户的责任。哪怕那个用户恰好凑出了那个诡异的产品满减组合,哪怕他反复点击了“提交订单”按钮十几次。和系产品崩溃了,系统挂了,责任就在写代码的人、在设计架构的人、在上线前拍胸脯说“没问题”的人身上。这事没什么可推诿的。
我见过太多团队在事故复盘会上把矛头指向“异常流量”“恶意攻击”“用户操作不当”。前年一个做在线文档的创业公司,数据库被一个简单的模糊查询拖垮,原因是没加索引。CTO在会上说“没想到用户会搜这么长的关键词”。这话听着耳熟吗?就像餐厅老板抱怨客人点太多菜把厨房累垮了。你开门做生意,就得扛住正常范围内的所有操作。用户没义务按你预设的路径走。
产品漏洞和系统漏洞,本质上是一回事——都是设计者对自己造出来的东西理解不够。产品漏洞是业务逻辑上的想当然,系统漏洞是技术实现上的偷懒。两者往往还纠缠在一起。比如一个社交App的“附近的人”功能,产品经理觉得按距离排序就行,没考虑地理位置伪造;后端工程师直接拿客户端传的经纬度去查数据库,没做校验。结果就是有人能通过改请求包把自己定位到任何地方。这怪谁?怪用户太聪明?
有个做安全的朋友跟我说过一句话:“所有输入都是恶意输入。”他做渗透测试十几年,见过的漏洞百分之九十都是开发人员假设“用户会按正常流程操作”。可现实是,总有人会乱填手机号,总有人会复制粘贴超长字符串,总有人会在支付页面按F5刷新一百次。这些行为不叫“攻击”,叫“正常的人类好奇心”。
我自己的团队犯过更蠢的错。一个内部管理系统,上传头像的功能没限制文件大小。测试的时候大家都传几十KB的小图,上线第二天有人传了一张20MB的相机原图,直接把服务器内存吃满。那个功能是我写的,我当时想的是“谁会传这么大的头像”。你看,又是“谁会”。这两个字就是漏洞的温床。
把责任推给用户是最省事的做法,也是最没用的做法。用户用脚投票,崩一次可能还回来,崩三次就永久流失了。你可以在用户协议里写“因不可抗力或用户操作不当造成的损失不承担责任”,但用户不会看,看了也不认。他们只知道你的App打不开,你的网页转圈圈,你的客服电话打不通。
真正该做的,是把“用户会乱来”当成第一前提。写代码的时候多问一句“如果这里传进来的是null呢”“如果这个数字是负数呢”“如果用户在一秒内点了五十次呢”。这些问题不需要多高深的技术,只需要一点对自身产品的敬畏。你造的东西,你得比任何人都清楚它会在什么情况下碎掉。
系统漏洞也一样。别指望用户帮你发现。等他们发现的时候,往往已经晚了。日志、监控、告警、混沌工程,这些不是大厂才配拥有的奢侈品。一个简单的健康检查接口,一个数据库连接数监控,就能在雪崩前给你十分钟的缓冲时间。十分钟够干什么?够你回滚一个版本,够你重启一台机器,够你发一条道歉公告。
说到底,产品和系统都是人造的。人造的东西就有缺陷,这不可耻。可耻的是缺陷暴露之后,第一反应是找别人的问题。那个电商平台后来发了一封公开信,承认是自身代码缺陷,没提任何“异常流量”。我觉得这态度就对了。崩了就是崩了,认。改。下次别再犯。
至于用户,他们不需要为你的漏洞负责。他们只需要决定,下次还来不来。
```