System training with ModSecurity (avoiding false positives)

When using ModSecurity the system will trigger any sort of exception, giving false positives in many kind of situations. This article enumerates those exceptions we have found useful in every day’s life.

All these rules must be put in a specific file:

vi /etc/httpd/modsecurity-crs/activated_rules/modsecurity_crs_48_local_exceptions.conf

Add the following lines:

#Avoid Google Analytics false positives:
SecRuleUpdateTargetById 981172 !REQUEST_COOKIES:'/^__utm/'
SecRuleUpdateTargetById 950901 !REQUEST_COOKIES:'/^__utm/'

SecRule REMOTE_ADDR "^$" "phase:1,t:none,nolog,allow,ctl:ruleEngine=Off,ctl:auditEngine=Off,id:9999"

#Request Missing an Accept Header -  Allow for Google Reader
SecRuleRemoveById 960015

#Avoid checks on some wordpress related posted arguments:
SecRuleUpdateTargetById 981173 "!ARGS:_wp_http_referer"
SecRuleUpdateTargetById 981173 "!ARGS:_wp_original_http_referer"
SecRuleUpdateTargetById 981173 "!ARGS:referredby"

#Avoid special encoding chars false positives
SecRuleRemoveById 960024

Another good way to avoid false positives is to set thresholds in the proper way: you have to edit the config file and set the score levels.

vi /etc/httpd/modsecurity-crs/modsecurity_crs_10_config.conf

than look at the lines

SecAction \
  "id:'900003', \
  phase:1, \
  t:none, \
  setvar:tx.inbound_anomaly_score_level=5, \
  setvar:tx.outbound_anomaly_score_level=4, \
  nolog, \

You have to put something different into the tx.inbound_anomaly_score_level and tx.outbound_anomaly_score_level: values of 15 and 12 are ok!

SecAction \
  "id:'900003', \
  phase:1, \
  t:none, \
  setvar:tx.inbound_anomaly_score_level=15, \
  setvar:tx.outbound_anomaly_score_level=12, \
  nolog, \

Then a restart…. and it’s up and running!

/etc/init.d/httpd restart

ModSecurity and Logrotate

As you may have read, we are using ModSecurity to filter out bad HTTP requests on our servers. In this little post you will learn how to integrate ModSecurity and Logrotate to work effectively together.

One of this technology’s fallback is that it logs an incredible amount of data to /var/log/modsec_audit.log (all this data is useful for debugging purposes, so we do not want to avoid logging at all)… The size of this file at the end of the day is HUGE…

To avoid this we have created a new logrotate script that handles all the work. To install it under CentOS type

vi /etc/logrotate.d/modsecurity

then insert the following lines:

/var/log/modsec_audit.log {
    rotate 1
        /sbin/service httpd reload > /dev/null 2>/dev/null || true

No need to restart, it does everything when logrotate runs by itself…

To complete the scenario, let’s have a look to the lines we have written:

rotate 1

tells logrotate to keep ONLY 1 copy of the file. This means that today at 4 am logrotates deletes the file modsec_audit.log.1.gz and creates a new one starting from modsec_audit.log.


means that we do want a compressed archive of the file

    /sbin/service httpd reload > /dev/null 2>/dev/null || true

forces a restart of Apache.

ModSecurity Sql Injections prevention

Today we had a long day, some nice people were tryin’ some sql injections in our applications. Unfortunately they got it quite easy against an old web application (sic). Our alerting system rang since 14.00 and from then we had a very intense afternoon…

The situation is easy to understand:

  • PHP is not such strong-typed language
  • sometimes the lazy programmer forgets to cast variables against their types…
  • and then somebody else finds a good way to retrieve informations from the database (and maybe from the system)

After the first few minutes-panic, we realized that the solution was to install ModSecurity on our system (we do run some LAMP machines, so we needed a module for Apache).

ModSecurity 2.7.7 on Scientific Linux 6.4


The ModSecurity’s installation process on Scientific Linux 6.4 is quite easy, first of all you have to install the necessary dependencies:

yum install libxml2 libxml2-devel httpd-devel pcre-devel curl-devel


Than you can proceed with ModSecurity itself:

cd /usr/src
wget --no-check-certificate
tar -xzvf modsecurity-apache_2.7.7.tar.gz
cd modsecurity-apache_2.7.7
make install
cp modsecurity.conf-recommended /etc/httpd/conf.d/modsecurity.conf
cp unicode.mapping /etc/httpd/conf.d/unicode.mapping


ModSecurity needs a few rules to work on… so you have to install them and activate all…

cd /etc/httpd/
wget -O SpiderLabs-owasp-modsecurity-crs-2.2.8-8.tar
tar -xvf SpiderLabs-owasp-modsecurity-crs-2.2.8-8.tar
mv SpiderLabs-owasp-modsecurity-crs-7528b8b modsecurity-crs
cd modsecurity-crs
cp modsecurity_crs_10_setup.conf.example modsecurity_crs_10_config.conf
for f in `ls base_rules/` ; do ln -s /etc/httpd/modsecurity-crs/base_rules/$f activated_rules/$f ; done
for f in `ls optional_rules/ | grep comment_spam` ; do ln -s /etc/httpd/modsecurity-crs/optional_rules/$f activated_rules/$f ; done

General configuration

Then you can proceed to configure the Apache module:

vi /etc/httpd/conf.d/modsecurity.conf

Add the following line to the top of the file:

LoadModule security2_module modules/

Activate the engine modifying the SecRuleEngine directive setting it On:

SecRuleEngine On

Put the following lines at the end of the file:

SecPcreMatchLimit 150000
SecPcreMatchLimitRecursion 150000
<IfModule security2_module>
    Include /etc/httpd/modsecurity-crs/modsecurity_crs_10_config.conf
    Include /etc/httpd/modsecurity-crs/activated_rules/*.conf

Last, but very important, you have to add mod_unique_id to the apache conf file. Mod_unique_id is normally shipped with the apache package, but you have to activate it putting the right code in the right place… First enter the apache conf file with vi:

vi /etc/httpd/conf/httpd.conf

Put the following line (if not already there):

LoadModule unique_id_module modules/


ModSecurity is very polite: it does what you tell it to do: after a few days you will discover a word of false positives… and this not so good….

Accordingly with Spiderlabs’ Blog there are two ways to let ModSecurity work:

  • Traditional Detection Mode (which is the default)
  • Anomaly Scoring Detection Mode – Collaborative Rules

I strongly encourage the use of the second one…. to activate it you have to follow these few steps.

First open the modsecurity_crs_10_config.conf file:

vi /etc/httpd/modsecurity-crs/modsecurity_crs_10_config.conf

Identify the following line:

SecDefaultAction "phase:1,pass,log"

and substitute it with

SecDefaultAction "phase:2,pass,log,noauditlog"

(the “log, noauditlog” part is to avoid ModSecurity logging to /var/log/modsec_audit.log)

Then identify the following lines:

#SecAction \
"id:'900004', \
phase:1, \
t:none, \
setvar:tx.anomaly_score_blocking=on, \
nolog, \

and uncomment the first one:

SecAction \
"id:'900004', \
phase:1, \
t:none, \
setvar:tx.anomaly_score_blocking=on, \
nolog, \

A restart…

After this you can restart apache and take a look at log files

/etc/init.d/httpd restart && tail -f /var/log/httpd/error_log

If you’ve done all right, you should read something like

[...] ModSecurity for Apache/2.7.7 ( configured.
[...] ModSecurity: APR compiled version="1.2.7"; loaded version="1.2.7"
[...] ModSecurity: PCRE compiled version="8.10"; loaded version="8.10 2010-06-25"
[...] ModSecurity: LIBXML compiled version="2.6.26"

That’s it! Enjoy your brand new protection system!