Using mod_security 2 with WordPress

Mod_sec 2 is an advanced apache firewall you can used to protect your blog. It’s basically a drop in module for Apache but fairly complex to install and setup. I’ll cover a basic installation and some WordPress specific rules.

Prerequisites: Apache or nginx (the rules below apply to Apache) , command line access to your server. It is also advisable that you have server/network experienced and to not install this on a live site before testing.

Features:

  • Core rules
  • Fully customizable
  • Per-rule transformation options
  • Transaction variables
  • Regular expressions
  • XML support

Mod_sec 2 is not mod_sec! There are many improvements between the versions, they cannot even be really compared. Mod_sec is outdated, so install Mod_Sec 2 which in most cases is not available from the repository due to licensing problems, don’t download the old one by mistake.

That mean you must download mod_sec from http://www.modsecurity.org/download/ and compile it yourself.

Installation based on Debain, depending on the environment the OS might already have some of these packages.:

  • Install g++
    apt-get install g++ 

    - You might have to also upgrade and install build-essential.

  • Install apache apxs
    apt-get install apache2-threaded-dev 
  • Install libxml2
    apt-get install libxml2-dev
  • Install libcurl
    apt-get install libcurl4-gnutls-dev
  • Download mod-sec from http://www.modsecurity.org, put it in a directory , maybe in /apache2, unpack it and run
     /. configure

    - then make.

  • Add or move the mod_security2.so to your apache modules directory and give it the right permissions (644 and whatever user group you want to use)
  • Load the mod_security2.load module for you /mods-available and /mods-enabled
  • Mod-sec needs mod_unique_id to run so check if your apache has it enabled , if not
    a2enmod mod_unique_id
  • Check the rules files, specifically modsecurity_crs_10_config.conf ( the main rules) in your mod-sec directory and enable “debug” mode with a debug log
    SecDebugLog     /yourlogpath..../modsec_debug.log
  • Restart Apache
  • Monitor you mod_sec_debug.log while using your site to see what’s going on

Configure
Configuring Mod_sec can be a full time job, I will keep it basic for WordPress. Out of the box when you have mod_sec running it will break lots of WordPress functionality ,especially if you use plugins.

The two basic things you want to do is monitor your modsec_debug.log and create a whitelist.conf file to tell mod_sec which rules to ignore. For example mod_sec might not allow you to to post an article to your blog, you will see this event in your debug.log with lots of parameters that you can add to your whitelist.conf.

Another configuration option, depending on your download, are the rule files that govern mod_sec’s firewall, they are usually found in /base_rules. Like your whitelist.conf you can add as many rule files with seperate logging and parameters as you would like. Thankfully you can get some of these rules from http://www.owasp.org, gotroot.com, or sourceforge. Several commercial rules packages are also available.

In order to save time, here are some WordPress specific whitelist rules that should allow you to use WordPress without any problems. These are for a base install with no plugins.

<LocationMatch "/wp-admin/post.php">
  SecRuleRemoveById 300015 300016 300017 950907 950005 950006 960008 960011 960904 959006
  SecRuleRemoveById phpids-17
  SecRuleRemoveById phpids-20
  SecRuleRemoveById phpids-21
  SecRuleRemoveById phpids-30
  SecRuleRemoveById phpids-61
</LocationMatch>

<LocationMatch "/wp-admin/admin-ajax.php">
  SecRuleRemoveById 300015 300016 300017 950907 950005 950006 960008 960011 960904 959006
  SecRuleRemoveById phpids-17
  SecRuleRemoveById phpids-20
  SecRuleRemoveById phpids-21
  SecRuleRemoveById phpids-30
  SecRuleRemoveById phpids-61
</LocationMatch>

<LocationMatch "/wp-admin/page.php">
  SecRuleRemoveById 300015 300016 300017 950907 950005 950006 960008 960011 960904
  SecRuleRemoveById phpids-17
  SecRuleRemoveById phpids-20
  SecRuleRemoveById phpids-21
  SecRuleRemoveById phpids-30
  SecRuleRemoveById phpids-61
</LocationMatch>

<LocationMatch "/wp-admin/options.php">
  SecRuleRemoveById 300015 300016 300017 950907 950005 950006 960008 960011 960904 959006
  SecRuleRemoveById phpids-17
  SecRuleRemoveById phpids-20
  SecRuleRemoveById phpids-21
  SecRuleRemoveById phpids-30
  SecRuleRemoveById phpids-61
</LocationMatch>

<LocationMatch "/wp-admin/theme-editor.php">
  SecRuleRemoveById 300015 300016 300017 950907 950005 950006 960008 960011 960904 959006
  SecRuleRemoveById phpids-17
  SecRuleRemoveById phpids-20
  SecRuleRemoveById phpids-21
  SecRuleRemoveById phpids-30
  SecRuleRemoveById phpids-61
</LocationMatch>

<LocationMatch "/wp-content/plugins/">
  SecRuleRemoveById 300015 340151 1234234 340153 1234234 300016 300017 950907 950005 950006 960008 960011 960904 959006
  SecRuleRemoveById phpids-17
  SecRuleRemoveById phpids-20
  SecRuleRemoveById phpids-21
  SecRuleRemoveById phpids-30
  SecRuleRemoveById phpids-61
</LocationMatch>

<LocationMatch "/wp-includes/">
  SecRuleRemoveById 960010 960012 950006 959006
  SecRuleRemoveById phpids-17
  SecRuleRemoveById phpids-20
  SecRuleRemoveById phpids-21
  SecRuleRemoveById phpids-30
  SecRuleRemoveById phpids-61
</LocationMatch>

<LocationMatch "/wp-content/themes/">
  SecRuleRemoveById 340151 340153 1234234 950006 959006
  SecRuleRemoveById phpids-17
  SecRuleRemoveById phpids-20
  SecRuleRemoveById phpids-21
  SecRuleRemoveById phpids-30
  SecRuleRemoveById phpids-61
</LocationMatch>

<LocationMatch "/wp-cron.php">
SecRuleRemoveById 960015
</LocationMatch>

<LocationMatch "/feed">
SecRuleRemoveById 960015
</LocationMatch>

<LocationMatch "/category/feed">
SecRuleRemoveById 960015
</LocationMatch>

If you have any plugins or themes, you will most likely have to add more rules.

For full documention check out http://www.modsecurity.org/documentation/

Update to block brute force login attempts, please test this beforehand.

<Locationmatch "/wp-login.php">
# Setup brute force detection.
# React if block flag has been set.
SecRule user:bf_block "@gt 0" "deny,status:401,log,id:5000135,msg:'ip address blocked for 5 minutes, more than 10 login attempts in 3 minutes.'"
# Setup Tracking. On a successful login, a 302 redirect is performed, a 200 indicates login failed.
SecRule RESPONSE_STATUS "^302" "phase:5,t:none,nolog,pass,setvar:ip.bf_counter=0,id:5000136"
SecRule RESPONSE_STATUS "^200" "phase:5,chain,t:none,nolog,pass,setvar:ip.bf_counter=+1,deprecatevar:ip.bf_counter=1/180,id:5000137"
SecRule ip:bf_counter "@gt 10" "t:none,setvar:user.bf_block=1,expirevar:user.bf_block=300,setvar:ip.bf_counter=0"
</Locationmatch>
#Drop all connections to wp-login
# This has not been tested
<Locationmatch "/wp-login.php">
SecRule REMOTE_ADDR "^\d" drop,phase:1
</Locationmatch>