测试同学必会系列之如何去应对缓存穿透
最近我们在做一些安全加固的工作,其间我们发现我们的一些接口存在缓存穿透的风险。
所谓的缓存穿透就是原本应该在缓存层面做的查询因为某种原因没有命中缓存,从而直接在数据库里进行查询。最典型的例子就是访问一个不存在的key,缓存不起作用,请求会穿透到DB,流量大时DB会挂掉。
这时候有同学就要有疑惑了,每次查询不就是应该从数据库拿数据的吗?这应该是正常现象,怎么会是安全风险呢?
这是因为在很多互联网公司,特别是流量大的场景下,我们一般不会让请求直接打到数据库,而且先去缓存查,缓存里找不到再去数据库里取,在极端情况下甚至直接返回空值,连查数据库都省了。这一设计的原理就是缓存的qps比数据库要高很多,在大流量时数据库很容易成为瓶颈,因此加个缓存保护是必要的。
一些恶意攻击者会构造大流量,其实就是像是我们性能测试时写的脚本,对在线服务进行ddos或者cc攻击,如果每一个攻击请求都去查数据库,那么数据库难免不堪重负直接瘫痪,如果恶意请求没有在接入层挡住,那么哪怕数据库重启了也会被后一波流量打垮,真的是拉都拉不起来。保护相数据库,人人有责。
当然了如果你的服务可以保证只有平稳而且比较少的流量访问,不用缓存也未尝不可。
解决方案
解决这个问题有几个思路。
采用布隆过滤器,使用一个足够大的bitmap,用于存储可能访问的key,不存在的key直接被过滤
访还有一种做法是如果访问的key未在DB查询到值,也将空值写进缓存,但可以设置较短过期时间。这样下次同样的非法key进来就会命中缓存,保护了数据库。
思考
我们经常说测试同学其实大部分的时间都是在考虑异常情况。
如果被测系统使用了缓存,那么我们不妨加个常规的测试用例,那就是如果在请求中构造一些不存在的key,看看系统的表现。正常预期应该是请求不会直接穿透到db层。
举个例子。
假设下面的接口是查看商品id=1的接口。
GET /api/v1/items/1
那么攻击者可能会构造 GET /api/v1/items/9999999
查询这种不存在的商品,因为商品不在缓存里,所以就会直接查数据库,造成了穿透。
把你的看法跟开发讨论一下,说不定他会对你刮目相看哦。