Block WordPress comment spammers manually


GamesGames

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_IP
FROM
  `wp_comments`
WHERE
  `comment_approved` = 'spam';Code language: SQL (Structured Query Language) (sql)

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)Code language: SQL (Structured Query Language) (sql)

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" />Code language: HTML, XML (xml)

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" />
...
...Code language: HTML, XML (xml)

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>Code language: Apache (apache)

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>Code language: Apache (apache)

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.

foto van Jan Reilink

About the author

Hi, my name is Jan. I am not a hacker, coder, developer or guru. I am merely a systems administrator, doing my daily SysOps/DevOps thing at cldin. With over 15 years of experience, my specialties include Windows Server, IIS, Linux (CentOS, Debian), security, PHP, websites & optimization.

0 0 votes
Article Rating
Subscribe
Notify of
2 Comments
Newest
Oldest Most Voted
Inline Feedbacks
View all comments
1 month ago

Recently, Jeff Starr wrote about blocking IP addresses posting random string comment spam. That post reminded me about my own older post about blocking WordPress comment spammers manually. With just a few manual steps, you create your own little blocklist for WordPress in either a .htaccess or web.config file. Here are the IP addresses I’m currently blocking. Note, this list can get long (loooonnggg).

.wp-block-code {
border: 0;
padding: 0;
}

.wp-block-code > div {
overflow: auto;
}

.shcb-language {
border: 0;
clip: rect(1px, 1px, 1px, 1px);
-webkit-clip-path: inset(50%);
clip-path: inset(50%);
height: 1px;
margin: -1px;
overflow: hidden;
padding: 0;
position: absolute;
width: 1px;
word-wrap: normal;
word-break: normal;
}

.hljs {
box-sizing: border-box;
}

.hljs.shcb-code-table {
display: table;
width: 100%;
}

.hljs.shcb-code-table > .shcb-loc {
color: inherit;
display: table-row;
width: 100%;
}

.hljs.shcb-code-table .shcb-loc > span {
display: table-cell;
}

.wp-block-code code.hljs:not(.shcb-wrap-lines) {
white-space: pre;
}

.wp-block-code code.hljs.shcb-wrap-lines {
white-space: pre-wrap;
}

.hljs.shcb-line-numbers {
border-spacing: 0;
counter-reset: line;
}

.hljs.shcb-line-numbers > .shcb-loc {
counter-increment: line;
}

.hljs.shcb-line-numbers .shcb-loc > span {
padding-left: 0.75em;
}

.hljs.shcb-line-numbers .shcb-loc::before {
border-right: 1px solid #ddd;
content: counter(line);
display: table-cell;
padding: 0 0.75em;
text-align: right;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
white-space: nowrap;
width: 1%;
}
$ grep -c 'Require not ip' .htaccess
313
Code language: Apache (apache)
That’s 313 unique IP addresses posting spam comments here on Sysadmins of the North. Consider this a public pillory. Unlike Jeff, I do remove the comments, so there are no samples saved. I have database backups available, so it’s easily restored.
Read how to restore single MySQL table from a full mysqldump backup file.
Without further ado, here’s the list (tip, use grep 'Require not ip' .htaccess | cut -d " " -f 4 | sort -n):
1.169.65.70
2a01:4f9:2a:9a7::2
2a03:b0c0:3:d0::18f3:3001
5.165.138.66
5.172.177.218
5.62.43.147
5.62.43.182
8.219.211.176
8.219.76.117
14.186.36.41
20.102.66.0
23.105.157.157
23.105.157.239
23.105.157.30
23.108.233.191
23.108.45.80
23.108.48.124
23.154.177.5
23.19.248.162
23.231.32.228
23.236.148.139
23.250.54.189
23.81.227.124
23.81.227.59
23.81.231.136
23.83.89.228
23.90.29.9
23.90.30.148
23.90.30.70
23.90.43.45
23.94.171.163
23.95.239.56
34.212.159.85
37.139.53.199
37.145.130.234
37.204.161.9
37.220.87.30
37.46.115.24
38.153.112.165
38.153.131.0
38.153.141.27
38.154.132.47
44.200.17.20
45.10.164.233
45.114.14.238
45.120.51.144
45.126.185.232
45.127.250.160
45.130.60.74
45.131.194.207
45.136.155.91
45.139.124.38
45.192.131.207
45.43.65.177
45.70.236.194
45.72.67.12
45.87.249.76
45.95.29.242
45.95.39.59
46.21.146.150
46.53.243.51
46.8.111.229
49.206.121.204
49.36.89.118
50.3.137.232
54.153.80.45
62.171.129.108
62.210.80.33
62.4.24.100
64.137.92.179
64.43.90.185
65.109.172.58
66.115.149.83
66.115.181.195
66.42.52.115
68.71.249.153
69.147.248.68
76.108.0.152
77.245.2.148
79.139.183.195
79.181.164.15
83.31.253.64
88.103.235.229
88.147.153.69
88.147.231.47
88.99.218.174
89.238.183.237
91.108.177.112
91.108.177.150
91.208.184.9
91.219.212.195
91.243.191.237
91.244.42.203
92.205.161.205
93.120.32.192
93.124.126.153
94.26.31.115
95.181.151.86
95.216.105.155
95.79.224.133
101.255.151.17
102.165.51.172
103.121.122.184
103.14.226.100
103.14.226.101
103.142.21.41
103.146.23.202
103.149.86.249
103.149.86.25
103.153.69.134
103.153.69.145
103.176.20.13
103.196.37.111
103.48.68.34
103.80.86.100
103.87.142.138
104.144.26.58
104.144.98.186
104.149.136.105
104.160.17.171
104.160.17.205
104.160.17.224
104.160.17.247
104.160.17.37
104.232.211.9
104.239.126.0
104.239.97.89
107.150.31.92
107.150.84.111
107.172.146.137
107.172.146.179
107.174.148.4
107.174.238.96
107.174.251.162
107.175.34.53
107.175.37.114
107.181.112.187
107.181.152.162
108.184.160.113
108.62.124.161
109.195.85.80
109.69.108.83
109.70.100.27
117.160.250.137
117.214.73.246
117.252.236.31
119.160.59.222
119.59.115.161
124.122.197.206
125.228.230.78
128.1.184.212
135.181.188.233
138.117.160.34
138.128.40.146
139.162.2.219
139.28.223.56
139.99.121.192
140.83.49.207
141.226.72.198
142.132.203.69
149.200.184.73
152.58.90.187
152.58.92.7
154.12.142.93
154.13.102.93
154.13.103.91
154.16.4.124
154.29.111.252
154.30.246.179
154.3.222.164
154.47.28.72
154.84.132.12
154.84.132.130
154.84.132.39
154.84.132.56
154.84.132.74
154.84.132.82
154.84.132.89
154.84.133.121
154.84.133.147
154.84.133.148
154.84.133.65
154.85.101.29
154.92.123.182
155.138.156.38
156.146.36.66
156.238.5.173
157.254.202.223
161.117.9.99
162.212.174.105
162.212.174.18
162.212.174.55
164.90.174.185
165.231.105.42
165.231.108.220
166.88.232.101
166.88.232.12
166.88.232.127
166.88.232.51
166.88.232.58
166.88.232.92
166.88.248.120
166.88.248.127
166.88.248.43
166.88.248.54
166.88.248.65
166.88.248.68
166.88.248.93
168.151.243.57
168.90.199.228
168.91.8.75
171.224.180.26
172.104.163.82
172.104.70.19
172.245.107.238
172.245.107.242
172.245.171.78
172.245.229.85
172.245.250.164
172.245.34.24
172.245.64.120
172.245.73.13
172.245.73.79
172.245.87.80
172.94.53.2
173.213.84.142
173.44.153.174
173.44.153.212
173.44.164.162
173.44.167.44
173.44.213.133
173.44.222.123
173.44.223.44
175.100.60.212
175.171.147.181
176.31.115.13
178.159.37.55
178.239.173.48
180.190.99.47
181.177.102.73
183.111.79.2
183.17.127.10
185.102.112.137
185.121.138.185
185.140.249.71
185.205.18.2
185.206.249.76
185.220.101.16
185.220.101.161
185.220.102.253
185.220.103.117
185.220.103.120
185.242.92.212
185.243.218.61
185.47.88.150
185.65.134.164
186.179.6.142
188.130.185.41
188.132.174.221
188.74.182.6
190.113.42.162
191.101.114.232
191.102.143.210
191.96.181.83
192.111.130.5
192.126.158.203
192.126.232.78
192.186.145.52
192.210.144.73
192.210.201.241
192.3.143.79
192.3.188.203
192.40.95.123
192.42.116.209
192.42.116.210
194.169.217.48
194.34.248.138
194.5.53.40
194.88.152.40
195.154.61.146
195.176.3.19
196.196.247

6 years ago

nice article and discuss in detail

2
0
Would love your thoughts, please comment.x
()
x