Webサーバー(Nginx)をインターネット上に公開すると、存在しない管理画面や脆弱性ファイルを探索するボットのスキャン、Basic認証への総当たり攻撃、不正なHTTPリクエストなどが頻繁に発生します。
そこで今回は、AlmaLinux 10環境に構築した「Nginx」を「Fail2ban」で保護し、不審なアクセスや認証失敗を繰り返すIPアドレスを自動的に遮断(BAN)する設定手順を解説します。
本手順は、すでにAlmaLinux 10へFail2ban(基本設定・SSH保護)およびNginxが導入されている環境を前提としています。
作業工程
作業工程は下記のとおりです。
- Nginx保護用Jailの概要(標準Jail)
- 設定ファイル(jail.local)への追記(backend = auto の指定)
- 設定ファイルのチェック・事前テスト(--test / -d / fail2ban-regex)
- 設定の再読み込み(fail2ban-client reload)
- 動作確認とステータス確認(fail2ban-client & firewalld)
- Webサーバー運用時の注意点(誤BAN対策・ログ確認)
Nginx保護用Jailの概要(標準Jail)
Fail2banには、Nginxのエラーログやアクセスログを監視するための標準フィルタ(検知パターン)とJail(監視・遮断ルール)があらかじめ用意されています。用途に応じて必要なJailを有効化します。
- [nginx-http-auth](Basic認証の総当たり対策)
- Nginxのエラーログを監視し、Basic認証などに連続して失敗したIPアドレスを遮断します。
- [nginx-botsearch](悪質ボット・脆弱性スキャン対策)
- Nginxのエラーログを監視し、存在しない管理画面や設定ファイル(phpmyadmin、.envなど)を手当たり次第に探索するスキャナーを検知して遮断します。
- [nginx-bad-request](不正リクエスト・400エラー対策)
- Nginxのアクセスログを監視し、構文エラーなどの不正なリクエスト(HTTP 400 Bad Request)を繰り返すIPアドレスを遮断します。
- [nginx-limit-req](過剰アクセス・レート制限超過対策)
- Nginx側のレート制限機能(limit_req_zone / limit_req)によってエラーログに記録された過剰アクセス元を、さらにファイアウォールレベルで遮断します(※Nginx側でのレート制限設定が必要です)。
設定ファイル(jail.local)への追記
既存の「/etc/fail2ban/jail.local」をバックアップした後でNginx用のJail設定を追記します。
cd /etc/fail2ban sudo cp -p jail.local jail.local_$(date +%Y%m%d-%H%M%S) sudo vi jail.local
「[DEFAULT]」や既存の設定([sshd]等の設定をしている場合)の下に、以下の内容を追記します。
記載している設定内容(ログパス、検知期間、試行回数、遮断時間など)はあくまでも設定の一例です。ご自身の環境で実際に利用しているJailのみを有効化し、運用方針に合わせて調整してください。
# Basic認証の失敗対策 [nginx-http-auth] enabled = true backend = auto port = http,https logpath = /var/log/nginx/*error.log findtime = 10m maxretry = 5 bantime = 1h # 悪質ボットのスキャン対策 [nginx-botsearch] enabled = true backend = auto port = http,https logpath = /var/log/nginx/*error.log findtime = 10m maxretry = 3 bantime = 1h # 不正リクエスト(400エラー)対策 [nginx-bad-request] enabled = true backend = auto port = http,https logpath = /var/log/nginx/*access.log findtime = 10m maxretry = 5 bantime = 1h # レート制限超過対策(※Nginx側でlimit_reqを使用している場合のみ行頭の#を削除して有効化) #[nginx-limit-req] #enabled = true #backend = auto #port = http,https #logpath = /var/log/nginx/*error.log #findtime = 10m #maxretry = 5 #bantime = 1h
本環境のNginxではレート制限(limit_req)を設定していないため、「[nginx-limit-req]」は行頭に「#」を付けてコメントアウトしています(Nginx側でlimit_reqを使用している場合のみ、「#」を外して有効化してください)。
設定のポイント
- backend = auto を必ず指定する理由
-
基本設定記事の「[DEFAULT]」で「backend = systemd」を指定している場合、そのままではFail2banが「systemd-journald」だけを見に行き、「logpath」に指定したNginxのログファイルが無視されてしまいます。
Nginxのようにテキストファイルへログを出力するサービスを監視する場合は、各Jailに「backend = auto」を明記してファイル監視に切り替える必要があります。 - logpath のワイルドカード指定
- バーチャルホストごとに「site1_access.log」「site1_error.log」のようにログファイルを分けている場合でも、「*access.log」「*error.log」と記述しておくことで一括で監視対象に含められます。
- ワイルドカードを使わずに複数のログファイルを個別指定する方法
-
特定のログファイルだけを個別に複数指定したい場合は、次のように改行して先頭にスペース(インデント)を入れて並べて記述します(※2行目以降のインデントを忘れると設定エラーになるためご注意ください)。
logpath = /var/log/nginx/error.log /var/log/nginx/site1_error.log /var/log/nginx/site2_error.log
設定ファイルのチェック・事前テスト
編集が終わったら、Fail2banへ反映させる前に構文・設定読み込み・フィルタの動作を確認します。
構文チェック(--test)
sudo fail2ban-client --test
「OK: configuration test is successful」と表示されれば構文およびログパスの指定に問題はありません。
反映内容のダンプ確認(-d オプション)
設定項目名のスペルミスで無視されていないか、およびバックエンドが正しくファイル監視になっているかを確認します。
sudo fail2ban-client -d | grep nginx
設定した各Jail名や「logpath」「maxretry」「bantime」などが意図通りに出力されていることを確認してください。
標準フィルタがNginxのログに反応するかテストする
Nginxのログファイルに対して、Fail2banの標準フィルタが正しくマッチするかを確認できます。
sudo fail2ban-regex /var/log/nginx/error.log /etc/fail2ban/filter.d/nginx-botsearch.conf sudo fail2ban-regex /var/log/nginx/access.log /etc/fail2ban/filter.d/nginx-bad-request.conf
実行結果の「Results」欄の下にある「Lines: ...」の行を確認し、該当する不正アクセスが過去のログにあれば「Matched」の欄に一致した件数が表示されます(該当ログがまだ無い場合は「0 matched」となります)。
以下は実行結果の例です。
Running tests ##### 中略 ##### Results ======= Failregex: 2 total ##### 中略 ##### Lines: 27 lines, 0 ignored, 2 matched, 25 missed [processed in 0.00 sec] Missed line(s): too many to print. Use --print-all-missed to print all 25 lines
なお、「Missed line(s): too many to print. ...」と表示されるのは通常のアクセスログなど攻撃に該当しない行(missed)が多いため省略されただけであり、エラーではありません。
詳しく確認したい場合は以下のオプションを付けて実行してください。
- --print-all-matched:フィルタに一致して検知された行(matched)だけを一覧表示する
- --print-all-missed:フィルタに該当しなかった行(missed)をすべて表示する
設定の再読み込み(reload)
すでにFail2banが稼働している場合は、現在BAN中のIPや監視状態を維持したまま設定を反映させるため「reload」を実行します。
sudo fail2ban-client reload
設定反映時の「reload」と「restart」の違いは以下のとおりです。すでにBANされているIPがある場合は、不要なBANの解除や監視状態のリセットを避けるためにも「reload」で反映させるのが安全です。
- reload(sudo fail2ban-client reload / sudo systemctl reload fail2ban):現在BAN中のIPや監視状態を維持したまま、安全に設定のみを反映できる(推奨)
- restart(sudo systemctl restart fail2ban):サービスをいったん停止して再起動するため、停止時に「firewalld」上のBANルールや一時的なカウントがいったんリセット(解除)されてしまう
動作確認とステータス確認
追加したNginx用のJail(nginx-bad-request, nginx-botsearch, nginx-http-auth)が正しく有効化されているかを確認します。
有効化されているJail一覧の確認
sudo fail2ban-client status
Status |- Number of jail: 4 `- Jail list: nginx-bad-request, nginx-botsearch, nginx-http-auth, sshd
各Jailの詳細ステータスとfirewalldの確認
個別のJailの検知状況と、firewalld側に登録された遮断ルールを確認します。
各jailの詳細ステータスの確認方法
sudo fail2ban-client status nginx-bad-request sudo fail2ban-client status nginx-botsearch sudo fail2ban-client status nginx-http-auth
以下は「nginx-bad-request」のステータスを表示した際の例です。
Status for the jail: nginx-bad-request |- Filter | |- Currently failed: 1 | |- Total failed: 104 | `- File list: /var/log/nginx/access.log /var/log/nginx/site1_access.log `- Actions |- Currently banned: 0 |- Total banned: 3 `- Banned IP list:
表示される各項目(Filter / Actions)の意味は以下のとおりです。
- Filter(ログ監視・検知状況)
-
- Currently failed:現在「findtime」の期間内で検知されている失敗回数(しきい値に達する前のカウント中)
- Total failed:サービス起動後からこれまでにフィルタが検知した累計回数
- File list:このJailが実際に監視しているログファイルの一覧(「logpath」で指定したワイルドカードや複数ファイルが正しく認識されているかをここで確認できます)
- Actions(遮断・BAN状況)
-
- Currently banned:現在BAN(遮断)されているIPアドレスの数
- Total banned:サービス起動後からこれまでにBANしたIPアドレスの累計数
- Banned IP list:現在BAN中のIPアドレス一覧(遮断中のIPがない場合は空欄になります)
firewalldのリッチルールの確認方法
現在適用されているリッチルールを確認するには、以下のコマンドを実行します。
sudo firewall-cmd --list-rich-rules
rule family="ipv4" source address="xxx.xxx.xxx.xxx" port port="http" protocol="tcp" reject type="icmp-port-unreachable" rule family="ipv4" source address="yyy.yyy.yyy.yyy" port port="https" protocol="tcp" reject type="icmp-port-unreachable"
なお、この時点でBANされているIPアドレス(遮断ルール)が1つもない場合、「sudo firewall-cmd --list-rich-rules」を実行しても何も表示されません。
Webサーバー運用時の注意点(誤BAN対策・ログ確認)
誤BANへの注意と対策
Webサイト側の構成やアクセス状況によっては、リバースプロキシ(CDNなど)のIPを誤って遮断してしまったり、「nginx-limit-req」を厳しく設定しすぎて画像・CSS/JSを同時に読み込む正常な訪問者を誤ってBANしてしまうことがあります。
そこで誤ったBANを防ぎ、安全に運用するためには、あらかじめ以下の対策を行っておくことが有効です。
- 自宅やオフィスの固定IPを「[DEFAULT]」の「ignoreip」に登録する:ignoreipに登録されたIPはFail2banの遮断対象から除外されるため、管理作業や動作確認中に誤って自分自身をBANして閉め出される事故を防げます
- 運用開始直後は「maxretry」を少し大きめに設定する:しきい値に余裕を持たせてログの様子を見ることで、通常の訪問者が誤ってBANされるリスクを抑えながら環境に合った値へ調整できます
万が一誤ってBANされた場合は、Jail名を指定した「unbanip」または全Jail一括の「unban」で即座に解除できます。
# 全Jailから一括で解除する場合 sudo fail2ban-client unban 遮断を解除したいIPアドレス # 特定のJailのみから解除する場合(nginx-botsearchを指定する場合の例) sudo fail2ban-client set nginx-botsearch unbanip 遮断を解除したいIPアドレス
ログの確認方法
BANの検知履歴は「/var/log/fail2ban.log」、実際のWebアクセス詳細はNginxのログファイルから確認します。
「tail -f」は現在のログをリアルタイムで追跡するコマンドのため、時間が経過した過去の履歴を確認したい場合は「grep」や「less」、ローテーション済みのログも含めて検索できる「zgrep」を使用します。
# Fail2banの検知・BANログをリアルタイムで確認 sudo tail -f /var/log/fail2ban.log # 過去のBAN履歴を遡って確認(ファイル全体から「Ban」を抽出) sudo grep "Ban" /var/log/fail2ban.log # ログローテーション済みの過去ログも含めて確認 sudo zgrep "Ban" /var/log/fail2ban.log* # 遮断されたIPがどのようなURLへアクセスしていたか調査 sudo grep "xxx.xxx.xxx.xxx" /var/log/nginx/*access.log /var/log/nginx/*error.log
なお、「/var/log/fail2ban.log」には主に以下のキーワードで状態が記録されるため、目的に応じて「Found」や「Unban」などに置き換えて検索することもできます。
- Found:フィルタに一致する不審なアクセスが検知された
- Ban:検知回数が「maxretry」に達し、IPアドレスが遮断された
- Unban:「bantime」の経過や手動操作により遮断が解除された
まとめ
以上が、AlmaLinux 10のFail2banでNginxを保護する基本設定の手順です。
SSHやメールサーバー向けの「backend = systemd」と異なり、テキストファイルにログを出力するNginxでは「backend = auto」を明記して「logpath」を有効にするのが最大のポイントになります。
なお、WordPress(wp-login.phpやxmlrpc.php)への不正ログイン攻撃など、標準のJailだけではカバーできないWebアプリ固有の攻撃を防ぎたい場合は、Fail2banのカスタムフィルタを作成して対策します。具体的な手順は以下の別記事で解説しています。
- AlmaLinux 10:Fail2banカスタムフィルタの作り方(WordPress保護の実践例)(※公開後にリンクを追加予定)
コメント