[PHP] サイト丸コピーをしようとするIPを検出してメールでアラートする

とあるサイトで、サイト内容をまるっとコピーされることがありました。そこでサイトコピーを未然に防ぐために、丸コピーをしようとするIPを検出してメールでアラートするプログラムを書いてみました。

サイトをコピーされてしまったら

定番は、GoogleへのDMCAによる著作権侵害申請

コピーされてから、ネットでいろいろと調べてみましたが、コピーされた方は、GoogleにDMCAによる著作権侵害を申請される方が多かったイメージです。プロバイダーを見つけて削除依頼をする方法もありますが、そちらは書類を用意したり結構面倒なので、フォームから申請するだけのDMCAは楽ですよね。

ただ、今回の自分の事象では、気づいた時にはコピーサイトが閉鎖していてDMCAで侵害を訴えられない状況でした。(それでも、コピーサイトのゴミインデックスだけがGoogleに残り、こちらのSEOは下がる)

また、DMCAはそもそもGoogleが取り合ってくれないなど、コピーしたもん勝ちなとこがあるのが現状です。

DMCAを乱用して自社の悪評を消すなんて逆SEO的なやり方も流行っているので、DMCAでコピーコンテンツ対策は万全!とはいかないのは仕方ないところです。

コピーされてからでは遅いのかもしれない=コピーを止めよう!

少し考え方を変えて、コピーサイトを止めるのではなく、「そもそもコピーされないようにするのはどうすればいいのか?」と考えた時に、

  1. ネットで公開している時点でオープンなので、個別コンテンツのコピーは防げない
  2. でも、コピーしてるユーザーは見つけることができるかもしれない
  3. コピーされる前にそのユーザーのアクセスを禁止してしまうのがいいかもしれない

という結論に至りました。

つまり、短期間に大量アクセスするIPを弾いてしまえばいいということです。

個別の記事をコピーする人は、パソコンで個別にコピーするで検出が難しいですが、サイト丸コピーをする人間は確実に1台のPCまたはサーバーからアクセスしてくるはずだから、ある程度の効果はあるはず!

プログラムの構成と流れ

まず、格安レンタルサーバーでも動かせるようにPHPで書きます。なるべくいろんなサーバーで使えるようにしたいのですが、exec関数を使うので、サーバーによっては使えないかもしれないのでご注意ください。

プログラムの流れをざっと書きだすと、

  1. access.logからIPごとのアクセス数を取る
  2. 全体の中央値を取って、異常値を出しているIPを抽出
  3. メールでアラートする

という感じにします。完璧ではないですが、発見の補助くらいにはなるかな?というレベルのものを目指します。

実装

access.logを一般ユーザーが閲覧できるようにする

まずはaccess.logが見れないと話にならないので、Apacheがaccess.logを読み取れるように権限を変えます。以下はCentOSの例。

access.logはサーバーによって場所が違うので、その辺りはサーバーのマニュアル等を参照してください。

chmod 0605 /var/log/httpd

プログラムを書く

さて、読み出せるようになったのでPHPプログラムを書いていきます。ここではcheck_spam_ip.phpというファイルで作成します。

//ログが保存されているパス
$log_path = "/var/log/httpd/access_log";

//google botなど。都度追加していく
$ok_ip = array(
  "157.55.39.74",//bingbot
  "207.46.13.50",//bingbot
  "157.55.39.58",//bingbot
  "157.55.39.242",//bingbot
  "207.46.13.37",//bingbot
  "66.249.71.154",//googlebot
  "66.249.71.155",//googlebot
  "66.249.79.10",//googlebot
  "66.249.71.88",//googlebot
);

$date = date("d/M/Y");

//アクセスログを整形させる
exec("grep '{$date}:01' {$log_path} | cut -d ' ' -f 1 | sort | uniq -c", $results);

//取得したアクセスログを配列に変換
$log_ips = array();
foreach($results as $result){
  $temp = explode(" ", trim($result));
  if(!in_array($temp[1], $ok_ip)){
    $log_ips[$temp[1]] = $temp[0];            
  }
}

//降順にする
arsort($log_ips);

//中央値を出す
$valuees = array_values($log_ips);
if (count($valuees) % 2 == 0){
  $median = (($valuees[(count($valuees)/2)-1]+$valuees[((count($valuees)/2))])/2);
}else{
  $median = ($valuees[floor(count($valuees)/2)]);
}

//中央値+n回までは許容する(ここではn=10)
$limit = intval($median) + 10;

//limitを超えたIPを抽出
$spam_ip = array();
$message = '';

foreach($log_ips as $ip=>$num){
  if($num > $limit){
    $spam_ip[$ip] = $num;
    $message .= $ip . ": " . $num . PHP_EOL;
  }
}

//結果が空でなかったらメール送信
if(!empty($spam_ip)){
  $now = date('Y-m-d h:i:s');
  $headers[] = 'From: Spamchecker <hoge@exmaple.com>';

  $title = "[{$now}] スパムIPを検出しました";

  // 送信する
  mail('fuga@exmaple.com', $title, $message, implode("\r\n", $headers));  
}

cronで一定期間で自動的に実行する

今度は、作ったプログラムを一定時間で実行させます。cronが簡単なのでcronを使いました。

下記の例では、1時間に一回(毎時1分)実行します。

1 * * * * /usr/bin/php /path/to/check_spam_ip.php

IPをチェックして、ApacheやNginxでアクセス制限をする

あとは、ApacheやNginxで対象のIPアドレスからのアクセスを拒否すればOK。

ただし、普通にいっぱいアクセスしてくれるヘビーユーザーの可能性もあるので、ブロックは慎重にする必要があります。

例えば、IPを抽出したら、そのIPの動きをアクセスログでチェックして、あきらかにおかしい挙動(1秒間に数回アクセスしているなど)を確認してからブロックするなど、「確実にスパムだ」と確定できてからブロックするようにすると良いと思います。


ざくっとしたプログラムですが、バッチで勝手に動いてくれれば面倒なアクセスログチェックもルーティンで行えます。

ただ、これだけでは当然不十分なので、抽出したIPの動きや数日、数週間の動きも同時にチェックできるように、今後プログラムを改善していこうと思います。

つづく(多分)。