bad behavior - move from fail2ban to pure lua

This commit is contained in:
bunkerity 2021-05-13 16:21:51 +02:00
parent eb2d0d330d
commit 0b3ff6a9f4
No known key found for this signature in database
GPG Key ID: 3D80806F12602A7C
27 changed files with 90 additions and 148 deletions

View File

@ -14,8 +14,6 @@ RUN chmod +x /tmp/dependencies.sh && \
COPY entrypoint/ /opt/entrypoint
COPY confs/ /opt/confs
COPY scripts/ /opt/scripts
COPY fail2ban/ /opt/fail2ban
COPY logs/ /opt/logs
COPY lua/ /opt/lua
COPY prepare.sh /tmp/prepare.sh

View File

@ -14,8 +14,6 @@ RUN chmod +x /tmp/dependencies.sh && \
COPY entrypoint/ /opt/entrypoint
COPY confs/ /opt/confs
COPY scripts/ /opt/scripts
COPY fail2ban/ /opt/fail2ban
COPY logs/ /opt/logs
COPY lua/ /opt/lua
COPY prepare.sh /tmp/prepare.sh

View File

@ -21,8 +21,6 @@ RUN chmod +x /tmp/dependencies.sh && \
COPY entrypoint/ /opt/entrypoint
COPY confs/ /opt/confs
COPY scripts/ /opt/scripts
COPY fail2ban/ /opt/fail2ban
COPY logs/ /opt/logs
COPY lua/ /opt/lua
COPY prepare.sh /tmp/prepare.sh

View File

@ -21,8 +21,6 @@ RUN chmod +x /tmp/dependencies.sh && \
COPY entrypoint/ /opt/entrypoint
COPY confs/ /opt/confs
COPY scripts/ /opt/scripts
COPY fail2ban/ /opt/fail2ban
COPY logs/ /opt/logs
COPY lua/ /opt/lua
COPY prepare.sh /tmp/prepare.sh

View File

@ -14,8 +14,6 @@ RUN chmod +x /tmp/dependencies.sh && \
COPY entrypoint/ /opt/entrypoint
COPY confs/ /opt/confs
COPY scripts/ /opt/scripts
COPY fail2ban/ /opt/fail2ban
COPY logs/ /opt/logs
COPY lua/ /opt/lua
COPY prepare.sh /tmp/prepare.sh

View File

@ -89,6 +89,7 @@ http {
%BLOCK_TOR_EXIT_NODES%
%BLOCK_USER_AGENTS%
%BLOCK_REFERRERS%
%BAD_BEHAVIOR%
# crowdsec init
%USE_CROWDSEC%

11
confs/site/log-lua.conf Normal file
View File

@ -0,0 +1,11 @@
log_by_lua_block {
local use_bad_behavior = %USE_BAD_BEHAVIOR%
local behavior = require "behavior"
if use_bad_behavior then
behavior.count()
end
}

View File

@ -20,6 +20,7 @@ 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%
local use_bad_behavior = %USE_BAD_BEHAVIOR%
-- include LUA code
local whitelist = require "whitelist"
@ -30,6 +31,7 @@ local javascript = require "javascript"
local captcha = require "captcha"
local recaptcha = require "recaptcha"
local iputils = require "resty.iputils"
local behavior = require "behavior"
-- user variables
local antibot_uri = "%ANTIBOT_URI%"
@ -98,6 +100,12 @@ if use_blacklist_reverse and not blacklist.reverse_cached() then
end
end
-- check if IP is banned because of "bad behavior"
if use_bad_behavior and behavior.is_banned() then
ngx.log(ngx.NOTICE, "[BLOCK] IP " .. ngx.var.remote_addr .. " is banned because of bad behavior")
ngx.exit(ngx.HTTP_FORBIDDEN)
end
-- check if IP is in proxies list
if use_proxies then
local value, flags = ngx.shared.proxies_data:get(iputils.ip2bin(ngx.var.remote_addr))

View File

@ -4,7 +4,7 @@ server {
%FASTCGI_PATH%
%SERVER_CONF%
%PROXY_REAL_IP%
%MAIN_LUA%
%INCLUDE_LUA%
%USE_MODSECURITY%
%LISTEN_HTTP%
%USE_HTTPS%
@ -29,7 +29,6 @@ server {
%PERMISSIONS_POLICY%
%COOKIE_FLAGS%
%ERRORS%
%USE_FAIL2BAN%
%USE_CLIENT_CACHE%
%USE_GZIP%
%USE_BROTLI%

View File

@ -69,15 +69,13 @@ CONTENT_SECURITY_POLICY="${CONTENT_SECURITY_POLICY-object-src 'none'; frame-ance
COOKIE_FLAGS="${COOKIE_FLAGS-* HttpOnly SameSite=Lax}"
COOKIE_AUTO_SECURE_FLAG="${COOKIE_AUTO_SECURE_FLAG-yes}"
SERVE_FILES="${SERVE_FILES-yes}"
WRITE_ACCESS="${WRITE_ACCESS-no}"
REDIRECT_HTTP_TO_HTTPS="${REDIRECT_HTTP_TO_HTTPS-no}"
LISTEN_HTTP="${LISTEN_HTTP-yes}"
USE_FAIL2BAN="${USE_FAIL2BAN-yes}"
FAIL2BAN_STATUS_CODES="${FAIL2BAN_STATUS_CODES-400|401|403|404|405|444}"
FAIL2BAN_BANTIME="${FAIL2BAN_BANTIME-3600}"
FAIL2BAN_FINDTIME="${FAIL2BAN_FINDTIME-60}"
FAIL2BAN_MAXRETRY="${FAIL2BAN_MAXRETRY-15}"
FAIL2BAN_IGNOREIP="${FAIL2BAN_IGNOREIP-127.0.0.1/8 192.168.0.0/16 172.16.0.0/12 10.0.0.0/8}"
USE_BAD_BEHAVIOR="${USE_BAD_BEHAVIOR-yes}"
BAD_BEHAVIOR_STATUS_CODES="${BAD_BEHAVIOR_STATUS_CODES-400 401 403 404 405 429 444}"
BAD_BEHAVIOR_THRESHOLD="${BAD_BEHAVIOR_THRESHOLD-10}"
BAD_BEHAVIOR_BAN_TIME="${BAD_BEHAVIOR_BAN_TIME-86400}"
BAD_BEHAVIOR_COUNT_TIME="${BAD_BEHAVIOR_COUNT_TIME-60}"
USE_CLAMAV_UPLOAD="${USE_CLAMAV_UPLOAD-yes}"
USE_CLAMAV_SCAN="${USE_CLAMAV_SCAN-yes}"
USE_CLAMAV_SCAN_CRON="${USE_CLAMAV_SCAN_CRON-30 1 * * *}"

View File

@ -105,11 +105,6 @@ fi
echo "[*] Running nginx ..."
nginx &
pid="$!"
#if [ "$?" -eq 0 ] ; then
# echo "[*] nginx successfully started !"
#else
# echo "[!] nginx failed to start"
#fi
# autotest
if [ "$1" == "test" ] ; then

View File

@ -220,9 +220,11 @@ else
replace_in_file "/etc/nginx/multisite-default-server.conf" "%MULTISITE_DISABLE_DEFAULT_SERVER%" ""
fi
# fail2ban setup
if [ "$(has_value USE_FAIL2BAN yes)" != "" ] ; then
echo "" > /etc/nginx/fail2ban-ip.conf
# bad behavior
if [ "$(has_value USE_BAD_BEHAVIOR yes)" != "" ] ; then
replace_in_file "/etc/nginx/nginx.conf" "%BAD_BEHAVIOR%" "lua_shared_dict behavior_ban 10m;\nlua_shared_dict behavior_count 10m;"
else
replace_in_file "/etc/nginx/nginx.conf" "%BAD_BEHAVIOR%" ""
fi
# CrowdSec setup

View File

@ -33,6 +33,13 @@ replace_in_file "/usr/local/lib/lua/blacklist.lua" "%BLACKLIST_REVERSE_LIST%" "$
list=$(spaces_to_lua "$DNSBL_LIST")
replace_in_file "/usr/local/lib/lua/dnsbl.lua" "%DNSBL_LIST%" "$list"
# bad behavior
list=$(spaces_to_lua "$BAD_BEHAVIOR_STATUS_CODES")
replace_in_file "/usr/local/lib/lua/behavior.lua" "%STATUS_CODES%" "$list"
replace_in_file "/usr/local/lib/lua/behavior.lua" "%THRESHOLD%" "$BAD_BEHAVIOR_THRESHOLD"
replace_in_file "/usr/local/lib/lua/behavior.lua" "%BAN_TIME%" "$BAD_BEHAVIOR_BAN_TIME"
replace_in_file "/usr/local/lib/lua/behavior.lua" "%COUNT_TIME%" "$BAD_BEHAVIOR_COUNT_TIME"
# CrowdSec setup
if [ "$(has_value USE_CROWDSEC yes)" != "" ] ; then
replace_in_file "/usr/local/lib/lua/crowdsec/crowdsec.conf" "%CROWDSEC_HOST%" "$CROWDSEC_HOST"

View File

@ -38,7 +38,7 @@ fi
cp /opt/confs/site/* "$NGINX_PREFIX"
# replace paths
replace_in_file "${NGINX_PREFIX}server.conf" "%MAIN_LUA%" "include ${NGINX_PREFIX}main-lua.conf;"
replace_in_file "${NGINX_PREFIX}server.conf" "%INCLUDE_LUA%" "include ${NGINX_PREFIX}main-lua.conf;\ninclude ${NGINX_PREFIX}log-lua.conf;"
if [ "$MULTISITE" = "yes" ] ; then
replace_in_file "${NGINX_PREFIX}server.conf" "%SERVER_CONF%" "include /server-confs/*.conf;\ninclude /server-confs/${first_server}/*.conf;"
replace_in_file "${NGINX_PREFIX}server.conf" "%PRE_SERVER_CONF%" "include /pre-server-confs/*.conf;\ninclude /pre-server-confs/${first_server}/*.conf;"
@ -562,6 +562,15 @@ else
replace_in_file "${NGINX_PREFIX}main-lua.conf" "%INCLUDE_ANTIBOT_RECAPTCHA%" ""
fi
# bad behavior
if [ "$USE_BAD_BEHAVIOR" = "yes" ] ; then
replace_in_file "${NGINX_PREFIX}main-lua.conf" "%USE_BAD_BEHAVIOR%" "true"
replace_in_file "${NGINX_PREFIX}log-lua.conf" "%USE_BAD_BEHAVIOR%" "true"
else
replace_in_file "${NGINX_PREFIX}main-lua.conf" "%USE_BAD_BEHAVIOR%" "false"
replace_in_file "${NGINX_PREFIX}log-lua.conf" "%USE_BAD_BEHAVIOR%" "false"
fi
# request limiting
if [ "$USE_LIMIT_REQ" = "yes" ] ; then
replace_in_file "${NGINX_PREFIX}server.conf" "%LIMIT_REQ%" "include ${NGINX_PREFIX}limit-req.conf;"
@ -578,13 +587,6 @@ else
replace_in_file "${NGINX_PREFIX}server.conf" "%LIMIT_CONN%" ""
fi
# fail2ban
if [ "$USE_FAIL2BAN" = "yes" ] ; then
replace_in_file "${NGINX_PREFIX}server.conf" "%USE_FAIL2BAN%" "include /etc/nginx/fail2ban-ip.conf;"
else
replace_in_file "${NGINX_PREFIX}server.conf" "%USE_FAIL2BAN%" ""
fi
# clamav scan uploaded files
if [ "$USE_CLAMAV_UPLOAD" = "yes" ] ; then
replace_in_file "${NGINX_PREFIX}modsecurity-rules.conf" "%USE_CLAMAV_UPLOAD%" "include ${NGINX_PREFIX}modsecurity-clamav.conf"

View File

@ -30,7 +30,7 @@ services:
- nc.website.com_LIMIT_REQ_BURST=10
- nc.website.com_ALLOWED_METHODS=GET|POST|HEAD|COPY|DELETE|LOCK|MKCOL|MOVE|PROPFIND|PROPPATCH|PUT|UNLOCK|OPTIONS
- nc.website.com_X_FRAME_OPTIONS=SAMEORIGIN
- nc.website.com_FAIL2BAN_STATUS_CODE=400|401|403|405|444
- nc.website.com_BAD_BEHAVIOR_STATUS_CODE=400|401|403|405|444
networks:
- net1
- net2

View File

@ -28,7 +28,7 @@ services:
- ALLOWED_METHODS=GET|POST|HEAD|COPY|DELETE|LOCK|MKCOL|MOVE|PROPFIND|PROPPATCH|PUT|UNLOCK|OPTIONS
- X_FRAME_OPTIONS=SAMEORIGIN
- USE_GZIP=yes
- FAIL2BAN_STATUS_CODE=400|401|403|405|444
- BAD_BEHAVIOR_STATUS_CODE=400|401|403|405|444
mync:
image: nextcloud:21-fpm

View File

@ -20,7 +20,7 @@ services:
- BLOCK_TOR_EXIT_NODE=no
- BLOCK_ABUSERS=no
- BLOCK_PROXIES=no
- USE_FAIL2BAN=no
- USE_BAD_BEHAVIOR=no
- USE_DNSBL=no
- USE_WHITELIST_IP=no
- USE_WHITELIST_REVERSE=no

View File

@ -1,8 +0,0 @@
[Definition]
actionstart = echo "" > /etc/nginx/fail2ban-ip.conf && /usr/sbin/nginx -s reload
actionstop = echo "" > /etc/nginx/fail2ban-ip.conf && /usr/sbin/nginx -s reload
actioncheck =
actionflush = echo "" > /etc/nginx/fail2ban-ip.conf && /usr/sbin/nginx -s reload
actionban = echo -n "deny <ip>;" >> /etc/nginx/fail2ban-ip.conf && /usr/sbin/nginx -s reload
actionunban = sed -i "s/deny <ip>;//g" /etc/nginx/fail2ban-ip.conf && /usr/sbin/nginx -s reload

View File

@ -1,7 +0,0 @@
[INCLUDES]
before = common.conf
[Definition]
failregex = <HOST> - .* \[.*\] ".*" (%FAIL2BAN_STATUS_CODES%) .* ".*" ".*"
ignoreregex =
datepattern = %%d/%%b/%%Y:%%H:%%M:%%S

View File

@ -1,8 +0,0 @@
[nginx-filter]
bantime = %FAIL2BAN_BANTIME%
findtime = %FAIL2BAN_FINDTIME%
maxretry = %FAIL2BAN_MAXRETRY%
ignoreip = %FAIL2BAN_IGNOREIP%
enabled = true
action = nginx-action
logpath = /var/log/access.log

View File

@ -1,23 +0,0 @@
/var/log/*.log /var/log/clamav/*.log /var/log/nginx/*.log /var/log/letsencrypt/*.log {
# compress old files using gzip
compress
# rotate everyday
daily
# remove old logs after X days
maxage %LOGROTATE_MAXAGE%
rotate %LOGROTATE_MAXAGE%
# no errors if a file is missing
missingok
# disable mailing
nomail
# mininum size of a logfile before rotating
minsize %LOGROTATE_MINSIZE%
# make a copy and truncate the files
copytruncate
}

View File

@ -1,29 +0,0 @@
#### Global directives ####
# Sets the directory that rsyslog uses for work files.
$WorkDirectory /var/lib/rsyslog
# Sets default permissions for all log files.
$FileOwner nginx
$FileGroup nginx
$FileCreateMode 0660
$DirCreateMode 0770
$Umask 0007
# Include all config files in /etc/rsyslog.d/.
include(file="/etc/rsyslog.d/*.conf" mode="optional")
#### Modules ####
# Provides --MARK-- message capability.
#module(load="immark")
# Provides support for local system logging (e.g. via logger command).
module(load="imuxsock" SysSock.Name="/tmp/log")
# Nginx
$template rawFormat,"%msg:2:2048%\n"
local0.=notice /var/log/access.log;rawFormat
local0.*;local0.!=notice /var/log/error.log;rawFormat
%REMOTE_SYSLOG%

37
lua/behavior.lua Normal file
View File

@ -0,0 +1,37 @@
local M = {}
local status_codes = {%STATUS_CODES%}
local threshold = %THRESHOLD%
local count_time = %COUNT_TIME%
local ban_time = %BAN_TIME%
function M.is_banned ()
return ngx.shared.behavior_ban:get(ngx.var.remote_addr) == true
end
function M.count ()
for k, v in ipairs(status_codes) do
if v == tostring(ngx.status) then
local count = ngx.shared.behavior_count:get(ngx.var.remote_addr)
if count == nil then
count = 0
end
count = count + 1
local ok, err = ngx.shared.behavior_count:set(ngx.var.remote_addr, count, count_time)
if not ok then
ngx.log(ngx.ERR, "[BEHAVIOR] not enough memory allocated to behavior_ip_count")
return
end
if count >= threshold then
ngx.log(ngx.NOTICE, "[BEHAVIOR] threshold reached for " .. ngx.var.remote_addr .. " (" .. count .. " / " .. threshold .. ") : IP is banned for " .. ban_time .. " seconds")
local ok, err = ngx.shared.behavior_ban:safe_set(ngx.var.remote_addr, true, ban_time)
if not ok then
ngx.log(ngx.ERR, "[BEHAVIOR] not enough memory allocated to behavior_ip_ban")
return
end
end
break
end
end
end
return M

View File

@ -28,7 +28,6 @@ ln -s /proc/1/fd/2 /var/log/nginx/modsec_audit.log
ln -s /proc/1/fd/1 /var/log/access.log
ln -s /proc/1/fd/2 /var/log/error.log
ln -s /proc/1/fd/1 /var/log/jobs.log
ln -s /proc/1/fd/1 /var/log/fail2ban.log
ln -s /proc/1/fd/1 /var/log/clamav.log
mkdir /var/log/letsencrypt
chown nginx:nginx /var/log/letsencrypt

View File

@ -1,19 +0,0 @@
#!/bin/sh
# load some functions
. /opt/entrypoint/utils.sh
logrotate -f /etc/logrotate.conf > /dev/null 2>&1
pkill -HUP rsyslogd
fail2ban-client flushlogs
if [ -f /tmp/nginx.pid ] ; then
/usr/sbin/nginx -s reload > /dev/null 2>&1
if [ "$?" -eq 0 ] ; then
job_log "[NGINX] successfull nginx reload after logrotate"
else
job_log "[NGINX] failed nginx reload after logrotate"
fi
fi

View File

@ -804,19 +804,6 @@
}
]
},
"Fail2ban":{
"id":"fail2ban",
"params":[
{
"type":"checkbox",
"label":"Use fail2ban",
"env":"USE_FAIL2BAN",
"regex":"^(yes|no)$",
"id":"use-fail2ban",
"default":"yes"
}
]
},
"ClamAV":{
"id":"clamav",
"params":[

View File

@ -46,8 +46,8 @@
<div class="col col-6 text-center"><i class="fas fa-{{ env_to_summary_class([service["AUTO_LETS_ENCRYPT"], service["USE_CUSTOM_HTTPS"], service["GENERATE_SELF_SIGNED_SSL"]], ["yes", "yes", "yes"]) }}"></i></div>
<div class="col col-6">ModSecurity</div>
<div class="col col-6 text-center"><i class="fas fa-{{ env_to_summary_class(service["USE_MODSECURITY"], "yes") }}"></i></div>
<div class="col col-6">Fail2Ban</div>
<div class="col col-6 text-center"><i class="fas fa-{{ env_to_summary_class(service["USE_FAIL2BAN"], "yes") }}"></i></div>
<div class="col col-6">Bad behavior</div>
<div class="col col-6 text-center"><i class="fas fa-{{ env_to_summary_class(service["USE_BAD_BEHAVIOR"], "yes") }}"></i></div>
<div class="col col-6">Limit req</div>
<div class="col col-6 text-center"><i class="fas fa-{{ env_to_summary_class(service["USE_LIMIT_REQ"], "yes") }}"></i></div>
<div class="col col-6">DNSBL</div>