这两天翻日志的时候,无意间撞见了一批很诡异的调用记录。短时间内突然涌进来一堆请求,拿着不同的 Key 反复拉取模型列表,接着又挨个发极短的请求测试模型能不能通——这种测不通就立刻换下一个的架势,怎么看都是在跑自动测活脚本:sakta_emoji_12:

一开始我还以为只是哪把分发出去的 Key 不小心漏了,结果顺着时间线往前一翻日志,冷汗直接下来了,事情比预想的麻烦得多:sakta_emoji_80:

密钥是怎么出去的

往前翻更早的访问记录才发现,在这些测活请求出现之前,其实已经有人调过后台的备份导出和账户相关接口,而且请求全都成功了。

我赶紧拉下代码排查,并在本地做了复现,最后确认是当时跑的 metapi v1.3.0 存在后台鉴权绕过问题。因为我自己平时对代码做过一些修改,起初还怀疑是不是自己改出了岔子,特意拉了官方同版本的源码对照,确认原版就存在一样的漏洞。

为了避免问题被直接拿去刷,具体的复现细节我先不公开了:sakta_emoji_87:,相关的复现材料和修复补丁都已经整理好。本来想走私下渠道报给作者,结果安全报告页面打不开,发邮件也直接退信,实在没招,最后只能在仓库提了个 Issue,请作者留一个能用的联系方式。

现在回过头把日志里的时间线串起来,前因后果就很清楚了:对方先绕过鉴权摸进后台导出了数据,隔了一段时间,才开始拿里面的多把密钥跑脚本测试模型。虽然历史日志没有保存导出接口返回的具体内容,没法百分百确定对方究竟拿走了哪些字段,但光凭现有的线索,已经足够让我按“整批凭据全部泄露”的最坏情况来处理了。

影响有多大

最让我头疼的是备份里保存的那些信息:sakta_emoji_75:。里面不光有中转发出去的子密钥,连带着上游的账户凭据和相关配置也全在里面。所以只处理日志里露过面的那几把密钥,显然是不够的。

目前已经确认有一部分未经授权的成功调用。至于具体损失了多少额度,现在还算不清——本地日志只能看到经过中转的请求;

好在排查了一圈,暂时没有发现服务器被入侵或者数据被恶意删除的迹象。现阶段能确认的,主要是后台访问控制失效,以及随之而来的凭据泄露和盗刷风险。

发现问题后,第一时间停用了旧密钥,给程序打上补丁、更新了容器,也顺手把外网的访问入口收紧了一圈。“停用了旧密钥”这意味着中转服务已经暂停了,暂时不新发下游密钥了,这不代表跑路:sakta_emoji_22:;

不过补丁打上只是第一步,已经流出去的凭据随时还可能被继续盗用。接下来还得把相关的上游凭据挨个撤销、更换,核对这段时间的异常消耗,最后再重新整理客户端配置。这堆善后工作目前还在慢慢填坑中(特么涉及快上千的key,要累死:sakta_emoji_73:)。

这次踩坑也算是给我敲了个警钟:中转服务里集中放着不少账户和密钥,本质上就是个高价值的单点,一处出了问题,往往就会牵连一整批。以后不管是部署还是升级,后台访问控制、端口暴露和凭据管理真得多查几遍。

停运维护

目前中转已暂时停止运行,进入维护状态。

接下来打算考虑迁入 sub2api,正好趁这次把凭据和部署配置一起彻底重整一遍。等迁移完成、把权限和访问限制全部重新检查稳妥之后,再考虑恢复服务吧:sakta_emoji_84: