Introduction

ModSecurity also known as Modsec is a robust Open-source firewall application for Apache web server. A firewall is a utility that protects a network or a software application from abuse and unauthorized access by filtering requests.

This tutorial explains how to install and configure ModSecurity on Apache web servers.

Installing Dependencies

ModSecurity requires some dependencies to work correctly. Let’s install them -

First, upgrade the Ubuntu system.

sudo apt-get -y update
sudo apt-get -y upgrade

Now install the dependencies.

sudo apt-get -y install git libtool dh-autoreconf pkgconf gawk libcurl4-gnutls-dev libexpat1-dev libpcre3-dev libssl-dev libxml2-dev libyajl-dev zlibc zlib1g-dev libxml2 libpcre++-dev libxml2-dev libgeoip-dev liblmdb-dev lua5.2-dev iputils-ping locales apache2 apache2-dev ca-certificates wget

Optional: clean up the Ubuntu caches.

sudo apt-get clean && sudo rm -rf /var/lib/apt/lists/*

Install SSDeep as well (as done here)

cd ~
git clone https://github.com/ssdeep-project/ssdeep
cd ssdeep
./bootstrap
./configure
make
sudo make install

Compiling ModSecurity

Let’s clone ModSecurity from Github.

cd ~
git clone -b v3/master --single-branch https://github.com/SpiderLabs/ModSecurity
cd ModSecurity
git submodule init
git submodule update
./build.sh
./configure
make                # takes ~8 minutes on AWS t2.micro
sudo make install

Compiling ModSecurity-apache connector

To configure it with Apache, we will require ModSecurity-apache connector. Let’s install that as well.

cd ~
git clone https://github.com/SpiderLabs/ModSecurity-apache
cd ModSecurity-apache
./autogen.sh
./configure --with-libmodsecurity=/usr/local/modsecurity
make
sudo make install

Setting up CRS rules

Now, let’s download CRS rule set as well.

cd ~
git clone -b v3.2/dev https://github.com/SpiderLabs/owasp-modsecurity-crs
sudo mv owasp-modsecurity-crs/ /usr/local/

Rename CRS configuration file -

sudo mv /usr/local/owasp-modsecurity-crs/crs-setup.conf.example /usr/local/owasp-modsecurity-crs/crs-setup.conf

Setting up ModSecurity

Now, we need to create a file in the Apache modules directory, so that Apache can know, how to activate ModSecurity.

Create /etc/apache2/mods-enabled/security3.conf file and paste the following contents -

LoadModule security3_module /usr/lib/apache2/modules/mod_security3.so
modsecurity on
modsecurity_rules_file '/etc/apache2/modsec/main.conf'

As you can see, the last line in the above code block reference a file main.conf in a folder modsec. This folder will not be present by default. We need to create that.

sudo mkdir -p /etc/apache2/modsec

Setup ModSecurity configuration file -

# enables Unicode support in ModSecurity
sudo wget -P /etc/apache2/modsec/ https://raw.githubusercontent.com/SpiderLabs/ModSecurity/v3/master/unicode.mapping

sudo wget -P /etc/apache2/modsec/ https://raw.githubusercontent.com/SpiderLabs/ModSecurity/v3/master/modsecurity.conf-recommended
sudo mv /etc/apache2/modsec/modsecurity.conf-recommended /etc/apache2/modsec/modsecurity.conf

Change the SecRuleEngine directive in the configuration to change from the default “detection only” mode to actively dropping malicious traffic.

sudo sed -i 's/SecRuleEngine DetectionOnly/SecRuleEngine On/' /etc/apache2/modsec/modsecurity.conf

Change the location of modsec_audit.log file to Apache log directory.

sudo sed -i 's/SecAuditLog \/var\/log\/modsec_audit.log/SecAuditLog \/var\/log\/apache2\/modsec_audit.log/' /etc/apache2/modsec/modsecurity.conf

To configure ModSecurity to use CRS rule set, put the following text in /etc/apache2/modsec/main.conf file.

Include "/etc/apache2/modsec/modsecurity.conf"
Include "/usr/local/owasp-modsecurity-crs/crs-setup.conf"
Include "/usr/local/owasp-modsecurity-crs/rules/*.conf"

Also enable some Apache modules for better functioning of ModSecurity.

sudo a2enmod unique_id headers rewrite actions dav dav_fs

Now restart the Apache server

sudo systemctl restart apache2

Fixing some common issues

Sometimes, I had encountered errors when ModSecurity was not able to append logs to its log file. I figured out that ModSecurity did not have enough permissions to write that file. We can fix this issue quickly.

First, test if you really have this issue or not.

curl 'http://localhost/?q="><script>alert(1)</script>'
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
<html><head>
<title>403 Forbidden</title>
</head><body>
<h1>Forbidden</h1>
<p>You dont have permission to access / on this server.<br /></p>
<hr>
<address>Apache/2.4.29 (Ubuntu) Server at localhost Port 80</address>
</body></html>

Now go to Apache log directory and check the contents of modsec_audit.log file.

cd /var/log/apache2
tail modsec_audit.log

You should see the following content -

---0LzdyETA---A--
[01/Jul/2019:14:42:41 +0000] 156199216179.666171 127.0.0.1 41824 ip-xxx-xx-xx-xx.ap-south-1.compute.internal 80
---0LzdyETA---B--
GET /?q="><script>alert(1)</script> HTTP/1.1
Host: localhost
User-Agent: curl/7.58.0
Accept: */*

---TqjMwy7h---D--

---TqjMwy7h---F--
HTTP/1.1 403

---TqjMwy7h---H--
ModSecurity: Warning. detected XSS using libinjection. [file "/usr/local/owasp-modsecurity-crs/rules/REQUEST-941-APPLICATION-ATTACK-XSS.conf"] [line "37"] [id "941100"] [rev ""] [msg "XSS Attack Detected via libinjection"] [data "Matched Data: XSS data found within ARGS:q: "><script>alert(1)</script>"] [severity "2"] [ver "OWASP_CRS/3.1.0"] [maturity "0"] [accuracy "0"] [tag "application-multi"] [tag "language-multi"] [tag "platform-multi"] [tag "attack-xss"] [tag "OWASP_CRS/WEB_ATTACK/XSS"] [tag "WASCTC/WASC-8"] [tag "WASCTC/WASC-22"] [tag "OWASP_TOP_10/A3"] [tag "OWASP_AppSensor/IE1"] [tag "CAPEC-242"] [hostname "localhost"] [uri "/"] [unique_id "156198848361.198287"] [ref "v8,27t:utf8toUnicode,t:urlDecodeUni,t:htmlEntityDecode,t:jsDecode,t:cssDecode,t:removeNulls"]
....
....

---TqjMwy7h---I--

---TqjMwy7h---J--

---TqjMwy7h---Z--

If you do not see the following content, and the file is empty or it does not exist, then ModSecurity was not able to open this file for writing. Use the following fix -

# find out the user, Apache is running as
apache_user="$(ps -ef | egrep '(httpd|apache2|apache)' | grep -v `whoami` | grep -v root | head -n1 | awk '{print $1}')"

Now, change the owner of Apache log directory to apache_user.

sudo chown -R $apache_user:$apache_user /var/log/apache2/*

Now, ModSecurity should be able to append logs to the file modsec_audit.log.

Bonus: Enabling JSON logs

Note: Honestly speaking, I was not able to make it work every time. I do not know what is the issue, but it works with some of the installations, and with some of the installations, it just doesn’t log anything to the audit directory. If anyone has managed to make it work consistently, please let me know.

Anyway, if you are like me, who do not like the default ModSecurity log format, ModSecurity provides an option to generate logs in JSON format as well. To enable JSON support, the YAJL library should be installed. We already installed this package when we were installing dependencies, so our ModSecurity setup is compiled with JSON support. Let us now configure ModSecurity to generate JSON logs.

Open the /etc/apache2/modsec/modsecurity.conf file and find the following lines -

SecAuditLogType           Serial
SecAuditLog               /var/log/modsec_audit.log

Once you have found the following lines, replace these lines with the following lines

SecAuditLogFormat         JSON
SecAuditLogType           Parallel
SecAuditLog               /var/log/apache2/modsec_audit.log
SecAuditLogStorageDir     /var/log/apache2/audit/

SecAuditLogFileMode       0644
SecAuditLogDirMode        0755

Restart Apache server

sudo systemctl restart apache2

Now, go to /var/log/apache2/ directory and create audit folder.

cd /var/log/apache2
sudo mkdir audit

# make `apache_user` owner of this directory as well...
sudo chown -R $apache_user:$apache_user /var/log/apache2/audit

Now, ModSecurity should be able to generate JSON logs in this directory. ModSecurity generates logs in the following format -

ubuntu@server:/var/log/apache2$ tree audit
audit
└── 20190701
    ├── 20190701-1132
    │   ├── 20190701-113225-156196094515.868593
    │   └── 20190701-113226-156196094691.154769
    ├── 20190701-1211
    │   ├── 20190701-121122-156196328239.048942
    │   └── 20190701-121122-156196328243.018882

    ....
    ....

Now, your site should be relatively more secure than before.