nginx+lua控制nginx异常访问
nginx+lua 防护,对异常请求进行计数并屏蔽
用 nginx+lua 对异常频率较大的IP请求进行限制;
原理: 将每次异常请求的IP记录下来,这个IP每次异常则计数+1; 如果3分钟内多于3次异常就屏蔽此IP 3分钟(从第1次开始计的时); 如果3分钟内异常多于9次,则延长至10分钟;
nginx.conf
http {
lua_shared_dict acl_ip_tables 1m; # 开一个共享内存区域用来存储计数
server {
# 每个请求都会执行的逻辑
access_by_lua_file /opt/app/nginx/conf/acl_req.lua;
# 每个响应都会执行的逻辑
header_filter_by_lua_file /opt/app/nginx/conf/acl_res.lua;
location {}
}
}请求时逻辑 acl_req.lua
-- 如果这个IP已经存在异常计数,且大于3次就拒绝访问
local dict = ngx.shared.acl_ip_tables
local ip = ngx.var.remote_addr -- 获取请求使用的ip地址
num = dict:get(ip)
if ( num ~= nil ) and ( num > 2 ) then
ngx.log(ngx.ERR, "acl_num >2: ", num, ' DROP 403 ')
return ngx.exit(403)
end响应时逻辑 acl_res.lua
-- 本次请求的响应码,如果不是 200/304 或特定响应码,视为异常
local status_code = ngx.var.status
local res_status = 0
if ( status_code == '200' ) or ( status_code == '304' ) then
res_status = 1
elseif ( status_code == '999' ) then
res_status = 1
end
if ( res_status == 0 ) then
local ip = ngx.var.remote_addr -- 获取请求使用的ip地址
local dict = ngx.shared.acl_ip_tables
num = dict:get(ip)
if num == nil then
-- 第一次异常访问
ngx.log(ngx.ERR, "num: ",num, " status_code:", status_code," remote add: ", ngx.var.remote_addr)
dict:set(ip, 1, 180) -- 初始化计数
else
-- 存在异常时仍继续访问 +1
num = dict:incr(ip, 1)
ngx.log(ngx.ERR, "acl_num+1=", num)
-- 3分钟内异常大于9次,延长至10分钟
if ( num == 9 ) then
dict:set(ip, 9, 600)
ngx.log(ngx.ERR, "num: ",num, " set 10min: ", ip)
end
end
end最后更新于