幂等性导致的一次重大事故

大概三年前,外卖平台 Uber Eats 在印度发生了一次重大事故,使得用户可以免费获得食品。

一天早上,有人试图通过印度的 Uber Eats 订购食物,并使用印度的支付平台 Paytm 付款。但是,他的账户里面没有足够的余额,没有下单成功。

但是,这个人不死心,继续订购,这一次居然成功了!让他在没有付款的情况下,可以订购食物。

消息传开以后,人们疯狂地下单。Uber Eats 短时间涌入大量订单,餐馆无法接单,不得不下线。平台发现了以后,立刻停止使用 Paytm 作为付款方式。

事后调查发现,这个事故与 Paytm 团队前一天上线的一个看似无害的代码变更有关。他们把付款失败的 API 从幂等改为非幂等。

所谓幂等性,指的是如果你重复请求同一个 API,每次都得到相同的响应。

以前,如果余额不够,API 总是返回相同的错误对象,就像下面这样:

  • 1.“尝试在没有资金的情况下向 X 钱包充值”-> 返回 Error1
  • 2.“尝试再次在没有资金的情况下向 X 钱包充值”-> 返回 Error1

现在变成了:

  • 1.“尝试在没有资金的情况下向 X 钱包充值”-> 返回 Error1
  • 2.“尝试再次在没有资金的情况下向 X 钱包充值”-> 返回 Error2

这看起来只是一个很小的变化,偏偏 Uber Eats 的代码有问题。他们假设这个 API 是幂等的,只比较了再次请求失败返回的结果,跟上一次失败的结果是否相同。如果不相同,就认为第二次支付成功了。

事后,餐馆得到了报酬,滥用这个 bug 的用户也没被追究,免费享用了食物。外界并不知道,谁支付了这些食物的费用,到底哪一方应该对这件事负责呢?

只能说两方都有责任。Paytm 在未告知合作伙伴的情况下,API 返回了一个全新的响应。而 Uber Eats 代码不严谨,没有做足够的检查。正是因为双方都有过错,所以责任划分很困难。