LoginSignup
22
23

More than 5 years have passed since last update.

日本国外からの悪意あるアクセスをIPを指定して遮断する

Last updated at Posted at 2016-05-27

概要

運用しているWebサイトのアクセスログをみると,海外のサーバからひっきりなしに攻撃を受けていることに気づいたので,簡単な防御策を講じました.

具体的な方法は以下の通りです.

  • アクセスログを読み込み,海外IPからのアクセスがあればiptablesでブロックするようなスクリプトを作成.
  • そのとき,Googleなどの検索エンジンのクローラーはブロックしないように注意する.
  • アクセスされた海外IPが新しいものか判断するために,過去ブロックしたIPはdenyIpファイルに保存しておく.
  • cronで5分おきにスクリプトを走らせ,新たな海外IPからのアクセスがあればブロックリストに追加する.

アクセスされた時に即座に対応できる即時性はありませんが,素早く対策を講じることを優先しました.

開発環境

  • CentOS 6.7

実装方法

スクリプトはPHPで書いています.

準備

IPアドレスから国を取得するためのPHPモジュール(GeoIP)

GeoIPを使うのでサーバに導入.

# peclコマンドを使うので必要であればpearパッケージもインストール
$ yum install php-devel php-pear geoip geoip-devel
$ pecl install geoip

# モジュールを使えるようにするために/etc/php.iniに追加
extension=geoip.so

アクセスログの形式

ddd.ddd.ddd.ddd - - [24/Apr/2016:04:24:04 +0900] "POST /hoge HTTP/1.1" 200 fugafuga

先頭にIPアドレスが記述してある形式とします.

実際のスクリプト

cron上で以下のように,引数にアクセスログのファイルを与えて,5分おきにスクリプトを走らせることを想定しています.

cron
*/5 * * * * php /path/to/denyForeignIp.php /path/to/access.log
denyForeignIp.php
<?php
// 引数があるか確認
if (!isset($argv)) {
  echo "You need a argument of a access log.";
  exit();
}

// 除外するIPとホスト名(自分のIPや検索エンジンのクローラーは除外)
$excludeIp = array("ddd.ddd.ddd.ddd");
$excludeName = array("google", "msnbot");

// ログファイルからIPを全取得
$file = fopen($argv[1], "r");
$spamIp = array();
while ($line = fgets($file)) {
  $result = preg_match("/\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}/", $line, $m);
  if (!$result) continue;

  // 除外対象のIPは取得しない
  $hostName = gethostbyaddr($m[0]);
  if (!in_array($m[0], $excludeIp))
    foreach ($excludeName as $value) {
      if (strpos($hostName, $value) === false)
        array_push($spamIp, $m[0]);
    }
}
$spamIp = array_unique($spamIp);
fclose($file);

// 外国IPのみを有害IPとする
foreach ($spamIp as $key => $value) {
  $countryCode = @geoip_country_code3_by_name($value);
  if ($countryCode === false) continue;

  if ($countryCode === "JPN") {
    unset($spamIp[$key]);
  }
}
$spamIp = array_values($spamIp);

// アクセスされた海外IPが新しいIPだったらiptablesに追加
foreach ($spamIp as $key => $value) {
  $existFlg = false;

  $denyIpFile = fopen("/path/to/denyIp", "w+");
  while ($denyIpLine = fgets($denyIpFile)) {
    $denyIpLine = str_replace(array("\r\n", "\r", "\n"), "", $denyIpLine);
    if ($value  === $denyIpLine) {
      $existFlg = true;
      break;
    }
  }

  if (!$existFlg) {
    fwrite($denyIpFile, $value.PHP_EOL);
    exec("iptables -A INPUT -s ".$value." -j DROP");
  }
  fclose($denyIpFile);
}

// ipteblesを保存
exec("/sbin/service iptables save");
22
23
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
22
23