毎日毎日性懲りもなくあちらの国から来る不正アクセスを自動的に排除したい!という時に助かるfail2banというソフトの導入手順を記載します。
https://github.com/fail2ban/fail2ban
ライセンスはGNU GPL v2です。
(2020.03.13)[recidive]ルールのenabled
指定がenable
になっていたので修正
fail2banは、超ざっくり説明すると各デーモンのログファイルを監視して、排除したいホストに対するIPフィルタルール等を動的に作成してくれるソフトです。
少し詳しく説明すると以下のような感じです。
(1)アタックと思しきログ(↓こんなの)に対して
postfix/smtpd[xxxxxx]: warning: unknown[xxx.xxx.xxx.xxx]: SASL LOGIN authentication failed
(2)ログレコードにマッチする正規表現(↓こんなの)を登録する
failregex = ^%(__prefix_line)swarning: [-._\w]+[<HOST>]: SASL (?:LOGIN|Login|login|PLAIN|(?:CRAM|DIGEST)-MD5) authentication failed(: [ A-Za-z0-9+/]={0,2})?\s$
(3)ログを監視して正規表現とマッチしたら、アタック間隔(1分間に何回来てるか等)に基づき、BAN対象か判別する
(4)BAN対象と判断したら、アタック元IPアドレス(上記(2)における<HOST>)をIPフィルタルール(iptablesとか)に自動登録する
(5)BAN対象期間(30分等)が過ぎたらIPフィルタルールを削除する
sshやメール認証だけでなく、exploit目的で存在しないurlを叩きまくってくる奴なんかもBANできます。
今回はそのようなhttp/httpsによる大量の403/404を弾く設定をします。
ログの書式が同一であれば、webサーバはnginx、apacheどちらも(リバースプロキシでも)同じような設定で良いと思われます。
参考にさせて頂いたサイト:
EC2でnginxの過剰な404|403に対しfail2banをかける
インストール
CentOS7での手順です。
epelリポジトリを追加する必要があります。
# yum install epel-release -y
# yum install fail2ban -y
以下のバージョンがインストールされました
fail2ban.noarch 0.10.5-2.el7
設定用ファイルの作成
# cd /etc/fail2ban
[Q] Should I make my configuration directly in jail.conf and fail2ban.conf?
[A] No. You should avoid to change .conf files, created by fail2ban installation. Instead, you'll write new files having .local extension.
との事なので、(アプデで上書きされる恐れのある)fail2ban.conf
とjail.conf
はいじらず、.conf
をコピーした.local
を作成して設定していきます。
# cp jail.conf jail.local
基本的にはjail.local
にBAN定義を追加していきます。
./jail.d/
配下に、ルール毎の.local
を作って管理しても良いです。
.conf
と.local
とサブディレクトリの詳細な優先順位は、
https://manpages.debian.org/experimental/fail2ban/jail.conf.5.en.html
./jail.conf
./jail.d/*.conf (in alphabetical order)
./jail.local
./jail.d/*.local (in alphabetical order)
の順で、上書きされていくとの事です。./jail.d/*.local
が最優先という事ですね。
正規表現フィルタ定義の作成
まずは、監視対象のログファイル(不正アクセスをしてきたホストIPが記載されているもの)に基づき、アタックと認識する為の正規表現を定義します。
今回はhttp/httpsの403/404エラーを弾きたいので、以下のようなログが、正規表現でマッチしたいログとなります(nginxのアクセスログですがapacheでも同じような書式かと)。
xxx.xxx.xxx.xxx - - [12/Mar/2020:17:03:10 +0900] "GET /wordpress/license.txt HTTP/1.1" 404 295 "-" "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:62.0) Gecko/20100101 Firefox/62.0" "-"
このログにマッチする正規表現を記載した定義ファイルを、./filter.d/
の配下に拡張子.conf
として作成します。ファイル名は後でも使用するルール名になりますので忘れず控えてください。ここではweb-404
としました。
[Definition]
failregex = ^<HOST>.*"(GET|POST).*" (403|404) .*$
ignoreregex = \.(?i)(jpe?g|gif|png|bmp|pdf|js|css|woff|eot|ttf|ico|txt|xml|swf|xlsx?|docx?|pptx?)
failregex
アタックと認識したいレコードにマッチする正規表現を定義します。
ignoreregex
ホワイトリストです。この正規表現にマッチするとBAN対象にしません。上記では画像やドキュメントファイル等の拡張子を対象としたnot foundに関してはアタックとみなしません。
favicon.ico
やrobots.txt
がない場合に404を吐いてしまい正規のアクセスまで弾いてしまうという事を防止できますが、例えば上記のようなwordpressのlicense.txt
を取得しようとするアクセスもOKとみなしてしまう為、慎重に検討してください。
BAN定義ファイルの作成
フィルタ定義を作成したら、次はフィルタにマッチしたホストをどのようにBANするかを設定に追加します。
[web-404]
enabled = true
filter = web-404
action = iptables-multiport[name=web-404, port="http,https", protocol=tcp]
sendmail-whois[name=web-404, dest=root, sender=fail2ban, sendername="Fail2Ban"]
logpath = /var/log/nginx/access.log
bantime = 30m
findtime = 10m
maxretry = 5
[ルール名]
他と重複のないルール名を指定
enabled
trueで有効化
filter
ここで指定した名称の./filter.d/*.conf
を使用してログファイルを監視しなさいという設定です。
action
BANの処理についてはここで指定した名称の./action.d/*.conf
を使用しなさいという設定です。上記の例では./action.d/iptables-multiport.conf
という、複数のポートを対象としたiptables用の設定を使ってIPフィルタを作成します。二行目はBANした事をメールで通知を受けたい場合の設定です。./action.d/sendmail-whois.conf
が使われます。
logpath
監視するログファイルのパスを指定します。不正アクセス元ホストIPが記載されているものである必要があります。
findtime
maxretry
findtime時間中にmaxretry回のフィルタマッチでBAN対象とみなす設定。例では1分間に5回の403/404を検出したらBAN(上記のactionを実行)となります。
bantime
どのくらいの期間BANするか、例では30分。
上記の例をまとめると、
http/httpsによる接続で10分間に5回以上の403/404エラーを検出したホストをiptablesにより30分間アクセス禁止にし、rootにメールするという設定になります。
(2020.03.18変更)1分間に5回でBANを例としていましたがデフォルトの設定通り10分間に5回へと変更
iptablesではなくfirewalldを使用している場合は、./action.d/firewallcmd-multiport.conf
を使用する書式に書き換えて下さい。
尚、v0.10では以下のデフォルト定義を元に、上記のiptables-multiportとsendmailへのactionを1行で書けるようになっていました。
[DEFAULT]
destemail = root@localhost
sender = fail2ban@<fq-hostname>
mta = sendmail
protocol = tcp
banaction = iptables-multiport
action_mwl = %(banaction)s[name=%(__name__)s, bantime="%(bantime)s", port="%(port)s", protocol="%(protocol)s", chain="%(chain)s"]
%(mta)s-whois-lines[name=%(__name__)s, sender="%(sender)s", dest="%(destemail)s", logpath="%(logpath)s", chain="%(chain)s"]
[web-404]
enabled = true
port = http,https
action = %(action_mwl)s
logpath = /var/log/nginx/access.log
bantime = 30m
findtime = 10m
maxretry = 5
filter項を省略しても、ルール名から./filter.d/web-404.conf
が参照されるようです。
悪質なホストに対する長期BAN設定
設定ファイルの下の方に、一日に何度もBANされている悪質なホストを長期間BANする[recidive]というルールのひな形があります。
必要ならenableにしましょう。fail2ban.log自体を監視しているルールとなります。
[recidive]
enabled = true
logpath = /var/log/fail2ban.log
banaction = %(banaction_allports)s
bantime = 1w
findtime = 1d
maxretry = 5
上記の例では、何かのルールで1日に5回BANされたホストを1週間BANします。
逆に言うと1日に5回BANされなければルールに当てはまらない為、
bantimeを中途半端に長くしてしまっていると(例えば10hとか)recidiveルールが適用されません。
正規表現フィルタの定義は./filter.d/recidive.conf
が使われます。
正規表現フィルタ定義のテスト
ここまで終わるとfail2banを起動できますが、その前に作成した正規表現フィルタが正しくアタックログにマッチするかテストしておきます。
fail2ban-regex
というツールに-v
オプションを付けて実行すると、マッチした行が見えるテストができます。
# fail2ban-regex --help
Usage: /usr/bin/fail2ban-regex [OPTIONS] <LOG> <REGEX> [IGNOREREGEX]
# fail2ban-regex -v /var/log/nginx/access.log /etc/fail2ban/filter.d/web-404.conf
Results
=======
Failregex: 2 total
|- #) [# of hits] regular expression
| 1) [2] ^<HOST>.*"(GET|POST).*" (403|404) .*$
| xxx.xxx.xxx.xxx Thu Mar 12 03:52:39 2020
| xxx.xxx.xxx.xxx Thu Mar 12 10:16:45 2020
`-
Ignoreregex: 67 total
|- #) [# of hits] regular expression
| 1) [67] \.(?i)(jpe?g|gif|png|bmp|pdf|js|css|woff|eot|ttf|ico|xml|swf|xlsx?|docx?|pptx?)
`-
`-
(省略)
Lines: 588 lines, 67 ignored, 2 matched, 519 missed
Failregexの項目に、フィルタがマッチした行が表示されます。最後の行には、ログファイルのレコード数、除外したレコード数、マッチしたレコード数、マッチしなかったレコード数がわかります。上記のテストでは588行中、2行のログが不正アクセスとして検出されました。
サービス起動と動作テスト
問題がなければサービスに登録して起動します。
# systemctl enable fail2ban
# systemctl start fail2ban
本当にBANされるかテストしてみます。試しに存在しないURLを連続5回叩き、fail2banのログを見てみます。
# tail /var/log/fail2ban.log
2020-03-12 17:02:53,398 fail2ban.jail [19885]: INFO Jail 'web-404' started
2020-03-12 17:03:08,651 fail2ban.filter [19885]: INFO [web-404] Found xxx.xxx.xxx.xxx - 2020-03-12 17:03:08
2020-03-12 17:03:09,254 fail2ban.filter [19885]: INFO [web-404] Found xxx.xxx.xxx.xxx - 2020-03-12 17:03:08
2020-03-12 17:03:09,456 fail2ban.filter [19885]: INFO [web-404] Found xxx.xxx.xxx.xxx - 2020-03-12 17:03:09
2020-03-12 17:03:10,060 fail2ban.filter [19885]: INFO [web-404] Found xxx.xxx.xxx.xxx - 2020-03-12 17:03:09
2020-03-12 17:03:10,262 fail2ban.filter [19885]: INFO [web-404] Found xxx.xxx.xxx.xxx - 2020-03-12 17:03:10
2020-03-12 17:03:10,641 fail2ban.actions [19885]: NOTICE [web-404] Ban xxx.xxx.xxx.xxx
5回の検出の後、BANされたログが確認できました。という事はiptablesにIPフィルタルールが追加されている筈なので確認してみます。
# iptables -nvL
Chain f2b-web-404 (1 references)
pkts bytes target prot opt in out source destination
76 4276 REJECT all -- * * xxx.xxx.xxx.xxx 0.0.0.0/0 reject-with icmp-port-unreachable
6 240 RETURN all -- * * 0.0.0.0/0 0.0.0.0/0
f2b-web-404
というチェインのsourceにBANしたIPが登録されていました。
最後に、BANを解除する手順です。
fail2ban-client
というツールに対象ルール名と、unbanipというコマンドを発行するとルールが消えます。
# fail2ban-client set web-404 unbanip xxx.xxx.xxx.xxx
1
結果が「1」とそっけないので確認しておきます。
# iptables -nvL
Chain f2b-web-404 (1 references)
pkts bytes target prot opt in out source destination
160 16886 RETURN all -- * * 0.0.0.0/0 0.0.0.0/0
ちゃんと消えてました。
以上で終わりです。繰り返しになりますが、sshやメール認証への不正アクセスも同様の手順で検知・BANできます。正規表現フィルタを公開して下さっている方もいらっしゃいますので自作が困難であれば探してみて下さい。