cache设置不当导致的Mercari用户情报泄漏

前两天,日本最大的二手个人交易应用Mercari的web版发生了大量的用户情报泄漏事件。
很多用户反映自己看到了别人的地址,点数,购买历史,信用卡尾号等等信息。

调查的结果表明,此次用户信息泄漏,是由于在切换CDN 服务商的时候,cache-control的 http header设置的不当,导致CDN误缓存了本来不该缓存的用户情报而引起的。

web服务的成长

一般来说,你的几百个用户的小博客,你帮人做外包的CURD小应用,一台廉价的vps就可以跑地起来。

当你的用户渐渐增长的时候,我们可能需要加上load balancer, 增加服务器的台数来抵抗增加的request数目。

当你的用户再次突破性地成长,你发现单纯累加服务器的台数的效果已经逐渐消失的时候,你就应该考虑使用CDN去帮助你抵抗大量的request。

事故经过

控制缓存(Cache)的策略有很多。比如有些CDN服务商就提供这种简单的配置,这样不需要担心服务器端的配置,工程师也可以把精力放到更重要的地方。
通过CDN的设置来控制Cache是Mercari切换CDN之前的做法。而切换了CDN之后,新的CDN支持通过HTTP 的cache-control header来设置CDN的Cache策略。
于是,Mercari并没有通过CDN的配置来禁止Cache,相反采用了设置HTTP header的方法。新的方法在经过本地修改hosts,简单测试一下后就草草上线了。

切换CDN之前,Mercari在服务器端nginx的关于cache的设置如下所示。

1
2
3
4
5
location / {
# disable cache
expires -1;
proxy_pass https://127.0.0.1:80;
}

用户实际获得的response header的形式如下。

1
2
Cache-Control: no-cache
Expires: Thu, 22 Jun 2017 08:58:21 GMT (上一秒的时间,保证浏览器不cache内容)

这样,仅仅通过在CDN端的设置,就可以控制需要Cache的内容。而服务器端只需要保证自己的设置没有用到Cache即可。

我们知道,设置 cache-control no-cache 可以用来申明本url的以后的所有request都直接发送到server。
cache-control no-store则在response的时候告诉每个传递者不要cache本response的内容。这样在nginx的配置中,通过设置或者不设置cache-control no-cache no-store,可以控制哪些部分需要cache,哪些可以不需要cache。

这一切,如果当然仅仅是想当然。

等到有用户发现看到其他用户信息的时候,事情闹大,再去详细查看CDN服务商的说明,发现只有设置了cache-control private,CDN才会不进行内容的Cache。
而就算有了expires -1的设定,只要存在cache-control的header,CDN会直接无视expires header的相关设定。

事后,Mercari切换回了原来的CDN,并对新的CDN的cache进行了清理。我们再次打开Mercari,发现使用的CDN是Akamai。这个应该是切换之前的CDN吧。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
$ nslookup 184.26.231.118
Server: 103.5.140.18
Address: 103.5.140.18#53

Non-authoritative answer:
118.231.26.184.in-addr.arpa name = a184-26-231-118.deploy.static.akamaitechnologies.com.

Authoritative answers can be found from:
26.184.in-addr.arpa nameserver = ns7.reverse.deploy.akamaitechnologies.com.
26.184.in-addr.arpa nameserver = ns2.reverse.deploy.akamaitechnologies.com.
26.184.in-addr.arpa nameserver = ns8.reverse.deploy.akamaitechnologies.com.
26.184.in-addr.arpa nameserver = ns4.reverse.deploy.akamaitechnologies.com.
26.184.in-addr.arpa nameserver = ns6.reverse.deploy.akamaitechnologies.com.
26.184.in-addr.arpa nameserver = ns1.reverse.deploy.akamaitechnologies.com.
26.184.in-addr.arpa nameserver = ns3.reverse.deploy.akamaitechnologies.com.
26.184.in-addr.arpa nameserver = ns5.reverse.deploy.akamaitechnologies.com.
ns6.reverse.deploy.akamaitechnologies.com internet address = 23.61.199.32
ns3.reverse.deploy.akamaitechnologies.com internet address = 23.74.25.32
ns2.reverse.deploy.akamaitechnologies.com internet address = 2.16.40.32
ns5.reverse.deploy.akamaitechnologies.com internet address = 95.100.173.32
ns7.reverse.deploy.akamaitechnologies.com internet address = 184.26.161.32
ns1.reverse.deploy.akamaitechnologies.com internet address = 96.7.50.32
ns4.reverse.deploy.akamaitechnologies.com internet address = 95.100.168.32
ns8.reverse.deploy.akamaitechnologies.com internet address = 2.22.230.32

总结来说

对于用户敏感的内容,加上cache-control private总是没有错误的。

切换前修改hosts,草草点access几下进行测试的方法,也是不够专业。在投入release之前,应该使用一小部分节点进行回归测试,确定没有问题再全部切换。

读懂文档很重要。尤其是文档很坑的事后。

更详细的说明,大家可以参考官方的问题说明报告