1. 问题背景
今天主要是给大家分享一个如何从两个维度去制定CC的安全防护策略;
如何根据IP或者cookie限制URI个数的安全策略?
如何根据IP或者cookie限制UID个数的安全限制策略?
02. 算法介绍
关于cuckoo_filter 和bloom_filter 是我们日常生活中常用的过滤器,最大的特点是可以快速判断一个元素是否存在某个集合中, 特点是快速并且准确。相比cuckoo_filter优化了bloom_filter 误判的缺点!
由于算法是二进制向量的一种映射逻辑,所以存储空间小却能判断集合,正好满足安全策略的性能和存储特点
03. 已知的解决方案(可能还有更多;希望大家补全)
安全工作中,其中CC攻击防护和频率限制是我们经常要面对的事情,比如目前nginx 和openresty中的limit 等安全限制策略,可以很好从单一维度去限制请求频率;
如下配置,限制单个IP地址的访问次数
http { limit_req_zone $remote_addr zone=mylimit:10m rate=5r/s; server { location / { limit_req zone=mylimit burst=10 nodelay; } } }
技术结构采用的共享内存技术,通过内存过期算法统计频率
如图所示 通过读取key的次数做相对的逻辑判断,那问题来了;如何去统计同一个ip地址下访问了多少种页面,多少个cookie;多少种uid呢?
如果采用类似的方法话;我们尝试过以下几种方法(可能能力有限)
1)采用key_xxx这种计数方式 统计uid次数,但是shared还是没有好的方法去快速分析,需要实时遍历数据难度较大
2)存储JSON数据结构,(但是需要大量的内存去支持分析);我们尝试过,流量稍微大一点的节点IP+uid记录全部;nginx上内存直接炸掉
3)有钱人的方法 可以外部挂一个统计中心(钱阔以解决大部分计数难题);这种是最佳的解决方案。
04. 我们是如何解决的 保证平衡效率和速度
主要的原理计数架构图如下,采用cuckoo_filter的计数方式,快速统计出数据访问次数和个数!
其中主要是可以将一个cuckoo filter 对象进行编码和解码,做到上次数据状态保存,可以做到不同的数据进行统计而不影响过多的内存使用。
04. 模块代码和函数分析(核心代码)
模块采用C+lua的开发,兼容apisix,openresty等常见的luajitweb框架
项目地址:https://github.com/vela-security/x-limit-cuckoo
其中 cuckoo filter 的 encode 实现
然后cuckoo_filter的decode方法
还有一些其他函数就不一一介绍了
05. 实际应用效果
案例中采用openresty为框架测试案例
效果如下
06. 问题答疑
除了要用cuckoo_filter 算法 有其他算法吗?
答:也尝试过bloom_filter 版本 但是相同误差情况下 bloom_filter消耗空间和误差大一点 所以选择了cuckoo
为什么要启用snappy压缩算法?
答:主要是在cuckoo.new(10000)比较大的bucket时候,存储空间也比较答,但是流量特征中大部分是小于50左右,此时内存大部分bucket为空,不压缩内存还是比较高,压缩可以00100100这种0比较多有效压缩
这个是单机版本,集群版本吗?
答: 有开发过redis共享版本
必须依赖so,有无纯lua版本?
答: 目前开发过bloom_filter 过滤器纯lua版本,由于cuckoo版本需要snappy压缩 暂时没有
07. 总结
利用cuckoo_filter 过滤算法除了可以uid统计,有很好的性能和空间优化,目前采用lua c 开发方式,性能相对ffi较少,后期考虑开发ffi版本。最后希望插件能解决业务相关需求,不喜勿喷;还有大家有优化和想法可以联系.