I set up mod_security, a web firewall for Apache, to deal with comment and trackback spam on my server. This isn’t a complete guide to mod_security, just the information I wish I had when I started.

I’m using mod_security because my server has lots of different blogging tools installed, and there’s no way to centrally protect them all. This won’t take care of all comment or trackback spam, but I’m hoping it will greatly reduce the amount we get. Also, I’m expecting mod_security to be faster than other tools since it stays in memory and doesn’t hit the database.


Installing mod_security was a snap under Apache 2. I downloaded the source, went into the apache2 directory, ran sudo /usr/sbin/apxs -cia mod_security.c and restarted Apache. Super easy.

Next I copied the included example config to /etc/httpd/conf.d/mod_security.conf, since Apache is already configured to include /etc/httpd/conf.d/*.conf and restarted Apache.

Then I got blacklist_to_modsec.pl, which is a utility that takes Jay Allen’s master blacklist file and turns it into a set of mod_security rules. While the documentation for blacklist_to_modsec.pl says it has Jay Allen’s URLs as defaults, I had to manually add them. At line 414 I changed

# @master_sources - OPTIONAL list of urls or file paths to pull blacklist data from
my @master_sources = (
);
# @update_sources - OPTIONAL list of urls or file paths to pull blacklist update data
# from
my @update_sources = (
);

to


# @master_sources - OPTIONAL list of urls or file paths to pull blacklist data from
my @master_sources = (
'http://www.jayallen.org/comment_spam/blacklist.txt'
);
# @update_sources - OPTIONAL list of urls or file paths to pull blacklist update data
# from
my @update_sources = (
'http://www.jayallen.org/comment_spam/blacklist_changes.txt'
);

I also changed @restart_commands to work on my server and I left $mt_dir blank since it seems to only work with Movable Type 3 and I’m still on Movable Type 2. To get mod_security to read these rules I changed /etc/httpd/conf.d/mod_security.conf to add Include /path/to/my/blacklist_rules.txt and restarted apache.

I thought I was done, and a test on Movable Type confirmed it. I told Les to try it out on his recently-migrated-to-WordPress blog, and found out that mod_security didn’t consider PHP “dynamic”, and since it was configured to only worry about dynamic files it wasn’t filtering requests to PHP!

In the docs, they suggest changing AddType application/x-httpd-php .php to AddHandler application/x-httpd-php .php to fix this. The only problem was that for some unknown reason my Apache came configured with PHP thusly:

<Files *.php>
SetOutputFilter PHP
SetInputFilter PHP
LimitRequestBody 8388608
</Files>

Since I don’t know why it’s configured that way, I’m not inclined to break stuff by changing it to an AddHandler. My solution was to add SecFilterEngine On inside the <Files *.php> section.

I am happy with the ease of use of mod_security so far, except for the weird non-dynamic nature of PHP. I expect that this will reduce the headache of comment spam and trackback spam for everyone on the server. The only other things I would like to do are to integrate my blacklists with the blogging tools on the server (so that when a comment is marked as spam, it gets added to the blacklist) and a way to block hosts using open proxies.

[Update 2005-09-29] Apache was refusing to restart, leaving this error in the logs:
[error] (28)No space left on device: mod_security: Could not create modsec_auditlog_lock
This was because mod_security wasn’t cleaning up its semaphores for some reason. My solution was to add this to the stop function in my init script:
ipcs | perl -ane '`ipcrm -s $F[1]` if $F[2] == "apache" and $F[1] =~ /d+/ and $F[1] != 0'<br/ >
This removes any semaphores left by Apache when ever /etc/init.d/httpd stop or /etc/init.d/httpd restart are called.

[Update 2005-09-30] File uploads in desktop blogging tools were causing the server to nearly lock up. The file uploads are being scanned by each regular expression created by blacklist_to_modsec.pl, which are base64 encoded XML-RPC packets. Currently there are 3111 rules in my blacklist, which means each file will be scanned three thousand times, no wonder the server was going crazy! The solution I came up with (which I don’t believe is ideal) was to allow XML-RPC and SOAP packets without having to go through the blacklist rules. I do this because I’m not using mod_security to protect web applications from malicious users, but trying to block a bunch of known-bad strings. This will make mod_security a less effective security tool!

# Don't scan XML-RPC or SOAP packets for blacklist matches because they
# aren't comment spammers (assumption) and XML-RPC and SOAP packets can be
# huge, which kills the processor.
SecFilterSelective POST_PAYLOAD 
"^s*<?xml version="1.0"?>[^<]+<methodCall>" allow
SecFilterSelective POST_PAYLOAD 
"^s*<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">" 
allow
# Include MT-Blacklist imported rules
Include /etc/httpd/conf/blacklist_rules.txt

,

Leave a Reply