Hi, TOC安全小组又和大家见面了。
为了缓解大家的工作压力,让大家在工作之余有更多的“放松”时刻,我们推出了《安全故事会》系列内容,计划每周更新一篇公司内部或者业内有名的翻车现场,希望大家在围观的同时能够有所得。
背景
- 本期要分享的是内部的一个案例:某项目其中一项任务是对数据库中的用户敏感信息进行加解密,为了评估加解密后是否会对当前系统有性能影响,需要对此功能在staging环境中进行短信发送业务流程的模拟测试,该测试导致了神秘效果……
事件回放
2020年1月上旬:
PM:我们需要一些性能测试,来了解此次新功能对系统的影响
QA:Get,我要做性能测试
Dev:Get,稍等我给你个服务调用流程和API地址
Ops:什么,要做性能测试?那要注意发送短信的接口,不要真的发出去了
Dev:这是短信发送API,按这个格式发送,我们先测试下
QA & Dev:这是我的手机号,这是我的国家码,调用成功了!咦,短信呢,没收到短信,是不是这个短信在非生产环境不会真实发送?再用浏览器发送,咦,收到了,是不是这个API只能浏览器调用?
2020年1月下旬:
- QA & Dev: 测试脚本终于写完了,本地测试也通过了,走到QA环境测一把。经过了艰难的调试,小规模测试终于通过了,不玩了回家过年去了……
2020年2月初:
QA:终于复工了,Ops来帮忙部署到stagging环境
Ops:要大规模测试了,这个测试分支的短信接口一定已经被屏蔽了吧?(也可能Ops此时忘记了还有短信接口这回事……)好了,部署完毕,可以测试了
QA:终于测试完毕了,好了,分析下报告。
几天之后……
PM:客户怎么突然联系我,说最近短信平台总共发送了几十万条短信,还都是给美国发的,疫情期间不应该这么多数据啊,Ops来查下是怎么回事
Ops:这几天短信量大,莫非是被攻击了,我这没收到什么异常告警啊?赶紧上生产看看,没有啥异常啊……难道是前几天的性能测试?啊,查下staging环境的日志,这短信接口的日志不太对啊,测试时候短信真的发出去了,这下问题有点大
Dev:短信发出去了?stagging和生产共用的同一套配置吗?
QA:短信发出去了?难道我测试调用的接口和生产是同一个?
PM:问题有点大,我们先确认下发出去了多少条、发到哪里了,还需要向上汇报,再告知客户
QA & Dev & Ops:代码分析、日志分析…… 原来这个接口不是这样调用的,是前端拼接后发送给后台的,后台接口中的国家码只是给数据库存储,调用第三方接口时候是需要自己拼接的。这样当时随机构造的手机号,因为都是1开头的,所以1被当做国家码,短信都发到了美国,所以当时浏览器测试可以收到短信,API测试收不到短信,我们总共向美国发送了xxx条短信,发出去的都是随机的验证码,没有敏感信息,也几乎没有一个手机号重复收到多条短信。
客户技术人员:了解,这是你们要的短信发送记录。
客户小Boss:没有发出敏感信息,全部发送到了美国,目前还没收到垃圾短信的投诉,我不希望这件事情扩大到大Boss那,TW可以直接和短信平台结算。
项目全员:内部Retro
PM:和客户、财务、法务拉通,处理后续事宜
项目全员+TP+U Head:Retro
于是,可能是TOC史上最昂贵的性能测试就这样诞生了
亡羊补牢
如何防范生产环境被攻击?已确认,在现有生产环境下,任何一个用户都可以通过浏览器抓包或其他方式识别到短信发送接口,进而无上限调用此接口进行恶意攻击,产生大量费用。可以通过接口访问频率监控+限制、基于历史数据对每日短信发送限额设置合理的上线阈值。
不同环境应该使用不同账号。可以对不同环境设置不同的限额和告警策略,还可以避免一旦生产账号泄露导致其他恶劣后果。
短信平台是否支持白名单,已确认只允许白名单IP的调用。
短信平台账号密码信息存在代码库。成本最低的修改方式是修改为secure variable的形式,直接注入容器环境变量。
非生产限额&告警。首先实现不同环境使用不同账号,然后对非生产环境设置一个较小的上线,以免误操作等产生大量额外费用。
内部短信API手机号码调用时如果没有region信息就报错。这样错误的调用就不会生效,不会去调用三方平台。
调用第三方短信平台的方式改为https,避免通信链路不安全导致API的认证信息泄露。
API文档对内部短信API添加说明信息。
事件影响
手机用户:短信发送地区全部为美国,随机号码发送,重复号码发送量小,短信内容为随机的验证码,不含敏感信息,客户也并没有收到咨询或投诉电话,影响较小。
客户:短信量大,直接导致的经济损失和客户对我们的主观印象损失。
对公司:项目亏损,带来经济损失和声誉损失。
反思
一次事故,必然是所有相关环节都失效了,才会发生,回顾此次事件,其实有这几个关键环节都没有把握住:
测试时未对浏览器和直接调用API的参数进行比对,直接调用API没收到短信时没有进一步追究原因。正确的做法是,通过其他方法,比如后台日志、浏览器抓包、阅读代码等,去真正理解API的调用。这提醒我们,有些项目因为文档、开发团队变动等难以追溯的历史原因,可能导致某些API的调用方式比较神奇,所以在出现一些不合理的现象时,一定要去定位根因,不要想当然,另外,对于技术相关性较强的需求,BA/QA可以和Dev确认更多细节,确保AC/测试用例或者手段是有效;
不同角色之间的沟通没有到位,每个人都是只有部分信息(Dev认为环境是隔离的,QA认为浏览器调用使用的API和测试脚本API不是同一个API,Ops认为代码侧已经修改就不需要考虑环境隔离),而信息不全导致了对整套流程的认识出现了偏差。这提醒我们,在项目中,每个人的上下文要尽可能一致,不要担心沟通成本高;
相关角色没有对调用收费相关API的安全意识,没有对安全需求进行识别,没有对此API进行重视,也没有相应的安全测试用例。这提醒我们,当测试涉及到API的大量调用时,一定要反复确认会不会产生额外的费用。
性能测试流程不完善,没有专门建卡详细列出测试的todo-list和风险项。这提醒我们,不要忽视一些必要的流程,比如之前还见到有的团队为测试申请的云资源忘记释放,最终导致大量费用,而这些问题除了靠相关人员意识外,是可以通过合适的流程去规避的。对一些高风险需求进行安全评估,如需要单独添加安全卡
在QA环境进行小规模测试时,并没有暴露此问题,因为我们没有对收费API有任何限额和监控,只对服务是否正常有监控,而问题的最终暴露是第三方供应商发现异常告诉客户的。这提醒我们,项目中的监控和告警,既要考虑服务状态,还要兼顾一些重要的业务数据,不能在业务数据出现异常时没有感知。
最终在部署版本开始测试前,没有再次确认短信是否真实发出。这提醒我们,在发布版本时,最好要有角色(Ops/TL或其他角色)进行把关,了解到这个版本的功能改动及可能存在的风险点。
如果短信平台没有提醒客户,这样的测试多做几次,会是什么后果?
如果这些短信全部发送到了国内,被人投诉了,对客户造成了恶劣影响,又会是什么后果?
如果发出的信息中包含敏感数据,会是什么后果?可能这会触及到ThoughtWorks的生命线