5

Nginx+Lua实现动态黑名单

 2 years ago
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.
neoserver,ios ssh client

通过nginx+lua+redis可以实现nginx动态从redis读取需要拒绝的ip黑名单列表,并拒绝黑名单ip的访问请求。

其中redis中的ip黑名单列表既可以人工后台手动添加,也可以用类似logstash+elasticsearch的组合,实现logstash实时读取nginx的访问日志access.log,elasticsearch储存并聚合访问日志中的访问记录,再由一个分析程序定时统计分析访问记录后判断出要加入黑名单的ip,然后将ip储存到redis中的ip黑名单列表。

image

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"

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK