lua+nginx实现黑名单禁止访问

Lua 是可以很好地和Nginx配合使用的,带直接使用 Nginx 是需要安装扩展的,这里我们力求简单,省去安装,使用OpenResty(基于 Nginx 与 Lua 的高性能 Web 平台),地址:OpenResty地址

说明:我是在windows7电脑上测试使用

主要配置代码如下:

lua_shared_dict ip_blacklist 1m;

server {
    listen       80;
    server_name  localhost;

    root   E:/www/web/test;

    access_log  logs/host.access.log ;
    error_log  logs/host.error.log;

    location / {
        access_by_lua_file ../lua/black.lua;
        index  index.html index.htm;
    }
    
    error_page   500 502 503 504  /50x.html;
    location = /50x.html {
        root   html;
    }

    
    location ~ \.php$ {
        access_by_lua_file "D:\openresty-1.15.8.1-win64/lua/black.lua";
        fastcgi_pass   127.0.0.1:9000;
        fastcgi_index  index.php;
        fastcgi_param  SCRIPT_FILENAME  $document_root$fastcgi_script_name;
        include        fastcgi_params;
    }
}

简要说明:

lua_shared_dict 分配给ip_blacklist的内存,可根据业务量自行决定
access_by_lua_file 指定 lua 文件

black.lua 代码如下[说明较多,直接放注释了]:

local Redis_host    = "127.0.0.1" -- Redis的IP地址
local Redis_port    = "6379"

-- 连接超时时间,单位ms,不建议设置太高
local Redis_connection_timeout = 1000

local Redis_key  = "ip_blacklist"

-- 缓存时间,单位 s
local cache_ttl  = 100

-- 以上是配置

local ip                = ngx.var.remote_addr
local ip_blacklist      = ngx.shared.ip_blacklist
local last_update_time  = ip_blacklist:get("last_update_time");

-- 当缓存时间到期更新blacklist
if last_update_time == nil or last_update_time < ( ngx.now() - cache_ttl ) then

  local Redis = require "resty.Redis";
  local red = Redis:new();

  red:set_timeout(Redis_connect_timeout);

  local ok, err = red:connect(Redis_host, Redis_port);

  if not ok then
    ngx.say("Redis connect failed: ", err)
    ngx.log(ngx.DEBUG, "Redis connection error while retrieving ip_blacklist: " .. err);
    return ngx.exit(ngx.HTTP_INTERNAL_SERVER_ERROR)
  else
    -- local res, err = red:auth("foobared") -- 配置Redis的密码,我测试未设置密码,代码注释

    --if not res then
        --ngx.say("Redis auth is error: ", err)
        --return
    --end
    red:select(0)
    local new_ip_blacklist, err = red:smembers(Redis_key);
    if err then
      ngx.log(ngx.DEBUG, "Redis read error while retrieving ip_blacklist: " .. err);
    else
      -- 情况本地存储
      ip_blacklist:flush_all();
      for index, banned_ip in ipairs(new_ip_blacklist) do
        ip_blacklist:set(banned_ip, true);
      end

      -- 更新时间
      ip_blacklist:set("last_update_time", ngx.now());
    end
  end
end


if ip_blacklist:get(ip) then
  --ngx.say(ip)
  ngx.log(ngx.DEBUG, "Banned IP detected and refused access: " .. ip);
  return ngx.exit(ngx.HTTP_FORBIDDEN);
end

这样就完成了一个黑名单功能完成。

当然了,这只是个基础版本,你可以让这个禁止访问功能更强大,比如增加可疑ip写入,比如增加ip限流等等。


lua+nginx实现黑名单禁止访问
https://blog.puresai.com/2019/07/16/192/
作者
puresai
许可协议