数据人与超自然意识 发表于 2024-12-27 18:39:31

nginx|openresty配置lua脚本自动封ip

本文不举行介绍怎么安装lua环境、openresty预安装有lua脚本运行环境、nginx必要自行编译;
本文会把黑名单ip界说在文件中,步伐运行时定时覆盖内容到内存中,提拔运行速度
1、nginx.conf配置加载lua

#WAF
lua_shared_dict blist 50m;
init_worker_by_lua_file "/usr/local/openresty/nginx/conf/lua/init.lua";
access_by_lua_file "/usr/local/openresty/nginx/conf/lua/blacklist.lua";lua_shared_dict blist 作用:创建一个共享内存字典,定名为 blist(存储黑名单ip信息)
init_worker_by_lua_file 作用:初始化全局变量或其他 Lua 模块
access_by_lua_file 作用:在 access 阶段(哀求访问控制阶段)运行指定的 Lua 脚本
获取访问进来的ip地点(兼容ipv4和ipv6)

map $http_x_forwarded_for$realip
{
""    $remote_addr;
##兼容ipv4及ipv6,兼容特殊格式ipv6
   "~*(?P<firstAddr>({0,4}:){1,7}{1,4}|({1,3}\.){3}{1,3})" $firstAddr;
}把获取到的ip界说变量为$realip,后续脚本会调用
2、配置init.lua和blacklist.lua脚本

init.lua

    local function load_blacklist_to_shared_memory()
      local file, err = io.open("/usr/local/openresty/nginx/conf/waf/rule-config/iplist.txt", "r")
      if not file then
            ngx.log(ngx.ERR, "failed to open blacklist file: ", err)
            return
      end

      -- 检查文件是否为空
      local is_empty = true
      for _ in file:lines() do
            is_empty = false
            break
      end

      if is_empty then
            ngx.log(ngx.ERR, "blacklist file is empty")
            file:close()
            return
      end

      -- 文件非空时重新打开文件并加载数据
      file:seek("set", 0)
      local dict = ngx.shared.blist
      dict:flush_all()-- 清空共享内存,重新加载
      for line in file:lines() do
            dict:set(line, true)
      end

      file:close()
    end

    local function refresh_blacklist(premature)
      if premature then
            return
      end

      load_blacklist_to_shared_memory()
      ngx.log(ngx.INFO, "Blacklist reloaded successfully.")

      -- 重新设置定时器
      local ok, err = ngx.timer.at(5, refresh_blacklist)
      if not ok then
            ngx.log(ngx.ERR, "Failed to create timer: ", err)
      end
    end

    -- 初始化时加载黑名单
    load_blacklist_to_shared_memory()

    -- 设置定时器
    local ok, err = ngx.timer.at(5, refresh_blacklist)
    if not ok then
      ngx.log(ngx.ERR, "Failed to create timer: ", err)
    end定时器是5秒钟重新到黑名单文件读取ip写到内存中
blacklist.lua

    -- 加载黑名单数据到共享内存
    local function load_blacklist_to_shared_memory()
      local file, err = io.open("/usr/local/openresty/nginx/conf/waf/rule-config/iplist.txt", "r")
      if not file then
            ngx.log(ngx.ERR, "failed to open blacklist file: ", err)
            return false
      end

      -- 检查文件是否为空
      local is_empty = true
      for _ in file:lines() do
            is_empty = false
            break
      end

      if is_empty then
            ngx.log(ngx.ERR, "blacklist file is empty")
            file:close()
            return false
      end

      -- 文件非空时重新打开文件并加载数据
      file:seek("set", 0)
      local dict = ngx.shared.blist
      dict:flush_all()-- 清空共享内存,重新加载
      for line in file:lines() do
            dict:set(line, true)
      end

      file:close()
      return true
    end

    -- 检查 IP 是否在黑名单中
    local function check_blacklist(ip)
      local dict = ngx.shared.blist
      return dict:get(ip)
    end

    -- 获取客户端 IP
    local function get_client_ip()
      return ngx.var.realip or "unknown"
    end

    -- 主逻辑
    -- local blacklist_loaded = load_blacklist_to_shared_memory()
    local client_ip = get_client_ip()

    ifcheck_blacklist(client_ip) then
      ngx.log(ngx.ERR, "IP " .. client_ip .. " is blacklisted")
      ngx.exit(ngx.HTTP_FORBIDDEN)
    end

    -- 根据请求路径分发处理逻辑
    local uri = ngx.var.uri
    if uri == "/reload-blacklist" then
      -- 添加 IP 条件判断
      local allowed_ip_prefix = "172.31"
      local client_ip_prefix = string.sub(client_ip, 1, #allowed_ip_prefix)
      if client_ip_prefix ~= allowed_ip_prefix then
            ngx.log(ngx.ERR, "Access forbidden for IP: " .. client_ip)
            ngx.exit(ngx.HTTP_FORBIDDEN)
      end

      -- 重新加载黑名单到共享内存
      local reloaded = load_blacklist_to_shared_memory()
      if reloaded then
            ngx.say("Blacklist reloaded successfully.")
      else
            ngx.say("Blacklist file not found or is empty. No changes made.")
      end
    end可以自界说访问reload-blacklist路径的url就举行革新黑名单ip,allowed_ip_prefix对访问进来的ip举行白名单限制
最后界说iplist.txt就可以了,每个ip为一行,init.lua和blacklist.lua中用io.open界说iplist.txt的路径

iplist.txt

1.2.3.4
1a:d8:eb:42:91:f8举行reload步伐就可以利用了,在这个自动化的基础上,配合日志体系,根据自界说规则就可以自动化的屏蔽异常ip;
异常ip输出到error日志中
https://img2024.cnblogs.com/blog/3574597/202412/3574597-20241227095609571-748446676.png
博主利用过loki日志体系和elk日志体系,都可以根据一定时间内ip次数到达多少就自动屏蔽ip;运维以后不再半夜起床排查异常ip;
后续更新这篇博客,到场跳转链接,敬请等待;

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
页: [1]
查看完整版本: nginx|openresty配置lua脚本自动封ip