>백엔드 개발 >PHP 튜토리얼 >怎么保证对外暴露接口的安全性(调用频率限制)

怎么保证对外暴露接口的安全性(调用频率限制)

WBOY
WBOY원래의
2016-06-06 20:31:012909검색

如何限制接口调用者对接口的调用频率?

问题:对某个对外暴露的接口加一个限制:调用者一分钟之内调用次数不能超过100次,如果超过100次就直接返回给调用者失败的信息。

  • 给调用者一个SECRET,每次调用者需要调用接口的时候,都需要把这个SECRET带过来(为了安全需要对key进行一系列加密的措施)
  • 一个SECRET就代表一个调用者,把相应的SECRET的调用次数放入缓存中(必须确保次数增加的原子性),并且把SECRET当做缓存的SECRET(这里如果区分方法的话,可以把方法和KEY做一次加密)。

这里主要的难点就是,如何判断调用者1分钟之内调用次数是否超过100?也就是很难确实这个1分钟的开始时间。

我现在的想法是:分别把当前秒调用的次数存入缓存。比如说,当前调用者调用次数为3,那么我就往缓存中加入KEY=SECRET_1,VALUE=3;然后调用者在第二秒调用的次数为4,那么就往缓存中加入KEY=SECRET_2,VALUE=3;如此循环,当循环到61秒的时候替换KEY=SECRET_1中得VAALUE,每次调用的时候计算SECRET_1~SECRET_60的值来判断调用次数,是否超过100次。(这里具体一秒钟调用几次,需要通过时间戳来算出是第几秒。这里以60秒为时间周期,并且以秒为一个时间单位,当然如果要求不是很准确的话,时间单位可以调大一点)

问题 请问有没有别的更好方法或者想法可以实现这个调用频率的限制?

回复内容:

如何限制接口调用者对接口的调用频率?

问题:对某个对外暴露的接口加一个限制:调用者一分钟之内调用次数不能超过100次,如果超过100次就直接返回给调用者失败的信息。

  • 给调用者一个SECRET,每次调用者需要调用接口的时候,都需要把这个SECRET带过来(为了安全需要对key进行一系列加密的措施)
  • 一个SECRET就代表一个调用者,把相应的SECRET的调用次数放入缓存中(必须确保次数增加的原子性),并且把SECRET当做缓存的SECRET(这里如果区分方法的话,可以把方法和KEY做一次加密)。

这里主要的难点就是,如何判断调用者1分钟之内调用次数是否超过100?也就是很难确实这个1分钟的开始时间。

我现在的想法是:分别把当前秒调用的次数存入缓存。比如说,当前调用者调用次数为3,那么我就往缓存中加入KEY=SECRET_1,VALUE=3;然后调用者在第二秒调用的次数为4,那么就往缓存中加入KEY=SECRET_2,VALUE=3;如此循环,当循环到61秒的时候替换KEY=SECRET_1中得VAALUE,每次调用的时候计算SECRET_1~SECRET_60的值来判断调用次数,是否超过100次。(这里具体一秒钟调用几次,需要通过时间戳来算出是第几秒。这里以60秒为时间周期,并且以秒为一个时间单位,当然如果要求不是很准确的话,时间单位可以调大一点)

问题 请问有没有别的更好方法或者想法可以实现这个调用频率的限制?

nginx的limit_req_zone就符合你想要的这种需求,它是使用令牌桶算法的.具体你可以看一下.怎么保证对外暴露接口的安全性(调用频率限制)

为每个secret维护一个长度为100的队列
当队列长度为100的时候,取出队列头
判断时间是否超过1分钟,则accept
如果不足1分钟则deny
然后shift和push队列即可

这个呢?
Redis 与网络流量整形
http://blog.jobbole.com/88064/

令牌桶

====
令牌桶算法是网络流量整形(Traffic Shaping)和速率限制(Rate Limiting)中最常使用的一种算法。典型情况下,令牌桶算法用来控制发送到网络上的数据的数目,并允许突发数据的发送。

实现一个栈,存放请求信息,请求来源地或者来源用户,以及请求时间。

然后处理请求就是,系统当前时间向前规定时间内的请求出栈,以供处理。

由于后进先出的选择,出栈的请求应当是按时间顺序倒序排列。然后再统计这些数据中同源数据的个数,小于规定数目的向后转发进行处理,大于规定数目的返回超限的响应。

上述的操作在拦截器或者过滤器中完成。题主觉得这样的思路可行么?

我的想法是这样的:
为每个SECRET维护一个固定60秒的数组, key为每秒的时间(key_1: 第一秒的UNIX时间戳, key_2: 第二秒的UNIX时间戳), value为每秒访问的次数, value的默认值为0.
如果访问时间在这个数组中(通过key_1 + 60来进行判断), 则找到对应的key, 例如key_n.判断由key_1 + ... + key_n的总和是否大于100, 如果小于100, 则key_n++
如果访问时间不在这个数组中, 数组进行初始化, key_1为当前访问时间对应的第一秒的值, 例如当前访问时间为: 2015-06-29 17:09:30, 则key_1为2015-06-29 17:09:01对应的UNIX时间戳

可否创建一个计数器,在cache中set一个key(根据用户标识)=0,设置timeout=60s,这样,新的请求到来,判断是否存在这个key,如果存在key,value>100,则拒绝请求,如果

维护一个List,其中的每个Object包含的内容有
{
secret:'ad822513232',
ip:'127.0.0.1',
timestamp:'231321321',
count:1
};
当一个请求来的时候,根据secret(或ip,依据需求)查找是否存在该对象,不存在则创建,timestamp为当前时间,count1。如果存在对象obj,则先判断当前请求时间和obj.timestamp的时间差是否大于60s,大于就判断obj过期,然后重置它,obj.timestamp= currentTime,obj.count=1,小于则判断count100的大小关系,大于则obj.count++,大于或等于100则废弃当前请求。

Redid 的expire功能完全可以满足你的需求

赞同令牌桶,另外这里有算法,只需要记录一个数据:What's a good rate limiting algorithm?

接口请求频率,你最后采取的什么方案?谢谢

성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.