diff --git a/compile.sh b/compile.sh index 2a99b4e..f073cec 100644 --- a/compile.sh +++ b/compile.sh @@ -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 diff --git a/confs/antibot-recaptcha.conf b/confs/antibot-recaptcha.conf new file mode 100644 index 0000000..b7cbef2 --- /dev/null +++ b/confs/antibot-recaptcha.conf @@ -0,0 +1,39 @@ +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")) + } + } +} diff --git a/confs/main-lua.conf b/confs/main-lua.conf index 0e232be..da5e472 100644 --- a/confs/main-lua.conf +++ b/confs/main-lua.conf @@ -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% diff --git a/confs/nginx.conf b/confs/nginx.conf index 1d5a17b..9ef6b65 100644 --- a/confs/nginx.conf +++ b/confs/nginx.conf @@ -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% diff --git a/entrypoint.sh b/entrypoint.sh index 1674875..41afc6c 100644 --- a/entrypoint.sh +++ b/entrypoint.sh @@ -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 diff --git a/lua/recaptcha.lua b/lua/recaptcha.lua new file mode 100644 index 0000000..5f85555 --- /dev/null +++ b/lua/recaptcha.lua @@ -0,0 +1,46 @@ +local M = {} +local http = require "resty.http" +local cjson = require "cjson" + +function M.get_code (antibot_uri, recaptcha_sitekey) + return string.format([[ + +
+ + + + + + + + ]], 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