|
一个输入框,漏洞问题用户输入一段话,漏洞问题程序返回一段结果。漏洞问题看起来没问题。漏洞问题但如果用户输入的漏洞问题不是“话”呢? 去年有个团队做了一款文本摘要工具,上线第三天被人发现:输入一个超长字符串——大概二十万个“A”——服务器直接挂了。漏洞问题内存溢出。漏洞问题他们只校验了输入内容的漏洞问题格式,没校验长度。漏洞问题这个漏洞不复杂,漏洞问题甚至有点蠢,漏洞问题但它真实发生了。漏洞问题开发者在写代码时脑子里想的漏洞问题是“用户会正常输入一段文字”,而攻击者想的漏洞问题是“我偏不”。 漏洞的漏洞问题本质是什么?不是技术不够先进,是人的假设出了错。每一条代码背后都站着一个假设:用户会按预期操作,网络会稳定,输入不会恶意。漏洞就是这些假设被推翻的地方。 我见过一个更隐蔽的例子。某电商平台的优惠券系统,逻辑是“满100减20”。正常流程没问题。但有人发现,如果把两件商品分别下单、同时使用同一张优惠券——因为并发请求的时序问题,两个订单都判定优惠券可用。一张券用了两次。这不是代码写错了,是代码没想到“同时”这件事。 并发漏洞特别有意思。单线程思维的人类写多线程的程序,就像让一个只会走直线的人去指挥交通。你觉得A先执行然后B执行,但实际运行时A和B可能同时发生,甚至B先于A。结果就是各种匪夷所思的状态。 还有一类漏洞跟技术无关,纯粹是业务逻辑的问题。比如某平台允许用户用积分兑换商品,兑换后积分扣除。有人发现,在兑换请求发出后、积分扣除前,如果快速取消订单——积分退回来了,但商品兑换记录还在。反复操作,积分越兑越多。这种漏洞你拿扫描器扫不出来,得靠人去“玩”这个系统才能发现。 说回开头那个摘要工具。他们后来加了输入长度限制,但过了一周又出事了。这次是特殊字符。用户输入了一段包含大量Unicode控制字符的文本,前端显示正常,后端处理时字符编码转换出了岔子,数据库写入失败,整个请求链路崩了。修完这个,又发现文件上传接口没限制文件类型——有人传了个伪装成图片的脚本文件上去。 补丁一个接一个。每个补丁都在修补一个“没想到”。 我自己的判断是:漏洞不可能被消灭。你可以减少已知类型的漏洞,可以做代码审计、渗透测试、模糊测试,但“未知的未知”永远存在。这不是悲观,是事实。软件越复杂,假设越多,假设之间的交互越难穷举。一个微服务架构有几十个服务,每个服务有自己的假设,服务之间的调用又产生新的假设组合。你测不完。 能做的事只有一件:承认自己会犯错,然后在架构上留后路。输入校验做在离用户最近的地方,权限检查做在离数据最近的地方,关键操作加幂等,异常情况有降级方案。不是为了让系统无懈可击,是为了在漏洞被触发时,损失可控。 那个摘要工具后来怎么样了?他们招了一个安全工程师,每周做一次对抗性测试。不是走流程,是真的像攻击者一样去“搞”自己的系统。上个月他们发现了一个新问题:用户在摘要结果页面反复点击“重新生成”,每次请求都会调用一次付费的API,没有频率限制。一个人点了一下午,账单多了三千块。 漏洞这东西,你不动手去找,它就在那里安静地等着。 |