🚀 OpenResty集成Turnstile验证终极方案
针对OpenResty高性能特性,推荐在反向代理层直接完成验证,实现 零后端改造 的安全防护。以下是优化后的生产级配置:
一、环境准备
- 安装依赖
# 安装lua-resty-http用于发起验证请求
opm install ledgetech/lua-resty-http
- 创建验证缓存
# 在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;
}
}
三、动态规则增强
- 根据流量自动启用
# 在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
}
- 实时监控仪表盘
# 安装Prometheus监控模块
opm install zmartzone/lua-resty-prometheus
四、性能优化策略
- 连接池配置
http {
lua_socket_pool_size 100; # 控制到Cloudflare的连接池大小
lua_socket_keepalive_timeout 60s;
}
- 验证失败惩罚
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
五、调试与日志分析
- 结构化日志输出
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;
- 实时跟踪命令
# 查看实时验证状态
tail -f /var/log/nginx/turnstile.log | jq -c '.'
🔧 部署验证
- 测试验证流程:
curl -X POST https://yourdomain.com/api/comments \
-H "X-Turnstile-Token: TEST_TOKEN" \
-d "content=HelloWorld"
- 压力测试(使用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片段。