diff --git a/Dockerfile b/Dockerfile index 2514293..cc3030f 100644 --- a/Dockerfile +++ b/Dockerfile @@ -12,7 +12,7 @@ COPY fail2ban/ /opt/fail2ban COPY logs/ /opt/logs COPY lua/ /opt/lua -RUN apk --no-cache add php7-fpm certbot libstdc++ libmaxminddb geoip pcre yajl fail2ban clamav apache2-utils rsyslog openssl && \ +RUN apk --no-cache add php7-fpm certbot libstdc++ libmaxminddb geoip pcre yajl fail2ban clamav apache2-utils rsyslog openssl lua && \ chmod +x /opt/entrypoint.sh /opt/scripts/* && \ mkdir /opt/entrypoint.d && \ adduser -h /dev/null -g '' -s /sbin/nologin -D -H nginx diff --git a/Dockerfile-amd64 b/Dockerfile-amd64 index e27fb3c..452a0c0 100644 --- a/Dockerfile-amd64 +++ b/Dockerfile-amd64 @@ -12,7 +12,7 @@ COPY fail2ban/ /opt/fail2ban COPY logs/ /opt/logs COPY lua/ /opt/lua -RUN apk --no-cache add php7-fpm certbot libstdc++ libmaxminddb geoip pcre yajl fail2ban clamav apache2-utils rsyslog openssl && \ +RUN apk --no-cache add php7-fpm certbot libstdc++ libmaxminddb geoip pcre yajl fail2ban clamav apache2-utils rsyslog openssl lua && \ chmod +x /opt/entrypoint.sh /opt/scripts/* && \ mkdir /opt/entrypoint.d && \ adduser -h /dev/null -g '' -s /sbin/nologin -D -H nginx diff --git a/Dockerfile-arm32v7 b/Dockerfile-arm32v7 index 8225452..e5e5bbe 100644 --- a/Dockerfile-arm32v7 +++ b/Dockerfile-arm32v7 @@ -19,7 +19,7 @@ COPY fail2ban/ /opt/fail2ban COPY logs/ /opt/logs COPY lua/ /opt/lua -RUN apk --no-cache add php7-fpm certbot libstdc++ libmaxminddb geoip pcre yajl fail2ban clamav apache2-utils rsyslog openssl && \ +RUN apk --no-cache add php7-fpm certbot libstdc++ libmaxminddb geoip pcre yajl fail2ban clamav apache2-utils rsyslog openssl lua && \ chmod +x /opt/entrypoint.sh /opt/scripts/* && \ mkdir /opt/entrypoint.d && \ adduser -h /dev/null -g '' -s /sbin/nologin -D -H nginx diff --git a/Dockerfile-arm64v8 b/Dockerfile-arm64v8 index 2117be4..f4091cf 100644 --- a/Dockerfile-arm64v8 +++ b/Dockerfile-arm64v8 @@ -19,7 +19,7 @@ COPY fail2ban/ /opt/fail2ban COPY logs/ /opt/logs COPY lua/ /opt/lua -RUN apk --no-cache add php7-fpm certbot libstdc++ libmaxminddb geoip pcre yajl fail2ban clamav apache2-utils rsyslog openssl && \ +RUN apk --no-cache add php7-fpm certbot libstdc++ libmaxminddb geoip pcre yajl fail2ban clamav apache2-utils rsyslog openssl lua && \ chmod +x /opt/entrypoint.sh /opt/scripts/* && \ mkdir /opt/entrypoint.d && \ adduser -h /dev/null -g '' -s /sbin/nologin -D -H nginx diff --git a/Dockerfile-i386 b/Dockerfile-i386 index 78381d7..bf86ae0 100644 --- a/Dockerfile-i386 +++ b/Dockerfile-i386 @@ -12,7 +12,7 @@ COPY fail2ban/ /opt/fail2ban COPY logs/ /opt/logs COPY lua/ /opt/lua -RUN apk --no-cache add php7-fpm certbot libstdc++ libmaxminddb geoip pcre yajl fail2ban clamav apache2-utils rsyslog openssl && \ +RUN apk --no-cache add php7-fpm certbot libstdc++ libmaxminddb geoip pcre yajl fail2ban clamav apache2-utils rsyslog openssl lua && \ chmod +x /opt/entrypoint.sh /opt/scripts/* && \ mkdir /opt/entrypoint.d && \ adduser -h /dev/null -g '' -s /sbin/nologin -D -H nginx diff --git a/confs/antibot-javascript.conf b/confs/antibot-javascript.conf new file mode 100644 index 0000000..7ceafc9 --- /dev/null +++ b/confs/antibot-javascript.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 javascript = require "javascript" + if not cookie.is_set("challenge") then + return ngx.exit(ngx.HTTP_FORBIDDEN) + end + local challenge = cookie.get("challenge") + local code = javascript.get_code(challenge, "%ANTIBOT_URI%", cookie.get("uri")) + ngx.say(code) + } + } + + if ($request_method = POST) { + content_by_lua_block { + local cookie = require "cookie" + local javascript = require "javascript" + if not cookie.is_set("challenge") 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["challenge"] then + return ngx.exit(ngx.HTTP_FORBIDDEN) + end + local challenge = args["challenge"] + local check = javascript.check(cookie.get("challenge"), challenge) + if not check then + return ngx.exit(ngx.HTTP_FORBIDDEN) + end + cookie.set("javascript", "ok") + cookie.save() + } + } +} diff --git a/confs/main-lua.conf b/confs/main-lua.conf index eedd4eb..2f69736 100644 --- a/confs/main-lua.conf +++ b/confs/main-lua.conf @@ -1,17 +1,19 @@ access_by_lua_block { -local use_whitelist_ip = %USE_WHITELIST_IP% -local use_whitelist_reverse = %USE_WHITELIST_REVERSE% -local use_blacklist_ip = %USE_BLACKLIST_IP% -local use_blacklist_reverse = %USE_BLACKLIST_REVERSE% -local use_dnsbl = %USE_DNSBL% -local use_antibot_cookie = %USE_ANTIBOT_COOKIE% +local use_whitelist_ip = %USE_WHITELIST_IP% +local use_whitelist_reverse = %USE_WHITELIST_REVERSE% +local use_blacklist_ip = %USE_BLACKLIST_IP% +local use_blacklist_reverse = %USE_BLACKLIST_REVERSE% +local use_dnsbl = %USE_DNSBL% +local use_antibot_cookie = %USE_ANTIBOT_COOKIE% +local use_antibot_javascript = %USE_ANTIBOT_JAVASCRIPT% -- include LUA code -local whitelist = require "whitelist" -local blacklist = require "blacklist" -local dnsbl = require "dnsbl" -local cookie = require "cookie" +local whitelist = require "whitelist" +local blacklist = require "blacklist" +local dnsbl = require "dnsbl" +local cookie = require "cookie" +local javascript = require "javascript" -- antibot local antibot_uri = "%ANTIBOT_URI%" @@ -74,15 +76,28 @@ end -- cookie check if use_antibot_cookie then - if not cookie.is_set() then - if ngx.var.uri ~= antibot_uri then - cookie.set() + if not cookie.is_set("uri") then + if ngx.var.request_uri ~= antibot_uri then + cookie.set("uri", ngx.var.request_uri) + cookie.save() return ngx.redirect(antibot_uri) end return ngx.exit(ngx.HTTP_FORBIDDEN) else - if ngx.var.uri == antibot_uri then - return ngx.redirect(cookie.get_uri()) + if ngx.var.request_uri == antibot_uri then + return ngx.redirect(cookie.get("uri")) + end + end +end + +-- javascript check +if use_antibot_javascript then + if not cookie.is_set("javascript") then + if ngx.var.request_uri ~= antibot_uri then + cookie.set("uri", ngx.var.request_uri) + cookie.set("challenge", javascript.get_challenge()) + cookie.save() + return ngx.redirect(antibot_uri) end end end @@ -90,3 +105,5 @@ end ngx.exit(ngx.OK) } + +%INCLUDE_ANTIBOT_JAVASCRIPT% diff --git a/entrypoint.sh b/entrypoint.sh index fc7afae..f68382f 100644 --- a/entrypoint.sh +++ b/entrypoint.sh @@ -154,7 +154,7 @@ SELF_SIGNED_SSL_ORG="${SELF_SIGNED_SSL_ORG-AcmeInc}" 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_COOKIE="${USE_ANTIBOT_COOKIE-yes}" +USE_ANTIBOT="${USE_ANTIBOT-cookie}" # install additional modules if needed if [ "$ADDITIONAL_MODULES" != "" ] ; then @@ -499,10 +499,20 @@ replace_in_file "/usr/local/lib/lua/dnsbl.lua" "%DNSBL_LIST%" "$list" replace_in_file "/etc/nginx/main-lua.conf" "%ANTIBOT_URI%" "$ANTIBOT_URI" # antibot via cookie -if [ "$USE_ANTIBOT_COOKIE" = "yes" ] ; then +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" "%INCLUDE_ANTIBOT_JAVASCRIPT%" "" +# 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" "%INCLUDE_ANTIBOT_JAVASCRIPT%" "include /etc/nginx/antibot-javascript.conf;" + replace_in_file "/etc/nginx/antibot-javascript.conf" "%ANTIBOT_URI%" "$ANTIBOT_URI" 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" "%INCLUDE_ANTIBOT_JAVASCRIPT%" "" fi if [ "$USE_LIMIT_REQ" = "yes" ] ; then diff --git a/lua/cookie.lua b/lua/cookie.lua index 8bafc28..4b783b5 100644 --- a/lua/cookie.lua +++ b/lua/cookie.lua @@ -1,22 +1,29 @@ + local M = {} local session = require "resty.session" -function M.is_set () - local s = session.open() - if s and s.data.uri then - return true - end - return false +local s = session.open() +if not s then + s = session.start() end -function M.set () - local s = session.start() - s.data.uri = ngx.var.request_uri +function M.is_set (key) + if s.data[key] then + return true + end + return false +end + +function M.set (key, value) + s.data[key] = value +end + +function M.get (key) + return s.data[key] +end + +function M.save () s:save() end -function M.get_uri () - return session.open().data.uri -end - return M diff --git a/lua/javascript.lua b/lua/javascript.lua new file mode 100644 index 0000000..e2e032a --- /dev/null +++ b/lua/javascript.lua @@ -0,0 +1,57 @@ +local M = {} +local session = require "resty.session" + +function M.get_challenge () + local charset = "abcdefghijklmnopqrstuvwxyzABCDEFGHIKLMNOPQRSTUVWXYZ0123456789" + math.randomseed(os.clock()*os.time()) + local random = "" + local rand = 0 + for i = 1, 20 do + rand = math.random(1, #charset) + random = random .. charset:sub(rand, rand) + end + return random +end + +function M.get_code (challenge, antibot_uri, original_uri) + return string.format([[ + + + + + + + + ]], challenge, antibot_uri, original_uri) +end + +function M.check (challenge, user) + local resty_sha256 = require "resty.sha256" + local str = require "resty.string" + local sha256 = resty_sha256:new() + sha256:update(challenge) + local digest = sha256:final() + return str.to_hex(digest) == user +end + +return M