2026年5月29日

2026年5月29日

Apacheのログから攻撃を見つける方法|grep・awkでの解析とfail2banでの自動ブロック

Web サーバーへの攻撃の多くは、Apache のアクセスログとエラーログに痕跡が残ります。この記事では、ログの場所と読み方、攻撃の痕跡を探すコマンド、見つけたパターンを fail2ban で自動ブロックする設定を順に説明します。fail2ban の設定項目は、2026年11月時点で fail2ban の公式リポジトリにある設定ファイルで確認したものです。

ログの場所と形式

OS アクセスログ エラーログ
Debian・Ubuntu /var/log/apache2/access.log /var/log/apache2/error.log
RHEL・AlmaLinux・Rocky Linux /var/log/httpd/access_log /var/log/httpd/error_log

バーチャルホストごとに CustomLog や ErrorLog で別のファイルを指定している場合は、そのファイルを見ます。設定の場所は grep -R "CustomLog\|ErrorLog" /etc/apache2/(RHEL 系は /etc/httpd/)で確認できます。Ubuntu ではログを読むのに root 権限か adm グループが必要です。

アクセスログは多くの場合 combined 形式で、1行は次のように並びます。

203.0.113.5 - - [10/Nov/2026:10:15:32 +0900] "POST /wp-login.php HTTP/1.1" 200 4521 "-" "Mozilla/5.0 ..."

空白で区切ると、1番目がアクセス元の IP アドレス、4番目が日時、6番目がメソッド(先頭に " が付く)、7番目がパス、9番目がステータスコードです。以下の awk の例はこの並びを前提にしています。LogFormat を変えている場合や、先頭にホスト名が付く vhost_combined 形式では番号がずれるので合わせてください。

ローテーション済みの古いログは access.log.1、access.log.2.gz のような名前で残ります。圧縮されたファイルは zcat や zgrep で読みます。

アクセスの多い IP アドレスを調べる

まず、どこから多くのアクセスが来ているかを見ます。

# アクセス数の多い IP アドレス上位20件
sudo awk '{print $1}' /var/log/apache2/access.log | sort | uniq -c | sort -rn | head -20

# 404 を多く返している IP アドレス(存在しないファイルを探し回るスキャンの目安)
sudo awk '$9 == 404 {print $1}' /var/log/apache2/access.log | sort | uniq -c | sort -rn | head -20

# 特定の時間帯だけ見る(例: 11月10日の10時台)
sudo grep '10/Nov/2026:10:' /var/log/apache2/access.log | awk '{print $1}' | sort | uniq -c | sort -rn | head

アクセス数が多いだけで攻撃とは限りません。検索エンジンのクローラーや監視サービスも上位に来るので、次の項目のようにアクセス先と組み合わせて判断します。

攻撃によく見られるパターン

WordPress のログイン画面への総当たり

wp-login.php と xmlrpc.php への POST が短い時間に繰り返されている場合は、パスワードの総当たりの可能性があります。

sudo grep -E '"POST /(wp-login|xmlrpc)\.php' /var/log/apache2/access.log \
  | awk '{print $1}' | sort | uniq -c | sort -rn | head -20

設定ファイルや管理ツールを探すスキャン

公開してはいけないファイルや、よく知られた管理ツールのパスへのアクセスです。ステータスが 200 になっているものがあれば、そのファイルが実際に外から読めていないかを確認してください。

sudo grep -iE '"(GET|POST|HEAD) /[^ ]*(\.env|\.git/|wp-config\.php\.|phpmyadmin|\.sql|\.bak)' \
  /var/log/apache2/access.log | awk '{print $1, $7, $9}' | sort | uniq -c | sort -rn | head -30

SQL インジェクション・ディレクトリトラバーサル・XSS の試行

パスやクエリ文字列に SQL の構文、../、<script> などが含まれるアクセスです。URL エンコードされた形(%20、%2e%2e、%3Cscript)も探します。

sudo grep -iE 'union(\+|%20| )+select|information_schema|\.\./|%2e%2e|<script|%3Cscript' \
  /var/log/apache2/access.log | awk '{print $1, $7, $9}' | head -50

不審なアップロード先へのアクセス

wp-content/uploads/ 以下の .php ファイルが呼ばれている場合は、アップロードされたバックドアが使われている可能性があります。ステータスが 200 なら、そのファイルが実在するかをすぐに確認してください。

sudo grep -E '/wp-content/uploads/[^ ]*\.php' /var/log/apache2/access.log | awk '{print $1, $7, $9}'

エラーログを見る

エラーログには、アクセス制限で拒否されたリクエストや、PHP のエラー、mod_security の検知などが記録されます。普段と比べて急に増えたメッセージがないかを見ます。

# 最新のエラーを追いかけて表示
sudo tail -f /var/log/apache2/error.log

# アクセス制限で拒否されたリクエスト
sudo grep "client denied by server configuration" /var/log/apache2/error.log | tail -20

fail2ban で自動的にブロックする

fail2ban は、ログを監視して条件に合うアクセスを繰り返す IP アドレスを、ファイアウォールで一定時間ブロックするソフトウェアです。Debian・Ubuntu では次のコマンドで入ります(RHEL 系は EPEL リポジトリから入れます)。

sudo apt update
sudo apt install fail2ban

標準のフィルターを使う

fail2ban には Apache 用のフィルターが用意されています。/etc/fail2ban/jail.conf に設定がありますが、すべて無効になっています。jail.conf は更新で上書きされるので直接編集せず、/etc/fail2ban/jail.local に有効にしたいものだけを書きます。

jail 名 見るログ 検知する内容
apache-auth エラーログ Basic 認証などの認証失敗
apache-badbots アクセスログ 既知の悪質なクローラーの User-Agent
apache-noscript エラーログ 存在しないスクリプトの実行要求
apache-overflows エラーログ 異常に長いリクエスト
apache-botsearch エラーログ 管理ツールなどを探すアクセス
# /etc/fail2ban/jail.local
[DEFAULT]
bantime  = 1h
findtime = 10m
maxretry = 5
# 信頼できる接続元(自分のIPアドレスなど)はブロックしない
ignoreip = 127.0.0.1/8 ::1

[apache-auth]
enabled = true
backend = auto

[apache-badbots]
enabled = true
backend = auto

ログの場所は Debian 系・RHEL 系それぞれの既定値が fail2ban 側に設定されているので、標準の場所なら logpath は書かなくてかまいません。backend = auto は、ディストリビューションの初期設定でログの読み方が systemd のジャーナルになっている場合に、ログファイルを読むよう明示するためのものです。

WordPress のログインへの総当たりを止めるフィルター

wp-login.php と xmlrpc.php への POST を数えるフィルターを作ります。

# /etc/fail2ban/filter.d/wordpress-login.conf
[Definition]
failregex = ^<HOST> -[^"]*"POST /(?:wp-login|xmlrpc)\.php
ignoreregex =

このフィルターはログインの成功・失敗を区別せず POST の回数だけを数えるので、findtime の間に maxretry 回を超えると、正しいパスワードで何度もログインした人もブロックされます。サイトの使い方に合わせて回数を調整してください。

# /etc/fail2ban/jail.local に追記
[wordpress-login]
enabled  = true
backend  = auto
port     = http,https
filter   = wordpress-login
logpath  = /var/log/apache2/access.log
maxretry = 10
findtime = 10m
bantime  = 1h

有効にする前に、fail2ban-regex でフィルターが手元のログに一致するかを確かめます。

sudo fail2ban-regex /var/log/apache2/access.log /etc/fail2ban/filter.d/wordpress-login.conf

結果の「Failregex」の件数が 0 なら、ログの形式とフィルターが合っていません。

反映と確認・解除

# 設定を反映
sudo systemctl restart fail2ban

# 動いている jail の一覧
sudo fail2ban-client status

# jail ごとのブロック中の IP アドレス
sudo fail2ban-client status wordpress-login

# 誤ってブロックした IP アドレスを解除
sudo fail2ban-client set wordpress-login unbanip 203.0.113.5

fail2ban の設定全体の流れは「fail2ban で不正アクセスを自動ブロックする設定手順」でも説明しています。

mod_security でリクエストの中身を検査する

ログの解析と fail2ban は、攻撃が記録されたあとに対処する方法です。リクエストの内容を受け付ける時点で検査するには、Apache のモジュールの mod_security(ModSecurity)と、そのルール集の OWASP Core Rule Set(CRS)を使います。Debian・Ubuntu では libapache2-mod-security2 パッケージで入り、インストールするとモジュールが有効になります。

導入直後の設定は SecRuleEngine DetectionOnly(検知してログに記録するだけ)にしておき、正常なアクセスが誤って検知されないかをログで確認してから On(遮断する)に切り替えます。WordPress の管理画面は誤検知が起きやすいので、この確認を省かないでください。導入手順とルールの書き方は「Apacheのmod_securityでWAFを設定する方法」で説明しています。

運用の注意

  • cat で大きなログ全体を表示すると端末が流れて読めません。grep・awk で絞り込むか、less で開いてください。
  • X-Forwarded-For を使うロードバランサーや CDN の後ろにある場合、ログの1番目の欄はプロキシの IP アドレスになります。その場合は mod_remoteip で本来の接続元を記録するよう設定してから解析・ブロックしてください。プロキシの IP アドレスをブロックすると、すべての利用者がアクセスできなくなります。
  • ログは日々増えるので、logrotate で保存期間を決めておきます。設定は「Apacheのログをlogrotateでローテーションする方法」を参考にしてください。
  • 見つかった攻撃が成功していた形跡(uploads 内の PHP が 200 を返している、知らない管理者が増えているなど)がある場合は、ブロックだけでなく侵入の調査が必要です。

お気軽にご相談ください

お見積りへ お問い合わせへ
▲