生产事故-错误密钥引发的接口通信问题

时间:2022-12-23 13:04:54

入职多年,面对生产环境,尽管都是小心翼翼,慎之又慎,还是难免捅出篓子。轻则满头大汗,面红耳赤。重则系统停摆,损失资金。每一个生产事故的背后,都是宝贵的经验和教训,都是项目成员的血泪史。为了更好地防范和遏制今后的各类事故,特开此专题,长期更新和记录大大小小的各类事故。有些是亲身经历,有些是经人耳传口授,但无一例外都是真实案例。

注意:为了避免不必要的麻烦和商密问题,文中提到的特定名称都将是化名、代称。

0x00 大纲

0x01 事故背景

2021年3月19日11时30分,C公司业务人员向外包A公司开发人员反映某业务登记系统从9时许开始无法使用某关键业务接口。该接口依赖于B公司提供的服务,所以刚开始怀疑过是网络波动的问题,经运维人员检查,证明网络连通性没有问题。后来尝试过重启应用服务,也还是不能解决。怀疑是2021年3月18日夜间升级后的系统版本存在缺陷。为了避免进一步影响业务处理,果断先采取系统回滚处理。回滚后,系统业务功能于2021年3月19日12时恢复正常。

0x02 事故分析

为了对问题进行定位和分析,第一时间让运维拷贝和固定了更新前后的系统日志和应用包。奇怪的是,日志上并未见明显异常,调用接口的相关日志没有看到任何 ERROR 级别的日志或者异常堆栈信息。追踪了若干次业务接口调用,均是对端无任何返回,正常情况应该会返回类似{"code":"200","msg":"succeed"}的响应码和响应信息。尝试在测试环境上复现问题并断点跟踪调试,测试环境问题未复现!无奈开始走查代码,但反复查看变更内容,都是与该接口无关的非关键性变更。按道理不可能影响到接口调用。

问题的线索似乎都断了。洗了把脸,重新梳理了目前的几个基本情况:

  • 变更升级后才发生的问题
  • 变更的代码非关键性代码,与接口调用和通信无关
  • 回滚后系统恢复正常
  • 测试环境未能复现
  • 问题不是偶现的

想到这里,一个想法已经呼之欲出,难道是打包的问题?于是拿到了当时部署的war包和与测试环境上的war包进行解包比对,除了配置文件之外其余文件都没有差异,而这正是问题所在。

0x03 事故原因

这是一个通过加密数字信封进行信息交换的接口,数据格式为JSON,加密方式为RSA非对称密钥加密,双方交换公钥,保留自己的私钥,从而实现可信通信。通信过程如下图所示:

生产事故-错误密钥引发的接口通信问题

对方的公钥被打包在应用包中,随着应用一同发布。然而,生产环境和测试环境使用的RSA密钥对是不同的。负责打包的小T,在进行生产应用包打包时,忘记将测试环境的公钥替换成生产环境的公钥了!替换密钥并重新打包部署到生产环境后,业务验证成功。此时已是2021年3月19日13时05分。

0x04 事故复盘

这里面存在一系列的不规范行为,最终导致了问题的发生。但凡有一个环节做好了,可能都可以避免这次事故,或者说更快地定位到问题。

  • 首先是密钥的存储方式。将密钥直接打包到应用包里面是非常不合理的,尤其是它可能发生可预见的变更时。哪怕外置到其他目录,或者存储在数据库中,也不至于发生如此*。
  • 其次是打包的问题。生产环境的包,居然是开发人员在自己机器上打包,然后通过跳板上传到生产服务器上进行部署。不但有些配置容易遗漏,也存在重大的风险隐患,哪怕没有现代化的现代CI/CD管道工具,也应该脚本化和自动化打包。
  • 最后是对端在解密和验签失败的情况下,居然没有任何返回。当然,不能要求外部系统能达到自己软件质量标准,这是不科学的,但是作为一个反例,也提醒了各位开发人员在设计接口时注意规范性,尤其是要给别人用的。

0x05 事故影响

造成C公司关键业务停摆三小时,生产系统紧急回滚一次。A公司吃到客户投诉一张,相关负责人连夜编写事故报告一份。