WordPress へのspam 投稿をしたことのあるIP を拒否するようにした

最近WordPress へのコメントとトラックバックスパムが酷くなってきました。URL が含まれている物は承認が必要なようにしているのですが面倒です。このときにスパムはスパムだと手動で振り分けをしているので振り分けたものからIP を抜き出してアクセス制限を掛けるとましにならないかと設定してみました。

データベースから該当IP を抜き出す

MySQL からスパムを指定したIP の一覧は以下のようにして取得出来そうです。

$ cat /etc/wordpress/spamcommentip.sql
SELECT comment_author_IP FROM wordpress.wp_comments WHERE comment_approved='spam'
$ /usr/bin/mysql -umy -p < /etc/wordpress/spamcommentip.sql | /usr/bin/sort -n | /usr/bin/uniq -c| sort -n|cut -c-7|uniq -c
81 1
31 2
26 3
12 4
8 5
9 6
4 7
9 8
1 9
1 10
3 11
2 12
3 13
1 14
1 15
1 18
4 20
1 22
1 23
1 24
1 26
1 43
1 82
1 119
1 146
1 394

自動化したいので、MySQL にアクセスする為のMySQL の設定ファイルと、IP を抜き出すsqlファイルを用意します。

MySQL アクセスの為の設定ファイル

$ cd /etc/wordpress
$ umask 077
$ sudo touch .my.conf
$ sudo chown www-data.root .my.conf
$ vi .my.conf
cat .my.conf
user=wp
password=XXXXXXXXXXXXXX
database=wordpress

IP を抜き出す為のsqlファイル

$ sudo vi /etc/wordpress/spamcommentip.sql
$ cat $ cat /etc/wordpress/spamcommentip.sql
SELECT comment_author_IP FROM wordpress.wp_comments WHERE comment_approved='spam'

以下のようにしてIP の一覧が取得出来るようになりました。

$ /usr/bin/mysql --defaults-file=/etc/wordpress/.my.conf < /etc/wordpress/spamcommentip.sql

apache httpd の .htaccess で指定IPアドレスからの WordPress のコメント投稿とトラックバックを制限

Debian のパッケージで WordPress を導入しているので導入パスは /usr/share/wordpress/ です。
設定ファイルは /etc/wordpress 以下です。
/usr/share/wordpress/.htaccess は /etc/wordpress/htaccess のシンボリックリンクになっています。

アクセス制限をするには .htaccess に deny from ip address な感じで行けます。
さっきのIPの一覧取得時に並べ替えて同一IPをまとめて頭にdeny from を付けるようにします。

$ /usr/bin/mysql --defaults-file=/etc/wordpress/.my.conf < /etc/wordpress/spamcommentip.sql | /usr/bin/sort -n | /usr/bin/uniq | /bin/grep -v 'comment_author_IP' | /bin/sed "s/^/ deny from /"

あまり無いと思いますが、正しいIP アドレスを登録してしまっても本文が読めるようにコメントやトラックバックだけ制限しようと思います。コメント、トラックバックは次のwp-comments-post.php / wp-trackback.php を利用するようなのでこのファイルへのアクセスを制限します。
.htaccess の Files ディレクティブを利用して以下ような感じでいけそうです。

<Files ~ wp-comments-post.php|wp-trackback.php>
deny from ip address
</Files>

動作確認は自分のIPアドレスを一時的に登録して行いました。blog本文にはアクセス出来てコメントURL は拒否されています。

% w3m -dump_head https://matoken.org/blog/blog/2015/06/09/facebook-pgp/|head -1
HTTP/1.0 200 OK
% w3m -dump_head https://matoken.org/blog/wp-comments-post.php|head -1
HTTP/1.1 403 Forbidden

cron を使って自動的に更新するようにする

IP list は外部ファイルにして読み込むようにすると便利そうですが、Include ディレクティブは .htaccess からは利用出来無いようなので分割ファイルを作って連結することにします。

/etc/wordpress/htaccess_base

元のhtaccess

/etc/wordpress/htaccess_spamhead

Files ディレクティブの先頭

/etc/wordpress/htaccess_spamiplist

データベースから抜き出して作成した拒否IPリスト

/etc/wordpress/htaccess_spamtail

Files ディレクティブの末尾

/etc/wordpress/htaccess

最終的に結合されて.htaccess のリンク元になるファイル

htaccess_base / htaccess_spamhead / htaccess_spamtail を用意します。

$ sudo cp -p /etc/wordpress/htaccess /etc/wordpress/htaccess_base
$ sudo sh -c "echo '<Files ~ wp-trackback.php|wp-comments-post.php>' > /etc/wordpress/htaccess_spamhead"
$ sudo sh -c "echo '</Files>' > /etc/wordpress/htaccess_spamtail"

htaccess_spamiplist / htaccess はcron で1時間毎に作成するようにします。

$ sudo -u www-data crontab -e
$ sudo -u www-data crontab -l
14 * * * * /usr/bin/mysql --defaults-file=/etc/wordpress/.my.conf < /etc/wordpress/spamcommentip.sql | /usr/bin/sort -n | /usr/bin/uniq | /bin/grep -v 'comment_author_IP' | /bin/sed "s/^/ deny from /" > /etc/wordpress/htaccess_spamiplist && /bin/cat /etc/wordpress/htaccess-base /etc/wordpress/htaccess_spamhead /etc/wordpress/htaccess_spamiplist /etc/wordpress/htaccess_spamtail > /etc/wordpress/htaccess

これで1時間毎にWordPress 上でspam と判定したコメント/トラックバックの送信元IP からコメント/トラックバックを拒否するようになりました。
うまくいくといいのですが……。

追記)
設定して数日経ちましたが，spam激減しました!