5
Nginx+Lua实现动态黑名单
source link: https://wakzz.cn/2018/12/23/nginx/Nginx+Lua%E5%AE%9E%E7%8E%B0%E5%8A%A8%E6%80%81%E9%BB%91%E5%90%8D%E5%8D%95/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
通过nginx+lua+redis可以实现nginx动态从redis读取需要拒绝的ip黑名单列表,并拒绝黑名单ip的访问请求。
其中redis中的ip黑名单列表既可以人工后台手动添加,也可以用类似logstash+elasticsearch的组合,实现logstash实时读取nginx的访问日志access.log
,elasticsearch储存并聚合访问日志中的访问记录,再由一个分析程序定时统计分析访问记录后判断出要加入黑名单的ip,然后将ip储存到redis中的ip黑名单列表。
nginx配置
http {
...
lua_shared_dict forbidden_list 5m;
location /lua {
# lua_code_cache off;
access_by_lua_file conf/lua/forbidden_list.lua;
default_type 'text/html';
content_by_lua 'ngx.say("hello world")';
}
}
lua配置
local redis = require("resty.redis")
local ngx_log = ngx.log
local ngx_ERR = ngx.ERR
local ngx_INFO = ngx.INFO
local ngx_exit = ngx.exit
local ngx_var = ngx.var
-- 黑名单缓存60秒
local cache_idle = 60
local forbidden_list = ngx.shared.forbidden_list
local function close_redis(red)
if not red then
return
end
-- 释放连接(连接池实现)
local pool_max_idle_time = 10000 -- 毫秒
local pool_size = 100 -- 连接池大小
local ok, err = red:set_keepalive(pool_max_idle_time, pool_size)
if not ok then
ngx_log(ngx_ERR, "set redis keepalive error : ", err)
end
end
-- 从redis获取ip黑名单列表
local function get_forbidden_list()
local red = redis:new()
red:set_timeout(1000)
local ip = "127.0.0.1"
local port = 6379
local password = "password"
local ok, err = red:connect(ip, port)
if not ok then
ngx_log(ngx_ERR, "connect to redis error : ", err)
close_redis(red)
return
end
local res, err = red:auth(password)
if not res then
ngx_log(ngx_ERR, "failed to authenticate: ", err)
close_redis(red)
return
end
local resp, err = red:smembers("forbidden_list")
if not resp then
ngx_log(ngx_ERR, "get redis connect error : ", err)
close_redis(red)
return
end
-- 得到的数据为空处理
if resp == ngx.null then
resp = nil
end
close_redis(red)
return resp
end
-- 刷新黑名单
local function reflush_forbidden_list()
local current_time = ngx.now()
local last_update_time = forbidden_list:get("last_update_time");
if last_update_time == nil or last_update_time < (current_time - cache_idle) then
local new_forbidden_list = get_forbidden_list();
if not new_forbidden_list then
return
end
forbidden_list:flush_all()
for i, forbidden_ip in ipairs(new_forbidden_list) do
forbidden_list:set(forbidden_ip, true);
end
forbidden_list:set("last_update_time", current_time);
end
end
reflush_forbidden_list()
local ip = ngx_var.remote_addr
if forbidden_list:get(ip) then
ngx_log(ngx_INFO, "forbidden ip refused access : ", ip)
return ngx_exit(ngx.HTTP_FORBIDDEN)
end
redis修改黑名单
添加黑名单
SADD forbidden_list "127.0.0.1"
移除黑名单
SREM forbidden_list "127.0.0.1"
[root@localhost ~]# curl http://localhost/lua
<html>
<head><title>403 Forbidden</title></head>
<body bgcolor="white">
<center><h1>403 Forbidden</h1></center>
<hr><center>openresty/1.13.6.1</center>
</body>
</html>
[root@localhost ~]# curl http://localhost/lua
hello world
2018/12/23 13:10:47 [info] 4416#0: *56 [lua] forbidden_list.lua:86: forbidden ip refused access : 127.0.0.1, client: 127.0.0.1, server: localhost, request: "GET /lua HTTP/1.1", host: "localhost"
Recommend
About Joyk
Aggregate valuable and interesting links.
Joyk means Joy of geeK