🚀 OpenResty集成Turnstile验证终极方案
针对OpenResty高性能特性,推荐在反向代理层直接完成验证,实现 零后端改造 的安全防护。以下是优化后的生产级配置:


一、环境准备

  1. 安装依赖
# 安装lua-resty-http用于发起验证请求
opm install ledgetech/lua-resty-http
  1. 创建验证缓存
# 在nginx.conf的http块添加
lua_shared_dict turnstile_cache 10m;  # 缓存已验证token

二、核心配置(server块)

server {
    listen 443 ssl;
    server_name yourdomain.com;

    # 拦截需要验证的路径
    location ~ ^/(api/comments|auth/login) {
        access_by_lua_block {
            local http = require "resty.http"
            local cjson = require "cjson"

            -- 从POST表单或Header提取token
            local args = ngx.req.get_post_args()
            local token = args.cf_turnstile_token or ngx.var.http_x_turnstile_token
            
            if not token then
                ngx.log(ngx.ERR, "Turnstile token missing")
                return ngx.exit(ngx.HTTP_FORBIDDEN)
            end

            -- 检查缓存
            local cache = ngx.shared.turnstile_cache
            if cache:get(token) then
                ngx.log(ngx.INFO, "Cached token verified: ", token)
                return 
            end

            -- 向Cloudflare发起验证
            local httpc = http.new()
            local res, err = httpc:request_uri("https://challenges.cloudflare.com/turnstile/v0/siteverify", {
                method = "POST",
                body = "secret=YOUR_SECRET_KEY&response="..token,
                headers = {
                    ["Content-Type"] = "application/x-www-form-urlencoded",
                },
                ssl_verify = true,
                keepalive_timeout = 60
            })

            if not res then
                ngx.log(ngx.ERR, "Turnstile API error: ", err)
                return ngx.exit(ngx.HTTP_SERVICE_UNAVAILABLE)
            end

            local data = cjson.decode(res.body)
            if data.success and data.action == ngx.var.request_uri then
                cache:set(token, true, 300)  -- 缓存5分钟
            else
                ngx.log(ngx.WARN, "Invalid token: ", token, " Errors: ", table.concat(data["error-codes"], ","))
                ngx.header.Content-Type = "application/json"
                ngx.say('{"error":"human_verification_failed"}')
                return ngx.exit(ngx.HTTP_FORBIDDEN)
            end
        }

        # 转发到Halo后端
        proxy_pass http://halo_backend;
        proxy_set_header X-Real-IP $remote_addr;
    }
}

三、动态规则增强

  1. 根据流量自动启用
# 在http块添加全局初始化代码
init_by_lua_block {
    -- 当QPS超过100时自动开启验证
    local threshold = 100  
    local last_activate = 0
    
    _G.dynamic_turnstile = function()
        local current_qps = ngx.shared.status:get("qps") or 0
        if current_qps > threshold and os.time() - last_activate > 600 then
            ngx.log(ngx.ALERT, "Activating Turnstile due to high traffic")
            last_activate = os.time()
        end
        return current_qps > threshold
    end
}

# 在server块中使用
access_by_lua_block {
    if _G.dynamic_turnstile() then
        -- 执行Turnstile验证
    else
        -- 放行请求
    end
}
  1. 实时监控仪表盘
# 安装Prometheus监控模块
opm install zmartzone/lua-resty-prometheus

四、性能优化策略

  1. 连接池配置
http {
    lua_socket_pool_size 100;  # 控制到Cloudflare的连接池大小
    lua_socket_keepalive_timeout 60s;
}
  1. 验证失败惩罚
local limit_req = require "resty.limit.req"
local limiter = limit_req.new("turnstile_fail", 5, 10)  -- 允许5R/S,突发10

if not data.success then
    local delay, err = limiter:incoming(ngx.var.binary_remote_addr, true)
    if not delay then
        ngx.exit(ngx.HTTP_SERVICE_UNAVAILABLE)
    end
end

五、调试与日志分析

  1. 结构化日志输出
log_format turnstile_log escape=json
    '{'
    '"time":"$time_iso8601",'
    '"remote_addr":"$remote_addr",'
    '"token":"$http_x_turnstile_token",'
    '"action":"$request_uri",'
    '"response_time":"$request_time",'
    '"status":"$status"'
    '}';

access_log /var/log/nginx/turnstile.log turnstile_log;
  1. 实时跟踪命令
# 查看实时验证状态
tail -f /var/log/nginx/turnstile.log | jq -c '.'

🔧 部署验证

  1. 测试验证流程:
curl -X POST https://yourdomain.com/api/comments \
     -H "X-Turnstile-Token: TEST_TOKEN" \
     -d "content=HelloWorld"
  1. 压力测试(使用wrk):
wrk -t12 -c400 -d30s --script=./test_verify.lua http://yourdomain.com/api/comments

📌 高级技巧

  • 通过Edge Certificates添加专属客户端证书,豁免内部请求验证
  • 利用lua-resty-iputils实现可信IP段白名单
  • 在验证页面添加challenge-timeout=30控制超时时间

需要定制化配置或性能调优方案?请提供当前OpenResty版本及nginx.conf片段。