openresty+redis拦截高频访问IP

文章目录

[隐藏]

  • CC攻击
  • 自动拦截
  • 安装环境
  • nginx配置
CC攻击

网站受到攻击通常是黑客通过几个甚至多个IP地址,在短时间内进行超高频率访问,从而让服务器在短时间内增加巨大的计算量,导致负载增加,降低响应能力,甚至直接宕机停止服务。
通常这类情况我们只能通过查看分析网站日志,从而获得攻击者的IP地址,再通过防火墙进行拦截。
但一般而言这只会发生在监控系统已经开始报警之后,也就是网站或服务已经遭受到了攻击,并造成影响之后。并且在日志中搜寻到攻击者的IP并不是十分简单的事情,通常当我们找到了攻击者,攻击者可能已经停止了攻击,我们也只能预防他下次可能的攻击。

自动拦截

经历了黑客们深夜的骚扰和攻击,如何让那些短时间内大量访问的地址被自动拦截变成了努力的方向。
云服务商提供了WAF等商业化产品,协助我们处理这些威胁。
相比较于这些高昂价格的产品,开源软件同样在灵活性和可整合性上有很大的优势,接下来就介绍一下我是如何使用openresty和redis实现拦截高频访问的地址。

安装环境

之前的文章已经介绍过:Openresty+Redis 动态切换upstream (http://learn-learn.top/archives/169.html)
大致按照官方介绍就可以轻松安装。

nginx配置

nginx在初始化时建立一个redis的链接,并且在每次访问前需要执行block.lua进行验证

init_by_lua_block {      redis = require "redis"      client = redis.connect('127.0.0.1', 6379)  }  server {      listen 8080;      location  / {          access_by_lua_file /usr/local/nginx/conf/lua/block.lua;          proxy_pass http://192.168.1.102:8000;      }  }  

lua脚本:

function isConnected()      return client:ping()  end  function createRedisConnection()          return redis.connect('127.0.0.1', 6379)  end    if pcall(isConnected)then --如果发生redis连接失败,将停止拦截。      --  else      if pcall(createRedisConnection)then     --断开重连会发送每次访问都需要重连redis          client = createRedisConnection();       --如果访问量大的情况下,建议关闭重连,if pcall不执行,直接ngx.exit      else          ngx.exit(ngx.OK);      end  end      local ttl = 60;     --监测周期  local bktimes = 30; --在监测周期内达到触发拦截的访问量  block_ttl = 600;    --触发拦截后拦截时间  ip = ngx.var.remote_addr  ipvtimes = client:get(ip)    if(ipvtimes)then      if(ipvtimes == "-1")then          --ngx.say("blocked")          return ngx.exit(403);      else          last_ttl = client:ttl(ip)          --ngx.say("key exist.ttl is ",last_ttl);          if(last_ttl==-1)then              client:set(ip,0)              client:expire(ip,ttl)              --ngx.say("ttl & vtimes recount")              return ngx.exit(ngx.OK);          end          vtimes = tonumber(client:get(ip))+1;          if(vtimes<bktimes)then              client:set(ip,vtimes);              client:expire(ip,last_ttl)              --ngx.say(ip," view ",vtimes," times");              return ngx.exit(ngx.OK);          else              --ngx.say(ip," will be block noext time.")              client:set(ip,-1);              client:expire(ip,block_ttl)              return ngx.exit(ngx.OK);          end      end  else      --ngx.say("key do not exist")      client:set(ip,1)      --ngx.say(ip," view 1 times")      client:expire(ip,ttl)      return ngx.exit(ngx.OK)  end  

脚本说明:

1.重要参数:

ttl = 60; –监测周期
bktimes = 30; –在监测周期内达到触发拦截的访问量
block_ttl = 600; –触发拦截后拦截时间

以上参数表示,一个IP地址在60秒内访问超过30次将被拦截600秒。

2.逻辑说明:

a)检测初始化的redis连接是否能够正常运行,如果连接失败或已经断开,将会重新建立连接,如果仍旧无法连接,将直接放行。这里是为了避免redis宕机导致nginx无法正常响应。当然如果初始连接中断,将会导致每次访问都会创建redis连接。

b)当某个IP首次访问时,将在redis中新建一个以IP地址为KEY的键(如果需要多个站点,修改下key的命名规则即可),value为1,并设置expire时间。当这个地址再次访问且key尚未过期前,将会每次递增key的value数,直到到达达到bktimes,或者key到期从而消亡。(本人用的redis5.0,到期key会直接不存在,可能部分版本到期后value为-1)

c)当key过期后,对于系统而言就是第一次访问,重新创建value为1的新key

d)当达到bktimes后,会将对应的IP的key的value设置为-1,且过期时间为block_ttl。

e)当访问到value为-1的key,即某个IP达到了我们设定的访问频次,我们将直接拦截,返回403.

3.完善方向:

a)在访问前添加黑白名单功能(这个在redis中新建立两个key即可)
b)拦截IP段(根据访问的IP地址建立以IP段为key的字段即可)
c)redis断开重连后,每次访问都要建立连接问题。

原文出处:learn-learn -> http://learn-learn.top/archives/184.html

本站所发布的一切资源仅限用于学习和研究目的;不得将上述内容用于商业或者非法用途,否则,一切后果请用户自负。本站信息来自网络,版权争议与本站无关。您必须在下载后的24个小时之内,从您的电脑中彻底删除上述内容。如果您喜欢该程序,请支持正版软件,购买注册,得到更好的正版服务。如果侵犯你的利益,请发送邮箱到 [email protected],我们会很快的为您处理。
超哥软件库 » openresty+redis拦截高频访问IP