博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
nginx+lua+redis自动识别封解禁频繁访问IP
阅读量:6657 次
发布时间:2019-06-25

本文共 4853 字,大约阅读时间需要 16 分钟。

  hot3.png

在站点遇到攻击且无明显攻击特征,造成站点访问慢,nginx不断返回502等错误时,可利用nginx+lua+redis实现在指定的时间段内,若单IP的请求量达到指定的数量后对该IP进行封禁,nginx返回403禁止访问。利用redis的expire命令设置封禁IP的过期时间达到在指定的封禁时间后实行自动解封的目的。

一、安装环境:

  • CentOS x64 release 6.4(Final)
  • Nginx-1.4.1
  • Redis 2.6.14
  • LuaJIT-2.0.2
yum install -y gcc gcc-c++ openssl-devel pcre-devel zlib-devel gd-devel GeoIP-devel

二、安装步骤:

1、安装LuaJIT-2.0.2

wget http://luajit.org/download/LuaJIT-2.0.2.tar.gztar -xzvf LuaJIT-2.0.2.tar.gzcd LuaJIT-2.0.2make && make install

注:64位系统安装完成后或许还需要将/usr/local/lib/libluajit-5.1.so.2建立软连接到/lib64//libluajit-5.1.so.2,否则在后面nginx启动时会提示找不到依赖库。

ln -s /usr/local/lib/libluajit-5.1.so.2 /lib64//libluajit-5.1.so.2

2、安装Redis

wget http://download.redis.io/releases/redis-3.2.8.tar.gztar -xzvf redis-3.2.8.tar.gzcd redis-3.2.8make && make install

3、安装Nginx

wget http://nginx.org/download/nginx-1.13.0.tar.gztar xf nginx-1.13.0.tar.gz wget https://github.com/openresty/lua-nginx-module/archive/v0.10.9rc3.tar.gztar xf v0.10.9rc3.tar.gzwget https://github.com/openresty/redis2-nginx-module/archive/v0.14.tar.gztar xf v0.14.tar.gzcd nginx-1.13.0./configure --prefix=/app/nginx \	--user=nginx \	--group=nginx \	--with-poll_module \	--with-http_realip_module \	--with-http_addition_module \	--with-http_sub_module \	--with-http_image_filter_module \	--with-http_geoip_module \	--with-http_dav_module \	--with-http_flv_module \	--with-http_mp4_module \	--with-http_gunzip_module \	--with-http_gzip_static_module \	--with-http_random_index_module \	--with-http_secure_link_module \	--with-http_stub_status_module \	--add-module=/app/lua-nginx-module-0.10.9rc3 \	--add-module=/app/redis2-nginx-module-0.14makemake install

4、下载nginx中lua使用redis需要的依赖包,并将redis.lua到nginx安装目录

wget https://github.com/openresty/lua-resty-redis/archive/v0.26.tar.gztar xf v0.26.tar.gz cp lua-resty-redis-0.26/lib/resty/redis.lua    /app/nginx

5、在nginx.conf文件的http段引入redis.lua包,加入代码

lua_package_path "/app/nginx/redis.lua;;";

6、编写控制访问lua脚本access.lua放到nginx安装目录的conf目录下

ip_bind_time = 300  --封禁IP时间  ip_time_out = 60    --指定ip访问频率时间段  connect_count = 100 --指定ip访问频率计数最大值  --连接redis  local redis = require "resty.redis"  local cache = redis.new()  local ok , err = cache.connect(cache,"127.0.0.1","6379")  cache:set_timeout(60000)  --如果连接失败,跳转到脚本结尾  if not ok then    goto A  end  --查询ip是否在封禁段内,若在则返回403错误代码  --因封禁时间会大于ip记录时间,故此处不对ip时间key和计数key做处理  is_bind , err = cache:get("bind_"..ngx.var.remote_addr)  if is_bind == "1" then    ngx.exit(403)    goto A  end  start_time , err = cache:get("time_"..ngx.var.remote_addr)  ip_count , err = cache:get("count_"..ngx.var.remote_addr)  --如果ip记录时间大于指定时间间隔或者记录时间或者不存在ip时间key则重置时间key和计数key  --如果ip时间key小于时间间隔,则ip计数+1,且如果ip计数大于ip频率计数,则设置ip的封禁key为1  --同时设置封禁key的过期时间为封禁ip的时间  if start_time == ngx.null or os.time() - start_time > ip_time_out then    res , err = cache:set("time_"..ngx.var.remote_addr , os.time())    res , err = cache:set("count_"..ngx.var.remote_addr , 1)  else    ip_count = ip_count + 1    res , err = cache:incr("count_"..ngx.var.remote_addr)    if ip_count >= connect_count then      res , err = cache:set("bind_"..ngx.var.remote_addr,1)      res , err = cache:expire("bind_",ip_bind_time)    end  end  --结尾标记  ::A::  local ok, err = cache:close()

7、在nginx.conf中需要控制访问的站点location段中加入访问控制代码:

access_by_lua_file /app/nginx/conf/access.lua;

现在可以启动redis和nginx进行测试了。

 

8、方式二 基于Redis的实时IP封禁

某些情况下,需要阻止流氓爬虫的抓取,这可以通过专门的封禁设备去做,但是通过Lua,也可以实现简单版本的封禁。Nginx进程每隔10秒从Redis获取一次最新的禁止IP名单。需要注意的是,如果架构中使用了Haproxy这样类似的负载均衡服务器时, 需要把$remote_addr设置为正确的远端IP地址。这个方法还可以用于HTTP User-Agent字段的检查,要求满足指定条件。

lua_shared_dict banned_ips 1m;location / {  access_by_lua '    local banned_ips = ngx.shared.banned_ips;    local updated_at = banned_ips:get("updated_at");    -- only update banned_ips from Redis once every ten seconds:    if updated_at == nil or updated_at < ( ngx.now() - 10 ) then      local redis = require "resty.redis";      local red = redis:new();      red:set_timeout(200);      local ok, err = red:connect("your-redis-hostname", 6379);      if not ok then        ngx.log(ngx.WARN, "Redis connection error retrieving banned_ips: " .. err);      else        local updated_banned_ips, err = red:smembers("banned_ips");        if err then          ngx.log(ngx.WARN, "Redis read error retrieving banned_ips: " .. err);        else          -- replace the locally stored banned_ips with the updated values:          banned_ips:flush_all();          for index, banned_ip in ipairs(updated_banned_ips) do            banned_ips:set(banned_ip, true);          end          banned_ips:set("updated_at", ngx.now());        end      end    end    if banned_ips:get(ngx.var.remote_addr) then      ngx.log(ngx.WARN, "Banned IP detected and refused access: " .. ngx.var.remote_addr);      return ngx.exit(ngx.HTTP_FORBIDDEN);    end  ';}

现在就可以阻止特定IP的访问:

$redis.sadd("banned_ips", "200.1.35.4")

转载于:https://my.oschina.net/mywiki/blog/899189

你可能感兴趣的文章
02-CSS基础与进阶-day1-录像293
查看>>
Web Services 应用开发学习笔记(三):XML模式定义
查看>>
Hadoop之hive 其他
查看>>
基础题(二)
查看>>
BGD 通信15-1 150206102 王嘉良 DDS信号发生器
查看>>
4-26 pts dts
查看>>
顺序查找JAVA实现 设置哨兵
查看>>
第十一章 继承与派生 学习笔记
查看>>
SQL 模糊查询 模糊查找 字符串匹配
查看>>
javascript-demo
查看>>
创新是一项可以学习的技能
查看>>
SpringSecurity学习之基于数据库的用户认证
查看>>
HttpPostedFile 和 HttpPostedFileBase 你真的了解嘛?
查看>>
zepto和jquery的区别
查看>>
【待续】Visual Studio 插件推荐
查看>>
CentOS 7 使用 Realtek 8188eu 上网 (解决 Required key not available)
查看>>
Python集合
查看>>
减治法-插入排序和图的两种查找方式
查看>>
Jquery焦点图实例
查看>>
【语法】【内存管理】retain和release
查看>>