http {
# Lua脚本配置(需要安装lua-resty-template)
lua_package_path "/usr/local/openresty/lualib/?.lua;;";
# 挑战验证状态存储
lua_shared_dict challenge_cache 10m;
server {
listen 80;
server_name secure.example.com;
location /challenge {
content_by_lua_block {
local template = require "resty.template"
-- 生成随机挑战
local challenge = ngx.var.request_time .. ngx.var.remote_addr
local hash = ngx.encode_base64(ngx.hmac_sha1("secret_key", challenge))
-- 挑战页面HTML
local html = [[
<!DOCTYPE html>
<html>
<head>
<title>Verification Required</title>
<meta name="robots" content="noindex, nofollow">
</head>
<body>
<h1>Verifying your browser...</h1>
<script>
// 简单的计算挑战
var result = Math.pow(2, 3) + 5;
var challenge = "{{challenge}}";
// 自动提交
setTimeout(function() {
var form = document.createElement('form');
form.method = 'POST';
form.action = '/verify';
var challengeInput = document.createElement('input');
challengeInput.type = 'hidden';
challengeInput.name = 'challenge';
challengeInput.value = challenge;
var answerInput = document.createElement('input');
answerInput.type = 'hidden';
answerInput.name = 'answer';
answerInput.value = result;
form.appendChild(challengeInput);
form.appendChild(answerInput);
document.body.appendChild(form);
form.submit();
}, 2000);
</script>
</body>
</html>
]]
ngx.say(template.compile(html)({challenge = hash}))
}
}
location /verify {
content_by_lua_block {
if ngx.var.request_method ~= "POST" then
ngx.status = 405
ngx.say("Method not allowed")
return
end
-- 验证挑战答案
ngx.req.read_body()
local args = ngx.req.get_post_args()
if args.answer == "13" then -- 2^3 + 5 = 13
-- 设置验证通过标记
local cache = ngx.shared.challenge_cache
cache:set(ngx.var.remote_addr, "verified", 3600) -- 1小时有效
ngx.redirect("/")
else
ngx.status = 403
ngx.say("Verification failed")
end
}
}
location / {
access_by_lua_block {
local cache = ngx.shared.challenge_cache
local verified = cache:get(ngx.var.remote_addr)
if not verified then
ngx.redirect("/challenge")
end
}
proxy_pass http://backend;
}
}
}