NOTE: This post has been updated to include the requirement of mod_unique_id.
As part of some investigations at work I have been playing around with ModSecurity, the open source web application firewall (WAF), and the standard set of rules provided by OWASP. All our infrastructure is hosted with Amazon AWS so I thought that it would be useful to drop down the steps I took to get this working on a bare bones Amazon Linux box.
Install ModSecurity
You can, of course, compile ModSecurity from the sources but it is easier to install via yum, however, it is part of the epel repo which isn’t enabled by default so you need to run as follows:
sudo yum install mod_security --enablerepo=epel
Now check that the ModeSecurity engine is on:
more /etc/httpd/conf.d/mod_security.conf
And look for the following line:
SecRuleEngine on
Download & configure the OWASP files
The Open Web Application Security Project (OWASP) has created a set of rules for ModSecurity – the OWASP ModSecurity Core Rule Set, whose “goal is to provide an easily “pluggable” set of generic attack detection rules that provide a base level of protection for any web application.”.
You can add these rules to ModSecurity as follows:
cd ~ sudo wget https://github.com/SpiderLabs/owasp-modsecurity-crs/zipball/master sudo unzip -q master cd /etc/httpd sudo mv ~/SpiderLabs-owasp-modsecurity-crs-* modsecurity-crs cd modsecurity-crs sudo cp modsecurity_crs_10_setup.conf.example modsecurity_crs_10_config.conf
Next you need to ensure that the OWASP config files are included when ModSecurity loads. To do this edit mod_security.conf
cd ../conf.d sudo nano mod_security.conf
And add the following lines in the section # ModSecurity Core Rules Set and Local configuration
Include modsecurity-crs/local_rules/*.conf Include modsecurity-crs/modsecurity_crs_10_config.conf Include modsecurity-crs/base_rules/*.conf
The easiest way to do this is with the following SED command:
sudo sed -i "s/Include modsecurity.d\/local_rules\/\*.conf/Include modsecurity.d\/local_rules\/\*.conf\n Include modsecurity-crs\/modsecurity_crs_10_config.conf\n Include modsecurity-crs\/base_rules\/\*.conf/" /etc/httpd/conf.d/mod_security.conf
Next you need to enable mod_unique_id Apache module which is required by mod_security:
sudo sed -i "s/#LoadModule unique_id_module modules\/mod_unique_id.so/LoadModule unique_id_module modules\/mod_unique_id.so/" /etc/httpd/conf/httpd.conf
Finally restart Apache:
sudo service httpd restart
If apache fails to start with a message similar to:
[alert] (EAI 2)Name or service not known: mod_unique_id: unable to find IPv4 address of “ip-x-x-x-x”
Add a line to your instance’s host file:
sudo nano /etc/hosts 127.0.0.1 ip-x-x-x-x localhost
Testing that the rules are working
If you are lucky all this will work with your application without modification, although that isn’t guaranteed of course. The question is how do you safely test that the rules are working. One way is to try with this simple SQL injection attempt on the URL as follows:
http://yourdomain.com/?username=1'%20or%20'1'%20=%20'1&password=1'%20or%20'1'%20=%20'1
If the rules are working then you should be shown a 403 error. You can also check the httpd error log (/var/log/httpd/error_log) to check any messages written there by ModSecurity.
Things to watch out for
During my tests with ModSecurity I discovered a couple of things that you should be aware of. Firstly you need to be testing using a domain name and not directly using the instances IP address. Secondly, ModSecurity and CloudFlare don’t play nicely together. ModSecurity seems to take exception to the cookies that are placed there by CloudFlare. There maybe a workaround for this but none was immediately obvious to me.
Conclusion
Protecting your web application should be a high priority for all and ModSecurity and the OWASP rules give you a good starting point. The issue is that you are relying on a set of rules written by someone else that you (probably) don’t understand and won’t be certain if they are going to conflict with your application. They are also no substitute for ensuring your application itself is as watertight as possible. However, if you have nothing else and cannot afford a commercial WAF then they are a great addition.