I recently installed mod_security2 on my personal Web server to block out the most annoying referral spam. It blocked the worst offenders. Then I found that mod_security also included the ability to block all access from sites in a DNS-based RBL. This would further reduce my comment and referral spam problems, at the cost of making the site slightly slower. There are also rules to block SQL injection attacks and other known attack vectors. If you’re trying to read this from a machine on DNS blacklists, stop reading and go get yourself off the blacklist.
The RBL rules aren’t in the base FreeBSD package. They’re in the newer mod_security2 ruleset, available from mod_security’s Sourceforge download page. Get the newest file.
Move your existing rules to a safe place, and put the new rules where the old rules were. Do not delete your old rules, you’ll want them for reference. In my case, the active rules directory is /usr/local/etc/apache22/Includes/mod_security2. I moved the existing directory to /usr/local/etc/apache22/Includes/old-mod_security2, created a new mod_security2 directory, and unzipped the rules it there.
The rules directory contains an example rule file, modsecurity_crs_10_config.conf.example. Apache will read any file that ends in .conf as a config file, so copy (not move) that example to modsecurity_crs_10_config.conf. Edit that file to include changes from the original setup, e.g.:
SecRuleEngine On
SecDataDir /var/run/modsecurity
Copy your referer.conf referrer blacklist into the new rules directory. Then reload Apache. If Apache won’t restart, read the error messages and correct them.
Now that you have the base rules upgraded, you can add rules from the optional_rules directory. I specifically want the comment spam blocking, so I copied modsecurity_crs_42_comment_spam.conf to the main directory and reloaded Apache.
Then use wget to test my work, using one of the less offensive referral spam sites as a referrer. (I’ve changed the name of the site to avoid giving them any more links.)
avarice/tmp$ wget http://www.michaelwlucas.com/ --referer=http://www.fishingscum.com
–2011-01-04 17:04:06– http://www.michaelwlucas.com/
Resolving www.michaelwlucas.com (www.michaelwlucas.com)… 198.22.63.8
Connecting to www.michaelwlucas.com (www.michaelwlucas.com)|198.22.63.8|:80… connected.
HTTP request sent, awaiting response… 500 Internal Server Error
2011-01-04 17:04:06 ERROR 500: Internal Server Error.
That’s what I want.
As I had to take the time to upgrade, I wanted to also get a log of what hits I was blocking. This only took adding two lines to the configuration:
SecDebugLogLevel 1
SecDebugLog /var/log/modsecurity.log
My wget request generated this log entry:
[04/Jan/2011:17:04:06 --0500] [www.michaelwlucas.com/sid#801948060][rid#801aa20a0][/][1] Access denied with code 500 (phase 2). Pattern match "fishingscum" at REQUEST_HEADERS:Referer. [file "/usr/local/etc/apache22/Includes/mod_security2/referer.conf"] [line "35"]
Setting SecDebugLogLevel to 2 gave me details on how mod_security2 processed its logs. That will be useful if I ever have to write my own mod_security2 rules. I suspect that if I have to do that, though, I’m solving the wrong problem.
One interesting thing I saw here was how the log statement in mod_security2 rules is applied. If you use the log keyword in a rule, a log message appears in the standard Apache access and error logs as well as the mod_security2. If you do not use the log statement, a message appears in the modsecurity log but not in the Apache logs. An anti-referral-spam rule should look like this:
SecRule REQUEST_HEADERS:REFERER "ezinearticles" deny,status:500
24 hours later, WordPress shows only 5 comments in my anti-spam queue. Another annoyance quashed.
UPDATE: More here.