spammer counter

[`evernote` not found]
Bookmark this on Hatena Bookmark
Share on Facebook
LINEで送る

アクセス禁止したスパマーが,その後どれだけアクセスしているかカウントする.

以前,スパム増加という記事でも触れたが,
本サイトではアクセス禁止リストにあるホストからのアクセスを禁止している.
ところが,似たようなIPからのアクセスが絶えず続いており,どんどんホストを追加している状態である.
このままではアクセス禁止リストが延々と伸びていってしまうので,特にアクセスの多いアドレス空間については,
適当なサブネットマスクでもってアク禁とすることにしたい.

ところが,一度アクセスを禁止してしまうと,その後はどの程度のアクセスがあるのか分からない.
アク禁リストのアップデートをするための情報として,アク禁を解除しないまま,アクセス数を把握する方法を考えた.

ずばり,403 エラードキュメントをphpにして,アクセス元をカウントアップする作戦である.
そして普通に誤った操作をした人に疑問を与えないよう,403を忠実に再現したい.
ということで,こんなコードを生成してみた.

<?php
header("HTTP/1.1 403 Forbidden");
header("Content-Type: text/html; charset=iso-8859-1");
?>
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
<HTML><HEAD>
<TITLE>403 Forbidden</TITLE>
</HEAD><BODY>
<H1>Forbidden</H1>
<?php printf("You don't have permission to access %s\non this server.",
             htmlentities(strip_tags($_SERVER['REQUEST_URI']))); ?><P>
<HR>
<ADDRESS><?php
$e = explode(' ',$_SERVER['SERVER_SOFTWARE']);
printf("%s Server at %s Port %d",$e[0],$_ENV['SERVER_NAME'],$_ENV['SERVER_PORT']);
?></ADDRESS>
</BODY></HTML>
<?php
// count IP addr
$addr = $_SERVER['REMOTE_ADDR'];
$fobj = fopen("counter.dat","r");
if (flock($fobj, LOCK_EX)) {
    $oobj = fopen("counter.tmp","w");
    $flag=false;
    for(;!feof($fobj);)
    {
        if ($flag) { fwrite($oobj,fgets($fobj));}
        else {
            $s=fgetcsv($fobj);
            if (count($s)<2) { break;}
            if ($s[0] === $addr) {
                $s[1]=(int)$s[1]+1;
                $flag=true;
            }
            fputcsv($oobj,$s);
        }
    }
    if (!$flag) { fprintf($oobj,"%s,1\n",$addr);}
    fclose($fobj);
    fclose($oobj);
    copy("counter.tmp","counter.dat");
} else {
    fclose($fobj);
}
?>

ファイルロックなんて,何年か振りに実装した.
普通に php のオンラインドキュメントにあるようなファイルロックにしていないのは,
各行毎に読み込み/書き込みをしたかったから.
読み込み用ファイルを排他ロックして,読み込めた人だけ処理が進むようにしてみた.
そんな処理が問題になるほど膨大なログが溜まる頃には,レンタルサーバのスペースを
食い潰してアカウント消されていそうだけどね…

んで,アク禁で ErrorDocument 403 へ飛ばす場合の注意.
403 で飛ばす先の php ファイルへのアクセスは可能とすること.
さもなくば, 403 の転送で無限ループが発生する.

<Files hogehoge.php>
allow from all
</Files>

とかでOK.

余談だが, ErrorDocument で http://~~ と URI 指定すると,
別サーバへの転送と同様に処理されてしまうらしく,呼び出し元が引けなくなるので注意.