LUA脚本

提示

本项目主要的防御逻辑和顺序都已经封装到lua脚本中了。

基本结构

function should_block()
    local req = request
    local client_ip = req.client_ip or ""
    local site_id = req.site_id or 0

    if client_ip == "" then
        return 0
    end

    if is_ip_blacklisted(client_ip, site_id) then
        log("Blocked by IP blacklist: " .. client_ip .. " (site_id=" .. tostring(site_id) .. ")")
        return 1
    end
    return 0
end

提示

如上例子所示,脚本必须是一个function,返回值是0、1、-1三个值

返回值说明
0不阻止请求,继续后续脚本
1阻止请求
-1不阻止请求,并跳过所有后续脚本

全局对象

为了方便定义防御能力,我们给lua脚本注入了一些全局对象

request 请求上下文

这个是请求的上下文,它包含以下属性

属性默认值说明
method请求的方法
uri请求的uri
headers请求的headers
body请求的body,注意这里的body如果太大,会被截断保障性能
client_ip请求ip,这个ip地址来源是:1、如果配置了trusted_source,并且请求来自于授信源,那就从X-Real-IP -> X-Forwarded-For(取第一个) -> peer_ip;2、如果没有配置trusted_source,就取请求来源ip(如果有上位nginx,就会取到上位nginx)
timestamp请求的时间戳
site_id请求指向的站点id

log 日志方法

为了方便调试,脚本也可以直接输出日志,调用方法如下

log("Blocked by IP blacklist: " .. client_ip .. " (site_id=" .. tostring(site_id) .. ")")

内置防御方法

脚本还内置了一些常用的防御方法:

is_verified_crawler 爬虫校验

function should_block()
    local req = request
    local user_agent = req.headers["user-agent"] or req.headers["User-Agent"] or ""
    if user_agent == "" then return 1 end

    local client_ip = req.client_ip or ""
    local exempts = {"MicroMessenger", "DingTalk"}
    local value = is_verified_crawler(client_ip, user_agent, nil, 0)  -- 不拉黑,直接拦截
    -- log("is_verified_crawler returned: " .. tostring(value))
    return value
end
is_verified_crawler方法参数
参数名称类型默认值说明
client_ip字符串请求的ip地址
user_agent字符串请求的UA
exemptsUA字符串列表豁免屏蔽,如果识别到冒充爬虫,只拒绝请求,不拉黑ip
block_duration数字检测到冒充爬虫的,拉黑分钟数

is_ip_blacklisted 黑名单校验

function should_block()
    local req = request
    local client_ip = req.client_ip or ""
    local site_id = req.site_id or 0

    if client_ip == "" then
        return 0
    end

    if is_ip_blacklisted(client_ip, site_id) then
        log("Blocked by IP blacklist: " .. client_ip .. " (site_id=" .. tostring(site_id) .. ")")
        return 1
    end
    return 0
end

is_ip_whitelisted 白名单校验

function should_block()
    local req = request
    local client_ip = req.client_ip or ""
    local site_id = req.site_id or 0

    if client_ip == "" then
        return 0
    end

    if is_ip_whitelisted(client_ip, site_id) then
        log("Allowed by IP whitelist: " .. client_ip .. " (site_id=" .. tostring(site_id) .. ")")
        return -1  -- 跳过所有后续脚本
    end
    return 0
end

is_rate_limited 请求频率

function should_block()
    local req = request
    local ip = req.client_ip or "unknown"
    local site = req.site_id or 0

    -- 若被 CC 限制,则立即阻断
    if is_rate_limited(ip, site) then
        log("CC rate limited: " .. ip .. " @site " .. tostring(site))
        return 1
    end

    return 0
end
最近更新::
Contributors: Pcloth