fail2banで間違ってBANしてしまったIPをPHPで解除するには?
DoS攻撃/DDoS攻撃からサーバーを守る方法(fail2banのススメ)で書いたように、Fail2banは非常に便利なサーバー攻撃防御ツールですが、FilterやJailの設定によっては間違ってBANしてしまう場合もあります。
これをUNBANするのが意外と大変。管理者でサーバーにログインしないといけないため、サーバー担当者は苦労されているのではないでしょうか?
PHP+cronシェルを組み合わせて外部からUNBAN予約できるようにしてみよう
PHPだけでは残念ながらセキュリティの関係上、fail2ban-clientコマンドを実行することができません。
そこで以下の手順でUNBANできるようにしてみましょう。
- PHPプログラムでサーバーにUNBANするIPアドレスとフィルターをテキストファイルで保存する。
- cronで実行するシェルスクリプトにそのテキストファイルを読みこませる。
- 登録されているIPアドレスをUNBANする。
UNBAN IP登録用のPHPプログラム作成
以下がUNBANするIPとフィルター名を登録するPHPプログラムです。
<?php
$file = '/tmp/my_unban_list.txt';
if (isset($_GET['clean'])) {
@file_put_contents($file, '');
print "<h1>UNBANリストをクリアしました。</h1>";
}
if (empty($_GET['ip']) or !preg_match('/^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/', $_GET['ip'])) {
print "<h1>IPアドレスが正しくありません。</h1>";
} else if (empty($_GET['filter'])) {
print "<h1>フィルター名が正しくありません。</h1>";
} else {
$ip = $_GET['ip'];
$fl = $_GET['filter'];
@file_put_contents($file, "{$fl},{$ip}\n", FILE_APPEND);
print "<h1>「{$fl}」の「{$ip}」をUNBAN予約しました。</h1>";
}
?>
cronで実行するシェルスクリプト
#! /bin/sh
UNBANFILE=/tmp/unban_list.txt
while read line; do
fl=`echo ${line} | cut -d , -f 1`
ip=`echo ${line} | cut -d , -f 2`
fail2ban-client set "$fl" unbanip "$ip"
done < $UNBANFILE
: > $UNBANFILE
このスクリプトを1分おきに実行できるようにcrontabで登録しましょう。
MAILTO=admin@example.com * * * * * /usr/local/bin/unbanip.sh
MAILTOのところは一応、解除されたかどうかをメール通知してもらうためですが、シェルの中でメール送信させたほうが他のcronタスクに迷惑かけないので親切ですね。
fail2banのBAN通知メールにUNBAN用のURLを仕込んでみよう
さて、外部からブラウザでUNBANできるようにはなったものの「BANメール内にそのURLを仕込みたい!」と思うのがわがままな優秀な管理者というもの。
jail.localの設定でメール内にリクエストログを載せるようにしている場合、/etc/fail2ban/action.d/sendmail-whois-lines.conf がそのメールテンプレートファイルになります。
これをバックアップしておき、以下のようにUNBAN用のURLを記載されるようにすればOKです。
actionban = printf %%b "Subject: [Fail2Ban] <name>: banned <ip> from `uname -n`
Date: `LC_ALL=C date +"%%a, %%d %%h %%Y %%T %%z"`
From: <sendername> <<sender>>
To: <dest>\n
Hi,\n
The IP <ip> has just been banned by Fail2Ban after
<failures> attempts against <name>.\n\n
Here is more information about <ip> :\n
`/usr/bin/whois <ip> || echo missing whois program`\n\n
Lines containing IP:<ip> in <logpath>\n
`grep -E <grepopts> '(^|[^0-9])<ip>([^0-9]|$)' <logpath>`\n\n
+UNBAN URL:
+https://www.example.com/my/secret/path/unban.php?filter=<name>&ip=<ip>\n\n
Regards,\n
Fail2Ban" | /usr/sbin/sendmail -f <sender> <dest>
ホスト名の部分を汎用的に自動取得したければhostnameコマンドで取ってくるようにできます。
-https://www.example.com/my/secret/path/unban.php?filter=<name>&ip=<ip>\n\n
+https://`hostname`/my/secret/path/unban.php?filter=<name>&ip=<ip>\n\n
あとはfail2banを再起動すればOKです。
2016-04-08