Block WordPress comment spammers manually

The less spammers hit your WordPress blog, the better your blog performs, is one of my opinions. A second is, the less unnecessary plugins you use on your WordPress blog, the better. So, a little while ago I decided to remove plugins like Stop Spammer Registration Plugin and do its work myself.
Published on Saturday, 30 November 2013

The less spammers hit your WordPress blog, the better your blog performs, is one of my opinions. A second is, the less unnecessary plugins you use on your WordPress blog, the better. So, a little while ago I decided to remove plugins like Stop Spammer Registration Plugin and do its work myself. Here is why & how:

As long as Akismet catches the spam, I can block the IP addresses myself. Plus, I might be able to see some trends like IP ranges that spam a lot, new IP ranges, new spam templates being used, and so on. I like that :).

Blocking WordPress spammers manually may sound very time consuming, but it really isn't. You mostly have to wait for the spam. Here on Saotn.org, Akismet catches about 98.53% of the spam, so I don't have to mark a lot of comments as spam. Further, we automate a lot of tasks with MySQL and Notepad++ (which is my text editor of choice on Windows) or VIM on your Linux Bash shell.

There is more than one way to block comment spammers on your WordPress blog. As you might know, I host my website on the IIS web server platform. Therefor we need the Dynamic IP Address Restrictions module.

If you are on Apache, you can use mod_rewrite instead.

Find spammer IP addresses in MySQL database

All real live data here. To find IP addresses belonging to spammers in your database:

WordPress saves the comments in the table prefix_comments. We can easily use MySQL to list all IP addresses that match our requirements. Akismet uses the word spam in the column comment_approved.

Knowing that, our query becomes:

SELECT DISTINCT  comment_author_IPFROM  `wp_comments`WHERE  `comment_approved` = 'spam';

We use SELECT DISTINCT to list unique IP addresses. In my case, this lists the following IP addresses:

+---------------------------+| comment_author_IP         |+---------------------------+| 37.115.188.27             || 5.135.200.88              || 173.213.97.191            || 175.44.17.43              || 64.120.171.172            || 173.213.99.149            || 190.200.17.249            |[...]| 213.184.99.7              || 107.6.159.30              || 178.216.54.220            || 198.143.145.182           || 173.232.105.133           || 151.237.177.159           || 2002:7180:2e5d::7180:2e5d || 96.127.185.149            || 5.157.45.154              || 60.168.7.171              || 50.2.194.250              || 60.168.6.2                |[...]| 218.85.145.245            || 5.135.200.91              || 74.221.223.195            || 59.60.123.156             || 198.50.189.122            |+---------------------------+452 rows in set (0.00 sec)

Did you notice the one IPv6 address? All IP addresses are presumed innocent until proven guilty :-) Look up their reputation at SenderBase.org.

Preparing the IP addresses for web.config with Notepad++

You might think it's a lot of work to copy/paste each address into the web.config format:

<add ipAddress="aa.bbb.cc.ddd" allowed="false" />

but it isn't. Notepad++ has a handy search and replace function (shortcut key: CTRL H).

  1. first, find one space ("") and replace 'all' with nothing. All spaces are gone;
  2. second, find the pipe ("|") and replace 'all' with nothing. All pipes are gone too;
  3. third, use the Regular Expression option to execute the following search and replace:
  • find what: ^(.*)$
  • Replace with: <add ipAddress="\1" allowed="false" />
  • The \1 is a back reference to the IP address found in (.*) and we have our web.config format ready!

Add IP addresses to Dynamic IP Address Restrictions web.config

The partial output of our Notepad++ actions above is:

<add ipAddress="107.6.159.30" allowed="false" />
<add ipAddress="108.163.221.85" allowed="false" />
<add ipAddress="108.163.247.19" allowed="false" />
<add ipAddress="108.163.248.68" allowed="false" />
<add ipAddress="108.163.248.70" allowed="false" />
<add ipAddress="108.177.194.114" allowed="false" />
<add ipAddress="108.178.5.100" allowed="false" />
<!-- ...... -->

We add this to our web.config file under <security> <ipSecurity>, just copy and paste. Now all those IP addresses are blocked and denied access to my blog.

Block IP addresses in Apache 2.4.6+ .htaccess module mod_authz_core

Apache 2.4.6+ uses a new module mod_authz_core for authorization and blocking. The Apache mod_authz_core documentation writes:

This module provides core authorization capabilities so that authenticated users can be allowed or denied access to portions of the web site. mod_authz_core provides the functionality to register various authorization providers. It is usually used in conjunction with an authentication provider module such as mod_authn_file and an authorization module such as mod_authz_user. It also allows for advanced logic to be applied to the authorization processing.

Apache Module mod_authz_core

Because it's really different from the Apache 2.2 Access Control, it requires a syntax change (and mindset). WordPress plugin editors take note: the new syntax is:

<RequireAll>
  Require all granted
  # IP address to block in Apache
  Require not ip 198.51.100.25
  # ...
</RequireAll>

To create an Apache .htaccess blacklist use the following steps:

  • connect to your database - use SSL wherever available for MySQL connections:
    • mysql --ssl-mode=PREFERRED -h db_hostname -u user_name -p --database=db_name, or
    • mysql --ssl-mode=REQUIRED -h db_hostname -u user_name -p --database=db_name
  • select all as spam marked comments:
    • SELECT DISTINCT comment_author_IP FROM wp_comments WHERE comment_approved = 'spam';
  • save the result in a file, and use VIM to transform it into a compatible .htaccess format:
    • :%s/ //g # remove spaces
    • :%s/|//g # remove pipes
    • :%s/^\(.*\)$/Require not ip \1/g # Apache 2.4.6+ .htaccess module mod_authz_core

Blocking IP addresses with Apache mod_rewrite

If your blog is on a Apache webserver, you can use mod_rewrite to block the IP addresses. The syntaxis is:

<IfModule mod_rewrite.c>
  RewriteEngine On
  RewriteCond %{REMOTE_ADDR} ^107\.6\.159\.30 [OR]
  RewriteCond %{REMOTE_ADDR} ^108\.163\.221\.85 [OR] 
  RewriteCond %{REMOTE_ADDR} ^108\.163\.247\.19 [OR]
  # ...
  # ...
  RewriteRule ^(.*)$ - [F,L]
</IfModule>

When, in time your web.config or .htaccess file grows (and becomes huge), it is necessary to start using rewrite maps:

And of course you can start blocking whole IP ranges. Don't forget to delete the spam comments and meta data from your database afterwards.

it's better to use mod_authz_core Require All blocks like above than all these rewrite conditions. Read the WordPress .htaccess security best practices in Apache 2.4.6+.

Create your own local web blacklist of comment spammers in PHP

Use Project Honey Pot and Stop Forum Spam to block spammers on your website

Beside these steps above, it is also possible to automatically filter web traffic with one or multiple blacklists. Project Honey Pot for instance. The IP address of every visitor is looked up in the Project Honey Pot database. If it's listed there, access to the website is denied. I've written a PHP implementation that works with both IIS web.config and Apache mod_rewrite:

Disable WordPress comments

Learn how to disable WordPress comments on individual posts or globally.