Debian: Apache + Mod-Security + fail2ban

ModSecurity was originally designed for Apache web server. It could work with Nginx before version 3.0 but suffered from poor performance. ModSecurity 3.0 (aka libmodsecurity) was released in 2017. It’s a milestone release, particularly for Nginx users, as it’s the first version to work natively with Nginx. The caveat of ModSecurity 3 is that it doesn’t yet have all the features as in the previous version (2.9), though each new release will add some of the missing features.

<!–more–>

@original post: https://www.linuxbabe.com/security/modsecurity-apache-debian-ubuntu

Step 1: Install Packages

The ModSecurity module for Apache is included in the default Debian/Ubuntu repository. To install it, run

# apt install libapache2-mod-security2

Then enable this module.

# a2enmod security2

Restart Apache for the change to take effect.

# systemctl restart apache2

Step 2: Configure ModSecurity

In the /etc/apache2/mods-enabled/security2.conf configuration file, you can find the following line.

IncludeOptional /etc/modsecurity/*.conf
sudo a2enmod security2

This means Apache will include all the *.conf files in /etc/modsecurity/ directory. We need to rename the modsecurity.conf-recommended file to make it work.

# mv /etc/modsecurity/modsecurity.conf-recommended /etc/modsecurity/modsecurity.conf

Then edit this file with a command-line text editor like Nano.

# vi /etc/modsecurity/modsecurity.conf

Find the following line.

SecRuleEngine DetectionOnly

This config tells ModSecurity to log HTTP transactions, but takes no action when an attack is detected. Change it to the following, so ModSecurity will detect and block web attacks.

SecRuleEngine On

Then find the following line (line 186), which tells ModSecurity what information should be included in the audit log.

SecAuditLogParts ABDEFHIJZ

However, the default setting is wrong. You will know why later when I explain how to understand ModSecurity logs. The setting should be changed to the following.

SecAuditLogParts ABCEFHJKZ

Save and close the file. Then restart Apache for the change to take effect. (Reloding the web server isn’t enough.)

# sudo systemctl restart apache2

Step 3: Install the OWASP Core Rule Set (CRS)

To make ModSecurity protect your web applications, you need to define rules to detect malicious actors and block them. For beginners, it’s a good idea to install existing rule sets, so you can get started quickly and then learn the nitty-gritty down the road. There are several free rule sets for ModSecurity. The OWASP Core Rule Set (CRS) is the standard rule set used with ModSecurity

When installing ModSecurity from the default Debian/Ubuntu repository, the modsecurity-crs package is also installed as a dependency. This package contains the OWASP core rule set version 3.x. However, it can become out of date. If you care about security, you should use the latest version of core rule set.

Download the latest OWASP CRS from GitHub.

# wget https://github.com/coreruleset/coreruleset/archive/v3.3.2.tar.gz

Extract the file.

# tar xvf v3.3.2.tar.gz

Create a directory to store CRS files.

# mkdir /etc/apache2/modsecurity-crs/

Move the extracted directory to /etc/apache2/modsecurity-crs/.

# mv coreruleset-3.3.2/ /etc/apache2/modsecurity-crs/

Create a symbolic link

# ln /etc/apache2/modsecurity-crs/coreruleset/ /etc/apache2/modsecurity-crs/coreruleset-3.3.2/

Go to that directory.

# cd /etc/apache2/modsecurity-crs/coreruleset-3.3.2/

Rename the crs-setup.conf.example file.

# mv crs-setup.conf.example crs-setup.conf

Edit the /etc/apache2/mods-enabled/security2.conf file.

# vi /etc/apache2/mods-enabled/security2.conf

Find the following line, which loads the default CRS files.

IncludeOptional /usr/share/modsecurity-crs/*.load

Change it to the following, so the latest OWASP CRS will be used.

IncludeOptional /etc/apache2/modsecurity-crs/coreruleset/crs-setup.conf
IncludeOptional /etc/apache2/modsecurity-crs/coreruleset/rules/*.conf
apache Install the OWASP Core Rule Set CRS debian ubuntu

Save and close the file. Then test Apache configuration.

# apache2ctl -t

If the syntax is OK, then restart Apache.

# systemctl restart apache2

Step 4: Handling False Positives

ModSecurity is a generic web application firewall and not designed for a specific web application. The OWASP core rule set is also a generic rule set with no particular application in mind, so it’s likely that you will see false positives after enabling ModSecurity and OWASP CRS. If you increase the paranoia level in the CRS, there will be more false positives.

For example, by default, the CRS forbids Unix command injection, to eliminate false positives, you need to add rule exclusions to the CRS.

Application-Specific Rule Exclusions

There are some prebuilt, application-specific exclusions shipped with OWASP CRS. Edit the crs-setup.conf file.

# vi /etc/apache2/modsecurity-crs/coreruleset-3.3.2/crs-setup.conf

Go to the Application Specific Rule Exclusions section and find the following lines.

#SecAction \
# "id:900130,\
#  phase:1,\
#  nolog,\
#  pass,\
#  t:none,\
#  setvar:tx.crs_exclusions_cpanel=1,\
#  setvar:tx.crs_exclusions_drupal=1,\
#  setvar:tx.crs_exclusions_dokuwiki=1,\
#  setvar:tx.crs_exclusions_nextcloud=1,\
#  setvar:tx.crs_exclusions_wordpress=1,\
#  setvar:tx.crs_exclusions_xenforo=1"

For instance, If I want to enable WordPress exclusions, the above lines should be changed to the following.

SecAction \
  "id:900130,\
   phase:1,\
   nolog,\
   pass,\
   t:none,\
   setvar:tx.crs_exclusions_wordpress=1"

Save and close the file. Then test Apache configurations.

# apache2ctl -t

If the test is successful, restart Apache for the change to take effect.

# systemctl restart apache2

Note that if you have multiple applications such as (WordPress, Nextcloud, Drupal, etc) installed on the same server, then the above rule exclusions will be applied to all applications. To minimize the security risks, you should enable a rule exclusion for one application only. To do that, go to the /etc/apache2/modsecurity-crs/coreruleset-3.3.2/rules/ directory.

# cd /etc/apache2/modsecurity-crs/coreruleset-3.3.2/rules/

Rename the REQUEST-900-EXCLUSION-RULES-BEFORE-CRS file.

# mv REQUEST-900-EXCLUSION-RULES-BEFORE-CRS.conf.example REQUEST-900-EXCLUSION-RULES-BEFORE-CRS.conf

Then edit this file.

# vi REQUEST-900-EXCLUSION-RULES-BEFORE-CRS.conf

Add the following line at the bottom of this file. If your WordPress is using the blog.yourdomain.com sub-domain and the request header sent from visitor’s browser contains this sub-domain, then ModSecurity will apply the rule exclusions for WordPress.

SecRule REQUEST_HEADERS:Host "@streq blog.yourdomain.com" "id:1000,phase:1,setvar:tx.crs_exclusions_wordpress=1"

If you have installed Nextcloud on the same server, then you can also add the following line in this file, so if a visitor is accessing your Nextcloud sub-domain, ModSecurity will apply the Nextcloud rule exclusions.

SecRule REQUEST_HEADERS:Host "@streq nextcloud.yourdomain.com" "id:1001,phase:1,setvar:tx.crs_exclusions_nextcloud=1"

Save and close this file. Then test Apache configurations.

# apache2ctl -t

If the test is successful, rstart Apache for the change to take effect.

# systemctl restart apache2

IP Whitelisting

If you want to disable ModSecurity for your own IP address, but leave it enabled for all other IP addresses, then add the following custom rule in the REQUEST-900-EXCLUSION-RULES-BEFORE-CRS.conf file. Replace 12.34.56.78 with your real IP address.

SecRule REMOTE_ADDR "^12\.34\.56\.78" "id:1004,phase:1,allow,ctl:ruleEngine=off"

To whitelist a subnet, use the following syntax, which will whitelist the 10.10.10.0/24 network.

SecRule REMOTE_ADDR "^10\.10\.10.*" "id:1005,phase:1,allow,ctl:ruleEngine=off"

Save and close the file. Then test Apache configurations.

# apache2ctl -t

If the test is successful, restart Apache for the change to take effect.

# systemctl restart apache2

(Optional) Integrate ModSecurity with Project Honeypot

Project Honeypot maintains a list of known malicious IP addresses, available free to the public. ModSecurity can integrates with Project Honeypot and block IP addresses on the Project Honeypot list.

Note that using Project Honeypot will make your website slower for new visitors, because your web server will need to send a query to Project Honeypot before it can send a response to the new visitor. However, once the IP reputation data is cached on your web server, the performance impact will be very minimal.

To use Project Honeypot, first create a free account on its website. Then go to your account dashboard and click the get one link to request an access key for the HTTP blacklist.

Project Honeypot HTTP blacklist API key

Next, edit the crs-setup.conf file.

# vi /etc/apache2/modsecurity-crs/coreruleset-3.3.2/crs-setup.conf

Find the following lines.

#SecHttpBlKey XXXXXXXXXXXXXXXXX
#SecAction "id:900500,\
#  phase:1,\
#  nolog,\
#  pass,\
#  t:none,\
#  setvar:tx.block_search_ip=1,\
#  setvar:tx.block_suspicious_ip=1,\
#  setvar:tx.block_harvester_ip=1,\
#  setvar:tx.block_spammer_ip=1"

Remove the beginning # characters to uncomment them, and add your HTTPBL API key obtained from Project Honeypot.

Integrate ModSecurity with Project Honeypot

Note that block_search_ip should be set to 0 (disabled), as we don’t want to block search engine crawlers. Save and close the file. Then restart Apache.

# systemctl restart apache2

Now ModSecurity will query Project Honeypot on all HTTP requests. To test if this would work, edit the crs-setup.conf file.

# vi /etc/apache2/modsecurity-crs/coreruleset-3.3.2/crs-setup.conf

In Nano text editor, you can quickly jump to the end of the file by pressing Ctrl+W, then Ctrl+V. Add the following line at the end of this file. This allows us to pass an IP address in an URL. (Once the test is successful, you can remove this line from the file.)

SecRule ARGS:IP "@rbl dnsbl.httpbl.org" "phase:1,id:171,t:none,deny,nolog,auditlog,msg:'RBL Match for SPAM Source'

Save and close the file. Test Apache configurations.

# apache2ctl -t

Then restart Apache.

# systemctl restart apache2

Go to Project Honeypot website and find a malicious IP address, for example, 134.119.218.243. Run the following command to test the HTTP blacklist.

# curl -i -s -k -X $'GET' 'https://yourdomain.com/?IP=134.119.218.243'

Your Apache web server should return a 403 forbidden response because the IP address is on Project Honeypot.

How to Disable ModSecurity for a Virtual Host

By default, ModSecurity is enabled for all Apache virtual hosts. If you want to disable ModSecurity for a specific virtual host, then edit the virtual host file (/etc/apache2/sites-enabled/example.com.conf) and add the following line to the <VirtualHost>...</VirtualHost> context.

SecRuleEngine DetectionOnly

Reload Apache for the change to take effect.

# systemctl reload apache2

How to Upgrade OWASP CRS

You need to upgrade the core rule set when a new version comes out. The process is straightforward.

  • Go through step 3 again to install the new version of core rule set.
  • Then go to step 7. Copy of your custom rules in the crs-setup.conf  and REQUEST-900-EXCLUSION-RULES-BEFORE-CRS file.

Next, test Apache configurations.

# apache2ctl -t

If the test is successful, restart Apache for the change to take effect.

# systemctl restart apache2

How do you know if the new version is working? Launch a simple SQL injection attack like in step 5 and check your server logs. It will show you the CRS version that’s preventing this attack.

Step 5: Enable Fail2Ban

if you have fail2ban configured, you can enable a specific jail to monitor mod-ecurity, create a new configuration file /etc/fail2ban/jail.d/apache-modsecurity.conf

[apache-modsecurity]
enabled  = true
port     = http,https
banaction = nftables-multiport[name=modsec, port="80,443", protocol=tcp]
ignoreip = 127.0.0.1/8 
findtime = 86400
bantime = 604800
maxretry = 2