Blocking comment spam using ModSecurity and realtime blacklists

Spammers are known to use compromised hosts from all over the world to send their messages. Many people are blocking or scoring email spam based on realtime blacklist (rbl), which contain ipaddresses of these known bad hosts. In my experience this works fairly well for email. A while ago I noticed in the ModSecurity documentation for version 2.0 that ModSecurity features an operator called rbl, that can be used to check the ipaddress of a visitor with a rbl. So I decided to see if I could use the realtime blacklists to prevent comment spam on my blog. Turns out this works great! In this post I’ll show how to get it working.

Recently I switched this blog from ModSecurity 1.9.4 to 2.0.4. Since then I’ve updated it to 2.1.0rc7, but this post should apply to 2.0.4 without modifications.

The basic syntax of the rbl rule is as follows:

SecRule REMOTE_ADDR “@rbl bl.spamcop.net”

However, I would not recommend just using this rule because it would do a lookup of the remote ipaddress for every request made to your site. This will totally destroy the performance of your site. So I decided to inspect only POST request, since posting comments requires… POST ;-)

SecRule REQUEST_METHOD “^POST$” “log,deny,chain,msg:’LOCAL comment spammer at rbl bl.spamcop.net'”
SecRule REMOTE_ADDR “@rbl bl.spamcop.net”

For some reason unclear to me, this doesn’t work. With this rule the rbl is never ever checked. I could see that just the rbl rule would work, so it must be something in the combination of the rules. Luckily, I found a workaround:

SecRule REQUEST_URI “^/blog/wp-(comments-post|trackback).php$” “log,deny,chain,msg:’LOCAL comment spammer at rbl bl.spamcop.net'”
SecRule REMOTE_ADDR “@rbl bl.spamcop.net”

So I tried some variations of rules and the above rule turns out to work just fine. It doesn’t look for the POST method, but instead just looks at the URI’s at which a comment poster posts.

After using this with a large number of blacklists, seven to be precise, I can conclude it is very effective. The last few days 144 attempts were blocked, while 22 still came through. I have manually inspected all blocked comments and so far not a single false positive has occured.

Even though I have configured seven different blacklists, only three are actually get hits, so I will paste those below:

SecRule REQUEST_URI “^/blog/wp-(comments-post|trackback).php$” “log,deny,chain,msg:’LOCAL comment spammer at rbl list.dsbl.org'”
SecRule REMOTE_ADDR “@rbl list.dsbl.org”


SecRule REQUEST_URI “^/blog/wp-(comments-post|trackback).php$” “log,deny,chain,msg:’LOCAL comment spammer at rbl bl.spamcop.net'”
SecRule REMOTE_ADDR “@rbl bl.spamcop.net”


SecRule REQUEST_URI “^/blog/wp-(comments-post|trackback).php$” “log,deny,chain,msg:’LOCAL comment spammer at rbl sbl-xbl.spamhaus.org'”
SecRule REMOTE_ADDR “@rbl sbl-xbl.spamhaus.org”

Good luck fighting off the spam! :-)

10 thoughts on “Blocking comment spam using ModSecurity and realtime blacklists

  1. About your attempt to only lookup IP addresses doing POST requests. The rules are correct. I am guessing you are having trouble because, unless rules are explicitly configured differently, default transformation functions from the context are applied to arguments (REQUEST_METHOD in this case) before the operator is run. By default ModSecurity will perform the following transformations: lowercase, replaceNulls, and compressWhitespace. So it’s either those or the ones specified with SecDefaultAction. If my hunch is correct than the first rule is not matching because a lowercase version of REQUEST_METHOD (“post”) is being compared to “^POST$”. The solution is to add “t:none” to the list of actions of the first rule. This will cancel any transformation functions specified in the context.

    On a similar note, your rules using REQUEST_URI are easy to evade if spammers send their requests to “/blog//wp-comments-post.php” (notice the two forward slashes). Again, this is because you are using the default transformations and they are not adequate for the job. Adding “t:normalisePath” to the list of actions fixes this problem.

    I always recommend enabling the debug log at level 9, especially if you are just starting with ModSecurity. For example, this is how you would find out exactly how input data is transformed before the operators are applied. ModSecurity will log variable values after each transformation takes place.

  2. Thank you for this explanation Ivan. I have changed the rules according to your suggestions and am now waiting for new commentspam attempts to occur. I will update the blog when I know more!

  3. This works for me:

    SecRule REQUEST_METHOD “^((?:post|head))$” “t:none,t:lowercase,log,chain,deny,msg:’IP address that has abusable vulnerabilities: web.dnsbl.sorbs.net'”
    SecRule REMOTE_ADDR “@rbl web.dnsbl.sorbs.net”

  4. Thank you !!!!!!

    Thank you indeed. The latest updated information about mod_security and blacklists I was finding on other websites dated from 2006 and was completely useless (links to lists that not exist, rules for mod_security 1, etc.).

  5. When you write “^/blog/wp-(comments-post|trackback).php$”, what is rationale for the final “$”? My rules doesn’t match with my URIs if I write this final $. Without it, they work perfectly. Perhaps am I misunderstanding something?

  6. The idea was to exactly match on the filenames, and not on anything else. I think if you replace REQUEST_URI by REQUEST_FILENAME it should still work. REQUEST_URI also includes the QUERY_STRING and thats probably why it didn’t work for you…

  7. Thanks for the rules. Feel free to use my blacklist at blacklist.junkemailfilter.com. It seems to work rather well. It’s my email blacklist but it’s mostly spambots.

  8. Pingback: Mod Security for Apache – Web Server Smart Firewall

  9. Hi,

    First, thanks for sharing this. You don’t have the “Notify me when someone responds to my comment” feature on this blog, so could you pls write to my email if you reply.

    I am looking for a rule set that works on not just REMOTE_ADDR, but looks at the *content* of form submissions. Will the rule above by “Jens” cover the posted content too?

    Thanks!

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s