fail2banとは?

あらゆるログファイルを分析してファイヤーウォールを適宜更新して不正IPなどを遮断するセキュリティツールです。NGINXやApacheなどWebサーバのaccess.logやerror.logから分析することもできますし、MySQLやMongoDBなどデータベースへのアクセス失敗ログを分析して不正アクセスのIPを遮断することも可能です。

fail2banでできること

  • NGINXのアクセスログから404 errorログが大量に残っているIPを遮断する
  • MongoDBのログAuthentication failedログが大量に残っているIPを遮断する
  • サーバーへのSSHログインの失敗ログが多いIPを遮断する
  • 短期間でログが大量に残っているIPを遮断する(IDoS/DDoS対策)
  • WordPressの不正ログインのログからIPを遮断する

fail2banの流れ

fail2banの大まかな流れ
  1. 攻撃者から攻撃ツールなどを利用して不正アクセスを試み
  2. データベースやサーバーは不正ログイン不正アクセスをログに記録する
  3. fail2banがそのログファイルを分析して定義したルールに従って設定変更
  4. ファイアウォールやルールに反映

不正アクセスのログ分析

下記のログは私が運営しているサイトから抜粋してわかりやすく加工しました。(NGINXをDocker上で運用しているためログのJSONの形式になっています。)
ここで見てほしいところはアクセス時間不正アクセスによる404のログです。ツールを使わない限り短時間(1秒も経ってない)でこのようなアクセスは無理だからツールによる攻撃だと分かります。

不正とみなすアクセスは人によって違いますが、私の基準を紹介します。

  • 短時間(5分くらい)
  • 404エラーが10回以上発生
  • WordPressっぽい不正アクセスの試み

下記のようなログを不正アクセスログとみなします。

{"log":"nginx.1     | example.com 34.124.195.158 - - [13/Dec/2021:01:47:34 +0900] \"GET //website/wp-includes/wlwmanifest.xml HTTP/1.1\" 404 11 \"-\" \"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.108 Safari/537.36\" \"172.18.0.2:80\"\n","stream":"stdout","time":"2021-12-12T16:47:34.003697411Z"}
{"log":"nginx.1     | example.com 34.124.195.158 - - [13/Dec/2021:01:47:34 +0900] \"GET //wp/wp-includes/wlwmanifest.xml HTTP/1.1\" 404 11 \"-\" \"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.108 Safari/537.36\" \"172.18.0.2:80\"\n","stream":"stdout","time":"2021-12-12T16:47:34.077365751Z"}
{"log":"nginx.1     | example.com 34.124.195.158 - - [13/Dec/2021:01:47:34 +0900] \"GET //news/wp-includes/wlwmanifest.xml HTTP/1.1\" 404 11 \"-\" \"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.108 Safari/537.36\" \"172.18.0.2:80\"\n","stream":"stdout","time":"2021-12-12T16:47:34.154893282Z"}
{"log":"nginx.1     | example.com 34.124.195.158 - - [13/Dec/2021:01:47:34 +0900] \"GET //2018/wp-includes/wlwmanifest.xml HTTP/1.1\" 404 11 \"-\" \"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.108 Safari/537.36\" \"172.18.0.2:80\"\n","stream":"stdout","time":"2021-12-12T16:47:34.226329995Z"}
{"log":"nginx.1     | example.com 34.124.195.158 - - [13/Dec/2021:01:47:34 +0900] \"GET //2019/wp-includes/wlwmanifest.xml HTTP/1.1\" 404 11 \"-\" \"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.108 Safari/537.36\" \"172.18.0.2:80\"\n","stream":"stdout","time":"2021-12-12T16:47:34.299135859Z"}
{"log":"nginx.1     | example.com 34.124.195.158 - - [13/Dec/2021:01:47:34 +0900] \"GET //shop/wp-includes/wlwmanifest.xml HTTP/1.1\" 404 11 \"-\" \"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.108 Safari/537.36\" \"172.18.0.2:80\"\n","stream":"stdout","time":"2021-12-12T16:47:34.38219169Z"}
{"log":"nginx.1     | example.com 34.124.195.158 - - [13/Dec/2021:01:47:34 +0900] \"GET //wp1/wp-includes/wlwmanifest.xml HTTP/1.1\" 404 11 \"-\" \"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.108 Safari/537.36\" \"172.18.0.2:80\"\n","stream":"stdout","time":"2021-12-12T16:47:34.454212872Z"}
{"log":"nginx.1     | example.com 34.124.195.158 - - [13/Dec/2021:01:47:34 +0900] \"GET //test/wp-includes/wlwmanifest.xml HTTP/1.1\" 404 11 \"-\" \"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.108 Safari/537.36\" \"172.18.0.2:80\"\n","stream":"stdout","time":"2021-12-12T16:47:34.525887692Z"}
{"log":"nginx.1     | example.com 34.124.195.158 - - [13/Dec/2021:01:47:34 +0900] \"GET //media/wp-includes/wlwmanifest.xml HTTP/1.1\" 404 11 \"-\" \"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.108 Safari/537.36\" \"172.18.0.2:80\"\n","stream":"stdout","time":"2021-12-12T16:47:34.601121347Z"}
{"log":"nginx.1     | example.com 34.124.195.158 - - [13/Dec/2021:01:47:34 +0900] \"GET //wp2/wp-includes/wlwmanifest.xml HTTP/1.1\" 404 11 \"-\" \"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.108 Safari/537.36\" \"172.18.0.2:80\"\n","stream":"stdout","time":"2021-12-12T16:47:34.672751486Z"}
{"log":"nginx.1     | example.com 34.124.195.158 - - [13/Dec/2021:01:47:34 +0900] \"GET //site/wp-includes/wlwmanifest.xml HTTP/1.1\" 404 11 \"-\" \"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.108 Safari/537.36\" \"172.18.0.2:80\"\n","stream":"stdout","time":"2021-12-12T16:47:34.757962624Z"}
{"log":"nginx.1     | example.com 34.124.195.158 - - [13/Dec/2021:01:47:34 +0900] \"GET //cms/wp-includes/wlwmanifest.xml HTTP/1.1\" 404 11 \"-\" \"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.108 Safari/537.36\" \"172.18.0.2:80\"\n","stream":"stdout","time":"2021-12-12T16:47:34.837592253Z"}

このサーバーでWordpressを使ってないのにWordpressの脆弱性の攻撃ログが残ってますね。

fail2banのインストール

ここでの環境はubuntu 20.04です。
SSH不正ログインとNGINXの不正アクセスのIPを制限する流れまで設定します。

  1. fail2banインストール
$ sudo apt -y install fail2ban

2. 稼働確認

$ systemctl status fail2ban

3. jail.localにIP制限条件やルール設定
デフォルトパスはここです。jail.localファイルがない場合は作ってください。

$ vi /etc/fail2ban/jail.local

jail.local

[sshd]
enabled = true
port    = ssh
filter = sshd
logpath  = /var/log/auth.*
maxretry = 5
findtime  = 1d
banaction = firewallcmd-ipset

1日監視して/var/log/auth.*のログファイルに5回失敗があれば定義したルールを反映するようになっています。
次はnginxの404エラーです。こちらはカスタムフィルターの作成が必要です。回数やログの時間範囲、制限時間など調整できます。

jail.local

[nginx-404]
enabled = true
port = http,https
filter = nginx-404
logpath = /var/log/nginx/*access.log
maxretry = 10
findtime  = 1d
action = iptables-multiport[name=404, port="http,https", protocol=tcp]

1日監視して/var/log/nginx/*access.logのログファイルに10回失敗があれば定義したルールを反映するようになっています。回数やログの時間範囲、制限時間など調整できます。

4. filder.dに新しいフィルターを追加
デフォルトパスはここです。

$ cd /etc/fail2ban/filter.d/

nginx-404.conf

[Definition]
failregex =  ^<HOST>.*"(GET|POST).*" 404 .*$
ignoreregex =

<HOST>に自動的にIPアドレスが入りますが、省略不可です。
failregexに不正ログを見つける制限表現式を書きます。
上記の例はGETとPOSTの404エラーを探すコードの例です。

5. サービス再起動

$ service fail2ban restart
$ sudo fail2ban-client reload

6. sshdの稼働確認
私の環境では既に2個IPが制限されてます。

$ sudo fail2ban-client status sshd

Status for the jail: sshd
|- Filter
|  |- Currently failed:	3
|  |- Total failed:	79
|  `- File list:	/var/log/auth.log
`- Actions
   |- Currently banned:	2
   |- Total banned:	2
   `- Banned IP list:	104.171.245.133 62.28.7.213

7. nginx-404の稼働確認
私はdocker上でnginxを利用しているのでdockerのログから不正アクセスを探しています。
3個IPが制限されていることがわかります。

$ sudo fail2ban-client status nginx-404
Status for the jail: nginx-404
|- Filter
|  |- Currently failed:	3
|  |- Total failed:	58
|  `- File list:	/var/lib/docker/containers/980f9425d8a3ee4467db43086bbd12eea9f838333ec43ed56064a1b4fbb419c0/980f9425d8a3ee4467db43086bbd12eea9f838333ec43ed56064a1b4fbb419c0-json.log
`- Actions
   |- Currently banned:	3
   |- Total banned:	3
   `- Banned IP list:	209.159.152.105 34.125.238.254 52.188.227.175

まとめ

  • fail2banを利用することで不正アクセスからサーバーやDBなどを守ることができます。
  • ここではsshdとnginx-404に対して不正アクセスを制限する例をあげましたが、あらゆるログファイルから正規表現式でエラーを抽出し制限することができるのでカスタムも自由にできます。
  • filter.dにはApache, NGINX, mongoDBなど様々なフィルターがあるのでぜひ使ってみてください。