Commit c1d44387 authored by bunkerity's avatar bunkerity
Browse files

basic antibot feature through recaptcha v3

parent 135126e3
......@@ -68,6 +68,10 @@ cd lua-gd
make -j $NTASK
make INSTALL_PATH=/usr/local/lib/lua/5.1 install
cd /tmp
git clone https://github.com/ledgetech/lua-resty-http.git
cd lua-resty-http
make install
cd /tmp
git clone https://github.com/openresty/lua-nginx-module.git
export LUAJIT_LIB=/usr/local/lib
export LUAJIT_INC=/usr/local/include/luajit-2.1
......
location = %ANTIBOT_URI% {
default_type 'text/html';
if ($request_method = GET) {
content_by_lua_block {
local cookie = require "cookie"
local recaptcha = require "recaptcha"
if not cookie.is_set("uri") then
return ngx.exit(ngx.HTTP_FORBIDDEN)
end
local code = recaptcha.get_code("%ANTIBOT_URI%", "%ANTIBOT_RECAPTCHA_SITEKEY%")
ngx.say(code)
}
}
if ($request_method = POST) {
access_by_lua_block {
local cookie = require "cookie"
local recaptcha = require "recaptcha"
if not cookie.is_set("uri") then
return ngx.exit(ngx.HTTP_FORBIDDEN)
end
ngx.req.read_body()
local args, err = ngx.req.get_post_args(1)
if err == "truncated" or not args or not args["token"] then
return ngx.exit(ngx.HTTP_FORBIDDEN)
end
local token = args["token"]
local check = recaptcha.check(token, "%ANTIBOT_RECAPTCHA_SECRET%")
if check < %ANTIBOT_RECAPTCHA_SCORE% then
ngx.log(ngx.WARN, "client has recaptcha score of " .. tostring(check))
return ngx.exit(ngx.HTTP_FORBIDDEN)
end
cookie.set({recaptcha = "ok"})
return ngx.redirect(cookie.get("uri"))
}
}
}
......@@ -8,6 +8,7 @@ local use_dnsbl = %USE_DNSBL%
local use_antibot_cookie = %USE_ANTIBOT_COOKIE%
local use_antibot_javascript = %USE_ANTIBOT_JAVASCRIPT%
local use_antibot_captcha = %USE_ANTIBOT_CAPTCHA%
local use_antibot_recaptcha = %USE_ANTIBOT_RECAPTCHA%
-- include LUA code
local whitelist = require "whitelist"
......@@ -16,6 +17,7 @@ local dnsbl = require "dnsbl"
local cookie = require "cookie"
local javascript = require "javascript"
local captcha = require "captcha"
local recaptcha = require "recaptcha"
-- antibot
local antibot_uri = "%ANTIBOT_URI%"
......@@ -111,6 +113,16 @@ if use_antibot_captcha then
end
end
-- recaptcha check
if use_antibot_recaptcha then
if not cookie.is_set("recaptcha") then
if ngx.var.request_uri ~= antibot_uri and ngx.var.request_uri ~= "/favicon.ico" then
cookie.set({uri = ngx.var.request_uri})
return ngx.redirect(antibot_uri)
end
end
end
ngx.exit(ngx.OK)
}
......@@ -118,3 +130,5 @@ ngx.exit(ngx.OK)
%INCLUDE_ANTIBOT_JAVASCRIPT%
%INCLUDE_ANTIBOT_CAPTCHA%
%INCLUDE_ANTIBOT_RECAPTCHA%
......@@ -58,6 +58,9 @@ http {
# enable/disable sending nginx version
server_tokens %SERVER_TOKENS%;
# resolvers to use
resolver %DNS_RESOLVERS% ipv6=off;
# get real IP address if behind a reverse proxy
%PROXY_REAL_IP%
......
......@@ -155,6 +155,7 @@ SELF_SIGNED_SSL_OU="${SELF_SIGNED_SSL_OU-IT}"
SELF_SIGNED_SSL_CN="${SELF_SIGNED_SSL_CN-bunkerity-nginx}"
ANTIBOT_URI="${ANTIBOT_URI-/challenge}"
USE_ANTIBOT="${USE_ANTIBOT-cookie}"
ANTIBOT_RECAPTCHA_SCORE="${ANTIBOT_RECAPTCHA_SCORE-0.7}"
# install additional modules if needed
if [ "$ADDITIONAL_MODULES" != "" ] ; then
......@@ -436,9 +437,10 @@ else
replace_in_file "/etc/nginx/server.conf" "%AUTH_BASIC%" ""
fi
# lua resolvers
# DNS resolvers
resolvers=$(spaces_to_lua "$DNS_RESOLVERS")
replace_in_file "/usr/local/lib/lua/dns.lua" "%DNS_RESOLVERS%" "$resolvers"
replace_in_file "/etc/nginx/nginx.conf" "%DNS_RESOLVERS%" "$DNS_RESOLVERS"
# whitelist IP
if [ "$USE_WHITELIST_IP" = "yes" ] ; then
......@@ -503,30 +505,51 @@ if [ "$USE_ANTIBOT" = "cookie" ] ; then
replace_in_file "/etc/nginx/main-lua.conf" "%USE_ANTIBOT_COOKIE%" "true"
replace_in_file "/etc/nginx/main-lua.conf" "%USE_ANTIBOT_JAVASCRIPT%" "false"
replace_in_file "/etc/nginx/main-lua.conf" "%USE_ANTIBOT_CAPTCHA%" "false"
replace_in_file "/etc/nginx/main-lua.conf" "%USE_ANTIBOT_RECAPTCHA%" "false"
replace_in_file "/etc/nginx/main-lua.conf" "%INCLUDE_ANTIBOT_JAVASCRIPT%" ""
replace_in_file "/etc/nginx/main-lua.conf" "%INCLUDE_ANTIBOT_CAPTCHA%" ""
replace_in_file "/etc/nginx/main-lua.conf" "%INCLUDE_ANTIBOT_RECAPTCHA%" ""
# antibot via javascript
elif [ "$USE_ANTIBOT" = "javascript" ] ; then
replace_in_file "/etc/nginx/main-lua.conf" "%USE_ANTIBOT_COOKIE%" "false"
replace_in_file "/etc/nginx/main-lua.conf" "%USE_ANTIBOT_JAVASCRIPT%" "true"
replace_in_file "/etc/nginx/main-lua.conf" "%USE_ANTIBOT_CAPTCHA%" "false"
replace_in_file "/etc/nginx/main-lua.conf" "%USE_ANTIBOT_RECAPTCHA%" "false"
replace_in_file "/etc/nginx/main-lua.conf" "%INCLUDE_ANTIBOT_JAVASCRIPT%" "include /etc/nginx/antibot-javascript.conf;"
replace_in_file "/etc/nginx/main-lua.conf" "%INCLUDE_ANTIBOT_CAPTCHA%" ""
replace_in_file "/etc/nginx/main-lua.conf" "%INCLUDE_ANTIBOT_RECAPTCHA%" ""
replace_in_file "/etc/nginx/antibot-javascript.conf" "%ANTIBOT_URI%" "$ANTIBOT_URI"
# antibot via captcha
elif [ "$USE_ANTIBOT" = "captcha" ] ; then
replace_in_file "/etc/nginx/main-lua.conf" "%USE_ANTIBOT_COOKIE%" "false"
replace_in_file "/etc/nginx/main-lua.conf" "%USE_ANTIBOT_JAVASCRIPT%" "false"
replace_in_file "/etc/nginx/main-lua.conf" "%USE_ANTIBOT_CAPTCHA%" "true"
replace_in_file "/etc/nginx/main-lua.conf" "%USE_ANTIBOT_RECAPTCHA%" "false"
replace_in_file "/etc/nginx/main-lua.conf" "%INCLUDE_ANTIBOT_JAVASCRIPT%" ""
replace_in_file "/etc/nginx/main-lua.conf" "%INCLUDE_ANTIBOT_CAPTCHA%" "include /etc/nginx/antibot-captcha.conf;"
replace_in_file "/etc/nginx/main-lua.conf" "%INCLUDE_ANTIBOT_RECAPTCHA%" ""
replace_in_file "/etc/nginx/antibot-captcha.conf" "%ANTIBOT_URI%" "$ANTIBOT_URI"
# antibot via recaptcha
elif [ "$USE_ANTIBOT" = "recaptcha" ] ; then
replace_in_file "/etc/nginx/main-lua.conf" "%USE_ANTIBOT_COOKIE%" "false"
replace_in_file "/etc/nginx/main-lua.conf" "%USE_ANTIBOT_JAVASCRIPT%" "false"
replace_in_file "/etc/nginx/main-lua.conf" "%USE_ANTIBOT_CAPTCHA%" "false"
replace_in_file "/etc/nginx/main-lua.conf" "%USE_ANTIBOT_RECAPTCHA%" "true"
replace_in_file "/etc/nginx/main-lua.conf" "%INCLUDE_ANTIBOT_JAVASCRIPT%" ""
replace_in_file "/etc/nginx/main-lua.conf" "%INCLUDE_ANTIBOT_CAPTCHA%" ""
replace_in_file "/etc/nginx/main-lua.conf" "%INCLUDE_ANTIBOT_RECAPTCHA%" "include /etc/nginx/antibot-recaptcha.conf;"
replace_in_file "/etc/nginx/antibot-recaptcha.conf" "%ANTIBOT_URI%" "$ANTIBOT_URI"
replace_in_file "/etc/nginx/antibot-recaptcha.conf" "%ANTIBOT_RECAPTCHA_SITEKEY%" "$ANTIBOT_RECAPTCHA_SITEKEY"
replace_in_file "/etc/nginx/antibot-recaptcha.conf" "%ANTIBOT_RECAPTCHA_SECRET%" "$ANTIBOT_RECAPTCHA_SECRET"
replace_in_file "/etc/nginx/antibot-recaptcha.conf" "%ANTIBOT_RECAPTCHA_SCORE%" "$ANTIBOT_RECAPTCHA_SCORE"
else
replace_in_file "/etc/nginx/main-lua.conf" "%USE_ANTIBOT_COOKIE%" "false"
replace_in_file "/etc/nginx/main-lua.conf" "%USE_ANTIBOT_JAVASCRIPT%" "false"
replace_in_file "/etc/nginx/main-lua.conf" "%USE_ANTIBOT_CAPTCHA%" "false"
replace_in_file "/etc/nginx/main-lua.conf" "%USE_ANTIBOT_RECAPTCHA%" "false"
replace_in_file "/etc/nginx/main-lua.conf" "%INCLUDE_ANTIBOT_JAVASCRIPT%" ""
replace_in_file "/etc/nginx/main-lua.conf" "%INCLUDE_ANTIBOT_CAPTCHA%" ""
replace_in_file "/etc/nginx/main-lua.conf" "%INCLUDE_ANTIBOT_RECAPTCHA%" ""
fi
if [ "$USE_LIMIT_REQ" = "yes" ] ; then
......
local M = {}
local http = require "resty.http"
local cjson = require "cjson"
function M.get_code (antibot_uri, recaptcha_sitekey)
return string.format([[
<html>
<head>
<script src="https://www.google.com/recaptcha/api.js?render=%s"></script>
</head>
<body>
<form method="POST" action="%s" id="form">
<input type="hidden" name="token" id="token">
</form>
<script>
grecaptcha.ready(function() {
grecaptcha.execute('%s', {action: 'recaptcha'}).then(function(token) {
document.getElementById("token").value = token;
document.getElementById("form").submit();
});;
});
</script>
</body>
</html>
]], recaptcha_sitekey, antibot_uri, recaptcha_sitekey)
end
function M.check (token, recaptcha_secret)
local httpc = http.new()
local res, err = httpc:request_uri("https://www.google.com/recaptcha/api/siteverify", {
ssl_verify = false,
method = "POST",
body = "secret=" .. recaptcha_secret .. "&response=" .. token,
headers = { ["Content-Type"] = "application/x-www-form-urlencoded" }
})
if not res then
return 0.0
end
local data = cjson.decode(res.body)
if not data.success then
return 0.0
end
return data.score
end
return M
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment