Fail2ban integration with CSF to counteract DDoS on nginx
Tutorial
The ConfigServer Security & Firewall (CSF) script suite initially has a fairly rich set of features for securing the Web hosting server using the iptables packet filter. In particular, it can be used to resist flooding of an attacked host with TCP and SYN, UDP, and ICMP packets of weak and medium strength. CSF is complemented by the built-in Login Failure Daemon (lfd), which monitors the logs for the presence of numerous unsuccessful login attempts in various network services in order to select a password. Such attempts are blocked by adding the IP address of the attacker to the CSF blacklist.
There is another third-party tool that implements similar functionality: Fail2ban. Despite the similarity of the tasks being solved, there is a cardinal difference between lfd and Fail2ban. The first has a closed architecture and supports a limited set of services. While the second allows you to independently develop filters for almost any task. However, CSF and Fail2ban coexist badly on the same server, because they handle iptables rules somewhat unceremoniously. We will try to solve this problem using the Linux Debian v7.XX amd64 OS as an example, so as to maximize the capabilities of both tools. And as an example, we will organize protection against DDoS attacks on nginx.
In my configuration, CSF was originally installed and configured on the server. I will not dwell on this issue in detail; there is enough material on it. I recommend making the following settings in the file "/etc/csf/csf.conf":
Such a configuration will allow CSF to counteract those hosts that are involved in flood attacks by TCP SYN packets or open a large number of connections to the HTTP server TCP ports.
We proceed to the installation of Fail2ban, after which it must be stopped and autorun disabled:
service fail2ban stop
update-rc.d -f fail2ban remove
We will launch Fail2ban by means of CSF. To do this, create the script "/etc/csf/csfpost.sh":
#! / bin / sh
/etc/init.d/fail2ban reload
It will provide automatic loading of Fail2ban rules in iptables if CSF reloads its rules, for example, in case of updating.
The idea of integrating Fail2ban with CSF is based on the fact that the first will use the blacklist of the second, and not the iptables rules directly, to block the IP addresses of attackers. However, we do not refuse completely iptables in Fail2ban.
Disable all filters in Fail2ban. Most of them are covered by lfd. Fail2ban will be used only for what does not support lfd.
Add CSF support to Fail2ban. To do this, create the settings file "/etc/fail2ban/action.d/csf-ip-deny.conf" with the following contents:
[Definition]
actionstart =
actionstop =
actioncheck =
actionban = csf -d Added by Fail2Ban for
actionunban = csf -dr
Replace for all Fail2ban filters the blocking action with the created “csf-ip-deny”:
sed -i -e "s | banaction = | banaction = csf-ip-deny \ n # banaction = |" /etc/fail2ban/jail.conf
For particularly annoying intruders, a long lock is provided. This mechanism is implemented by monitoring the journal of Fail2ban itself. Create the settings file "/etc/fail2ban/filter.d/fail2ban.conf":
[Definition]
# Count all bans in the logfile
failregex = fail2ban.actions: WARNING \ [(. *) \] Ban
# Ignore our own bans, to keep our counts exact.
# In your config, name your jail 'fail2ban', or change this line!
ignoreregex = fail2ban.actions: WARNING \ [fail2ban \] Ban
Add the following lines to "/etc/fail2ban/jail.conf":
Those. those of cybercriminals who were blocked by other filters 10 or more times during the day will be blocked by this filter for a week. Note that the action is iptables-allports, not csf-ip-deny. It's not a mistake. So it is necessary that the long blocking does not happen to be accidentally removed by other filters.
Now, by the example of organizing nginx protection against DDoS attacks, consider creating Fail2ban filtering rules. Let's start by configuring nginx, it is necessary to use the capabilities of the ngx_http_limit_conn_module and ngx_http_limit_req_module modules in it . To do this, add the following lines to the settings:
limit_conn_zone $ binary_remote_addr zone = perip: 10m;
limit_conn perip 100;
limit_conn_zone $ server_name zone = perserver: 10m;
limit_conn perserver 200;
limit_req_zone $ binary_remote_addr zone = reqip: 10m rate = 10r / s;
limit_req zone = reqip burst = 30;
Thus, we set limits for no more than 100 connections from one IP address at a time with a speed of 10-30 new connections per second and no more than 200 - to one site from just any number of IP addresses. Excesses will be recorded in the error log, for which we will configure Fail2ban filters.
We create the following settings files.
"/etc/fail2ban/filter.d/nginx-conn-limit.conf"
# Fail2Ban configuration file
#
[Definition]
# Option: failregex
# Notes .: Regexp to catch a generic call from an IP address.
# Values: TEXT
#
failregex = limiting connections by zone. * client:
# Option: ignoreregex
# Notes .: regex to ignore. If this regex matches, the line is ignored.
# Values: TEXT
#
ignoreregex =
"/etc/fail2ban/filter.d/nginx-req-limit.conf"
# Fail2Ban configuration file
#
[Definition]
# Option: failregex
# Notes .: Regexp to catch a generic call from an IP address.
# Values: TEXT
#
failregex = limiting requests. * client:
# Option: ignoreregex
# Notes .: regex to ignore. If this regex matches, the line is ignored.
# Values: TEXT
#
ignoreregex =
"/etc/fail2ban/filter.d/nginx-dos.conf"
# Fail2Ban configuration file
#
[Definition]
# Option: failregex
# Notes .: Regexp to catch a generic call from an IP address.
# Values: TEXT
#
failregex = ^ -. * "(GET | POST). * HTTP. *" $
# Option: ignoreregex
# Notes .: regex to ignore. If this regex matches, the line is ignored.
# Values: TEXT
#
ignoreregex =
Add to "/etc/fail2ban/jail.conf":
[nginx-conn-limit]
enabled = true
filter = nginx-conn-limit
action = csf-ip-deny [name = nginx-conn-limit]
logpath = /var/log/nginx/error.log
maxretry = 4
findtime = 21600
bantime = 3600
[nginx-req-limit]
enabled = true
filter = nginx-req-limit
action = csf-ip-deny [name = nginx-req-limit]
logpath = /var/log/nginx/error.log
maxretry = 4
findtime = 21600
bantime = 3600
[nginx-dos]
# Based on apache-badbots but a simple IP check (any IP requesting more than
# 240 pages in 60 seconds, or 4p / s average, is suspicious)
enabled = true
filter = nginx-dos
action = csf-ip-deny [name = nginx-dos]
logpath = /var/log/nginx/access.log
maxretry = 240
findtime = 60
bantime = 3600
Filters "nginx-conn-limit" and "nginx-req-limit" will block those who exceed the limits for connecting to nginx, and "nginx-dos" will block those who access websites too often: more than 240 pages per minute.
Often the goal of attacks is the widespread WordPress CMS: password guessing and a large number of XML-RPC requests . We organize protection from them, too.
"/etc/fail2ban/filter.d/nginx-wp-login.conf"
[Definition]
failregex = . * POST /wp-login.php
ignoreregex =
"/etc/fail2ban/filter.d/nginx-wp-xmlrpc.conf"
[Definition]
failregex = . * POST /xmlrpc.php
ignoreregex =
Recently, cases have become more frequent when attackers carry out distributed enumeration of passwords from different IP addresses of one class C subnet. The Fail2ban operation algorithm is not able to recognize this behavior:
Those. Class C IP networks will be completely blocked for a week, if earlier other Fail2ban filters have been triggered to addresses from them 30 or more times.
Here is the result:
# csf -t
A / D IP address Port Dir Time To Live Comment
DENY 193.176.147.0/24 * in 6d 21h 34m 18s Subnet 193.176.147.0/24 is blocked for a week by Fail2ban after 641 attempts
DENY 46.148.30.0/24 * in 6d 21h 34m 19s Subnet 46.148.30.0/24 is blocked for a week by Fail2ban after 332 attempts
DENY 46.148.31.0/24 * in 6d 21h 34m 19s Subnet 46.148.31.0/24 is blocked for a week by Fail2ban after 334 attempts