2026年9月19日
2026年9月19日
WordPressのアクセスログを解析してセキュリティ侵害を早期に見つける方法
改ざんや乗っ取りに気づくきっかけの多くは、サイトの表示がおかしくなってからです。しかしその前に、アクセスログには「ログイン試行の急増」「見覚えのないPHPファイルへのアクセス」「設定ファイルを探す動き」といった兆候が残っていることがよくあります。この記事では、WordPressサイトのアクセスログのどこを見ればよいか、優先度の高い順に確認ポイントと具体的なコマンドを紹介し、怪しい行を見つけたときの次の一手までを説明します。
アクセスログの場所と読み方
VPSや専用サーバーでは、ログは次の場所にあることが多いです。
- Apache(Debian / Ubuntu系):
/var/log/apache2/access.log - Apache(RHEL系):
/var/log/httpd/access_log - Nginx:
/var/log/nginx/access.log
古いログは access.log.1、access.log.2.gz のように日ごとや週ごとに分けられ、一定期間で消えていきます。何日分残るかは logrotate の設定次第で、既定では数週間程度のことが多いため、調査が必要になったらまず別の場所へコピーして保全します。レンタルサーバーでは、コントロールパネルからダウンロードする形式が一般的です。
標準的な combined 形式では、1行が次のように並びます。
203.0.113.50 - - [28/Oct/2026:09:12:45 +0900] "POST /wp-login.php HTTP/1.1" 200 4521 "-" "Mozilla/5.0 ..."
スペースで区切ると、1番目が接続元IP、6〜8番目がリクエスト(メソッド・パス・プロトコル)、9番目がステータスコード、10番目が応答サイズです。以下のコマンドはこの並びを前提にしています。ログの形式を変えている場合は列番号を合わせてください。
CDNやリバースプロキシを経由している場合、1番目には利用者ではなくプロキシのアドレスが記録されます。本当の接続元をログに残す設定(Apacheの mod_remoteip、Nginxの realip モジュールなど)をしておかないと、IP別の集計に意味がなくなります。
確認ポイント1:uploads 配下のPHPへのアクセス
最も優先して確認したいのがこれです。wp-content/uploads/ は画像や文書を置く場所で、正常な運用ではここにあるPHPが外から呼ばれることはほとんどありません。ここへのリクエストがステータス200で応答しているなら、バックドア(不正に設置された操作用のファイル)が動いている可能性があります。
# uploads 配下の .php へのリクエストで、200 を返したもの
grep -E '"(GET|POST) /wp-content/uploads/[^ ]*\.php' access.log | awk '$9 == 200'
# 圧縮済みの過去ログも含めて調べる
zgrep -E '"(GET|POST) /wp-content/uploads/[^ ]*\.php' access.log* | awk '$9 == 200'
同じ考え方で、ルート直下やプラグインのフォルダにある「見覚えのないPHP」へのPOSTも注意が要ります。特に、ほかのページを経由せず特定のファイルだけにPOSTが繰り返されているパターンは、外部から操作されている典型です。
確認ポイント2:ログイン試行と、成功したログイン
wp-login.php と xmlrpc.php へのPOSTは、パスワード総当たり攻撃の対象です。IPごとの回数を数えると、攻撃の規模が分かります。
# wp-login.php への POST を接続元IPごとに数える(多い順に上位20件)
awk '$6 == "\"POST" && $7 ~ /^\/wp-login\.php/ {print $1}' access.log | sort | uniq -c | sort -rn | head -20
# xmlrpc.php への POST も同様に
awk '$6 == "\"POST" && $7 ~ /^\/xmlrpc\.php/ {print $1}' access.log | sort | uniq -c | sort -rn | head -20
試行が多いこと自体は、公開されているWordPressではよくあることで、それだけで侵害されたとは言えません。より重要なのは「成功したログイン」です。WordPressの標準のログイン画面では、ログインに失敗すると同じ画面が200で表示され、成功するとリダイレクト(302)で管理画面へ移ります。
# wp-login.php への POST が 302 を返した行(ログイン成功の可能性が高い)
awk '$6 == "\"POST" && $7 ~ /^\/wp-login\.php/ && $9 == 302 {print $1, $4}' access.log
ここに自分たちの接続元でないIPが出ていたら、アカウントが乗っ取られた可能性を疑います。ただし、パスワードリセットやログアウトなど他の操作でも302になることがあり、ログイン系のプラグインが挙動を変えている場合もあるので、時刻と前後の行を見て判断してください。
確認ポイント3:設定ファイルや秘密情報を探す動き
攻撃者は、wp-config.php のバックアップ、.env、.git フォルダ、データベースのダンプなど、置き忘れられたファイルを機械的に探します。404や403が返っていれば問題ありませんが、200が返っていたら情報が持ち出された可能性があります。
grep -E '"GET /[^ ]*(\.env|\.git/|wp-config\.php[^ ]+|\.sql|\.zip|\.tar\.gz)' access.log | awk '$9 == 200'
ここで200が見つかったら、そのファイルを公開領域から外し、含まれていたパスワードやキーをすべて変更します。
確認ポイント4:脆弱性スキャンとユーザー名の収集
特定のプラグインのパスに対して404が大量に出ているのは、既知の脆弱性を持つプラグインが入っていないかを探すスキャンです。これは「調べられている」段階で、多くは自動化された無差別のものです。ただし、スキャンされたプラグインが実際にインストールされていて200が返っている場合は、そのプラグインが最新版かを急いで確認してください。
/?author=1 や /wp-json/wp/v2/users へのアクセスは、ログインに使うユーザー名を集める動きです。これ自体は直接の被害ではありませんが、総当たり攻撃の前段階として現れることがあります。
# 404 が多いパスの上位(何が探されているかの把握)
awk '$9 == 404 {print $7}' access.log | sort | uniq -c | sort -rn | head -30
怪しい行を見つけたら、ログ以外で裏付ける
アクセスログだけでは「何が実行されたか」までは分かりません。兆候を見つけたら、サーバー上の状態と照らし合わせます。作業前にファイルとデータベースのバックアップ(調査用の保全)を取ってください。
# 指定日以降に変更されたPHPファイル(日付は調査対象に合わせる)
find /var/www/html -type f -name "*.php" -newermt "2026-10-20"
# WP-CLI:コアファイルが公式の配布物と一致するか
wp core verify-checksums
# WP-CLI:WordPress.org のプラグインが配布物と一致するか
wp plugin verify-checksums --all
# 管理者権限のユーザー一覧(見覚えのないユーザーがいないか)
wp user list --role=administrator
不審なファイルやユーザーが見つかった場合は、ファイルを消すだけで終わらせず、侵入経路(脆弱なプラグイン、漏れたパスワードなど)を特定して塞ぐ、全管理者のパスワードを変える、wp-config.php の認証用キー(ソルト)を変更する、という対応を一緒に行います。被害の範囲が分からない場合は、サーバー会社やセキュリティの専門業者に相談するのが確実性の高い進め方です。
継続的に見るための仕組み
毎回手作業でログを読むのは続きません。次のような仕組みを組み合わせると負担を減らせます。
- fail2ban:ログを監視し、ログイン試行が多いIPを自動で遮断します
- GoAccess などのログ解析ツール:アクセスの傾向をまとめて表示でき、急な変化に気づきやすくなります
- cron で定期チェック:上で紹介した「uploads のPHPへの200」などのコマンドを毎日実行し、該当があればメールで知らせる
- セキュリティプラグイン:Wordfence などは、WordPress側でログイン試行や不審なアクセスを記録・通知する機能を持っています。機能の範囲は無料版と有料版で異なり、内容も変わることがあります(2026年10月現在)
なお、アクセスログのIPアドレスは個人に関する情報として扱われる場合があります。保存期間を決め、不要になったログは適切に処分し、プライバシーポリシーの記載と合わせておくと安心です。
まとめ
- ログは数週間で消えることが多いので、異変に気づいたらまずコピーして保全する
- 最優先は uploads 配下のPHPへの200応答。バックドアの典型的な痕跡
- ログイン試行の多さより、見覚えのないIPからの「成功したログイン(POSTへの302)」を重視する
.envや設定ファイルのバックアップに200が返っていたら、含まれていた秘密情報をすべて変更する- ログの兆候は、ファイルの変更日時、チェックサム、管理者ユーザー一覧で裏付ける
- fail2ban や定期チェックで、見る作業を仕組みにする