mod_rewrite で RBL を使ったアクセス制御を行う

RBLを使ったアクセス制限をしたかったんだが、apache標準ではそういうモジュールは存在しない。第3者によるモジュールの実装やパッチ*1は存在するがapacheのバージョンによって使えるモジュールやパッチがまちまちだし実装によって設定方法も違うのでイマイチだった。何とかバージョン共通でコピペで使える方法が無いか考とえたアイデアの一つが以下に示す mod_rewrite を使ったやり方です。

その方法とは外部プログラムを使って RewriteMap を定義して、それに REMOTE_ADDR を渡してアクセス元が SPAM か HAM かチェックするというものです。

RewriteMap用プログラム

以下のような仕様のプログラムを、ここでは /etc/httpd/conf/bin/rbl_map.pl というファイル名で作成します。

  • 標準入力がcloseされるまでループし続ける常駐プログラム
  • IPアドレスを標準入力から1行ずつ受け付ける
  • 渡されたIPに対してRBLチェックを行い、SPAM か HAM を標準出力に出力する
#!/usr/bin/perl
use strict;
use Socket qw(inet_aton);
my @RBL_SERVERS = ('niku.2ch.net');
$| = 1;
while(<STDIN>) {
    chomp;
    my $ip = $_;
    my $revip = join('.', reverse(split(/\./, $ip)));
    my $status = 'HAM';
    foreach my $server (@RBL_SERVERS) {
        if(inet_aton("$revip.$server")) {
            $status = "SPAM";
            last;
        }
    }
    print "$status\n";
}

ここで @RBL_SERVERS に設定している niku.2ch.net はかなり強力ですが、強力すぎて正常なアクセスも阻害する恐れもあります。自分でコメントやトラックバックスパム用の RBL を調べた上で適当なのを使った方がよいかもしれません。

作成したプログラムを以下のようにしてテストしてみました。

[root@localhost ~]# echo 202.86.196.9 | /etc/httpd/conf/bin/rbl_map.pl
SPAM
[root@localhost ~]# echo 124.83.139.191 | /etc/httpd/conf/bin/rbl_map.pl
HAM

httpd.conf に以下のように記述します。

 RewriteEngine on
 RewriteMap rbl-map prg:/etc/httpd/conf/bin/rbl_map.pl
 RewriteCond %{REQUEST_URI} ^/rbltest/
 RewriteCond ${rbl-map:%{REMOTE_ADDR}} SPAM
 RewriteRule (.*) SPAM [F]
  • RewriteMap ディレクティブで rbl-map という名前で作成したプログラムを登録します。
  • 最初の RewriteCond は RBL チェックをかける範囲を限定する為に記述している*2
  • 2番目の RewriteCond で RBL チェックを行っています。
    • ${rbl-map:%{REMOTE_ADDR}} の rbl-map は定義したマップ名
    • コロンの後ろに書いたものがプログラムに渡せる情報となり、この値はプログラムからは1行の標準入力として渡されるように見えます。
    • rbl-map は渡された IP が SPAM と判定されたら SPAM という文字列を返すように作ってあるので SPAM にマッチさせます。
  • SPAMとしてマッチしたら 403 Forbidden にしたいので全てにマッチするダミーの RewriteRule を書いています*3

*1:mod_access_rblとかmod_access_rbl2とかmod_dnsbl_lookupとかmod_setenvdnsblとか、mod_accessやmod_authz_hostへのパッチとか

*2:コレがないと全てのリクエストに対してRBLチェックを行ってしまうのでスループットに大きな影響が出てしまいます

*3:[F] は 403 Forbidden にすることを意味します