使用OpenResty实现简易CC防护

January 2, 2024 默认分类

环境

  • CentOS 7
  • OpenResty 1.19.9.1
    • lua-resty-ipmatcher
    • lua-var-nginx-module

功能

  • 支持IP白名单
  • 支持IP黑名单
  • 计数key为:ip + “.” + md5(host + request_uri + useragent),可自定义
  • 60秒内请求超过60次就封禁3600秒

配置

对应nginx配置

lua_shared_dict cc_counter 100m;

server {
    listen 80;
    server_name demo.test.com;

    location / {
        access_by_lua_file lua/anticc.lua;
    }
}

anticc.lua

local require = require
local ngx = ngx
local ipmatcher = require("resty.ipmatcher")
local ngxvar = require("resty.ngxvar")
local ngx_md5 = ngx.md5

-- config
local CCcount = 60
local CCseconds = 60
local blockseconds = 3600

local allowips = ipmatcher.new({
    "127.0.0.1",
})

local denyips = ipmatcher.new({
    "192.168.0.0/24",
})

local cc_counter = ngx.shared.cc_counter
local req = ngxvar.request()
local IP = ngxvar.fetch("remote_addr")
local request_uri = ngx.var.request_uri
local url = ngxvar.fetch("host") .. request_uri
local ua = ngx.var.http_user_agent or "unknown"

local function anticc_check()
    local count_Key = IP .. "." .. ngx_md5(url .. ua)
    local countReq = cc_counter:get(count_Key)
    if countReq then
        if tonumber(countReq) >= CCcount then
            local block_Key = "block." .. count_Key
            local blockReq = cc_counter:get(block_Key)
            if blockReq then
                ngx.log(ngx.ERR, "cc_blocked: ", IP)
                ngx.exit(444)
            else
                cc_counter:set(block_Key, 1, blockseconds)
                cc_counter:set(count_Key, CCcount, blockseconds)
                ngx.log(ngx.ERR, "cc_blocked: ", IP)
                ngx.exit(444)
            end
        else
            cc_counter:incr(count_Key, 1)
            return
        end
    else
        cc_counter:set(count_Key, 0, CCseconds)
        cc_counter:incr(count_Key, 1)
        return
    end
end

if allowips:match(IP) then
    return
elseif denyips:match(IP) then
    ngx.log(ngx.ERR, "denyip: ", IP)
    return ngx.exit(444)
else
    anticc_check()
end

添加新评论