2026年10月12日
2026年10月12日
サーバーへの不正アクセスを検知する方法|認証ログの見方・fail2ban・ファイル改ざん検知・WordPress のログイン監視と通知
サーバーへの不正アクセスを検知するには、「入口の試行を見る(認証ログ)」「繰り返す試行を止める(fail2ban)」「入られた後の痕跡を見る(ファイル改ざん検知)」「WordPress 自身のログインを見る」の 4 つの層を重ねます。1 つの道具で全部を見ることはできず、どの層も「普段の状態」を知っていないと異常が分からないので、まずログを読む習慣から始めます。
結論を先にまとめます。
- SSH への試行は
journalctl -u ssh(または/var/log/auth.log、RHEL 系は/var/log/secure)とlastbで見ます。公開サーバーでは 1 日に数百〜数千件の失敗が普通にあり、それ自体は異常ではありません。見るべきは「成功した見知らぬログイン」です。 - fail2ban は、一定時間内に失敗を繰り返した IP をファイアウォールで遮断します。
jail.localにsshdを有効化するだけで SSH の総当たりは大半が止まります。 - ファイルの改ざん検知(AIDE / Tripwire)は、「入られてしまった後」に気づくための層です。WordPress のコアとテーマ・プラグインを対象にします。
- WordPress 側では、ログイン試行の記録と制限、管理者アカウントの追加の監視を、プラグインか自前のフックで行います。
- 検知しても通知が来なければ意味がありません。メールか chat への通知を最初に用意します。
不正アクセスの検知とは
不正アクセスの検知とは、サーバーに対する「入ろうとする試み」と「入った後の痕跡」を記録から見つけることです。試みの大半は自動化された総当たりで、止めるのは比較的簡単です。難しいのは、正しいパスワードや盗まれた鍵で入られた場合で、こちらは「いつもと違う」ことに気づく必要があります。この記事は Linux の VPS・専用サーバーで WordPress を運用している前提で書いています。共用のレンタルサーバーでは OS 側の層は事業者の管轄なので、WordPress 側の層だけが対象になります。
層 1: 認証ログを読む
SSH の失敗と成功
systemd を使う Debian / Ubuntu では、SSH のログは journal に入ります。
# 直近の SSH の記録(Ubuntu は ssh、Debian / RHEL 系は sshd)
sudo journalctl -u ssh --since "24 hours ago"
# 失敗した試行の多い IP を数える
sudo journalctl -u ssh --since "24 hours ago" | grep "Failed password" | awk '{print $(NF-3)}' | sort | uniq -c | sort -rn | head
# 成功したログインだけを見る(ここに見覚えのない IP があれば重大)
sudo journalctl -u ssh --since "7 days ago" | grep "Accepted"
journal を使わない環境では /var/log/auth.log(Debian / Ubuntu)、/var/log/secure(RHEL 系)を同じように grep します。
失敗したログインの記録は lastb、成功は last でも一覧できます。
sudo lastb | head -n 20 # 失敗
last | head -n 20 # 成功と再起動
見るときの基準
| 記録 | 普通の状態 | 確認が必要な状態 |
|---|---|---|
Failed password |
公開サーバーでは毎日多数 | 特定のユーザー名(自分の管理者名)に集中している |
Accepted publickey / Accepted password |
自分の IP、自分の作業時間 | 見知らぬ IP、深夜、使っていないユーザー |
Invalid user |
多数(root, admin, test など) | 自分のサイト名や社員名を使っている |
sudo の記録(journalctl _COMM=sudo) |
自分の操作 | 見覚えのないコマンド |
パスワード認証を止めて鍵認証だけにし(PasswordAuthentication no)、可能なら SSH を管理者の IP だけに絞ると、この層のノイズは大きく減ります。
Web サーバーのログ
WordPress への試行は Web サーバーのアクセスログに出ます。wp-login.php と xmlrpc.php への POST の数を見ます。
# Nginx の例。wp-login.php への POST が多い IP
grep 'POST /wp-login.php' /var/log/nginx/access.log | awk '{print $1}' | sort | uniq -c | sort -rn | head
# xmlrpc.php への POST(使っていなければ全部が不要な試行)
grep 'POST /xmlrpc.php' /var/log/nginx/access.log | wc -l
XML-RPC を使っていないなら、XML-RPC を無効化してこの入口を塞ぎます。
層 2: fail2ban で繰り返す試行を止める
fail2ban は、ログを正規表現(filter)で監視し、findtime 秒以内に maxretry 回失敗した IP を、bantime の間ファイアウォールで遮断します(action)。監視対象と条件の組を jail と呼びます。
sudo apt install fail2ban # Debian / Ubuntu
sudo dnf install fail2ban # RHEL 系(EPEL)
設定は /etc/fail2ban/jail.conf を直接編集せず、/etc/fail2ban/jail.local に変更分だけを書きます(読み込みは jail.conf → jail.d/*.conf → jail.local → jail.d/*.local の順で、後のものが優先されます)。
[DEFAULT]
bantime = 1h
findtime = 10m
maxretry = 5
ignoreip = 127.0.0.1/8 ::1 203.0.113.10 # 自分の管理用 IP を除外
[sshd]
enabled = true
[nginx-http-auth]
enabled = true
sshd は SSH の失敗、nginx-http-auth は Nginx の Basic 認証の失敗を監視する同梱の jail です。Apache なら apache-auth があります。
WordPress のログイン用 jail
WordPress のログイン失敗は、標準ではサーバーのログに「失敗」として残らないため、fail2ban が拾う材料を作る必要があります。方法は 2 つです。
- アクセスログの POST を数える:
wp-login.phpへの POST そのものを失敗とみなします。正しいログインも 1 回数えますが、maxretryを 5〜10 にしておけば通常の利用で遮断されることはほぼありません。 - WordPress 側で syslog に書く:
wp_login_failedフックで失敗を syslog に記録し、それを filter で読む方法です。WP fail2ban のようなプラグインがこの方式で、専用の filter を同梱しています。
方法 1 の filter と jail の例です。
# /etc/fail2ban/filter.d/wordpress-login.conf
[Definition]
failregex = ^<HOST> .* "POST /wp-login.php
^<HOST> .* "POST /xmlrpc.php
ignoreregex =
# /etc/fail2ban/jail.local に追加
[wordpress-login]
enabled = true
port = http,https
filter = wordpress-login
logpath = /var/log/nginx/access.log
maxretry = 8
findtime = 10m
bantime = 2h
filter が意図どおりに一致するかは fail2ban-regex で確かめます。
sudo fail2ban-regex /var/log/nginx/access.log /etc/fail2ban/filter.d/wordpress-login.conf
sudo systemctl restart fail2ban
sudo fail2ban-client status
sudo fail2ban-client status wordpress-login
Cloudflare などの CDN を通している場合、アクセスログの先頭の IP は CDN のものになります。先に Nginx の real_ip_header CF-Connecting-IP で実 IP を復元しないと、CDN の IP を遮断してサイト全体が見えなくなります。
層 3: ファイルの改ざんを検知する
入られた後の典型的な痕跡は、テーマやプラグインの PHP に追記されたコード、uploads に置かれた PHP、wp-config.php の変更、.htaccess への転送の追加です。これを見つけるのがファイル整合性監視で、AIDE と Tripwire が代表です。
# AIDE(Debian / Ubuntu)
sudo apt install aide
sudo aideinit # 基準データベースの作成
sudo aide --check # 差分の確認
# 正しい変更の後は aide --update を実行し、新しいデータベースに差し替える
Tripwire の導入と、WordPress のディレクトリを監視対象にするポリシーの書き方はTripwire でファイルの改ざんを検知する方法に詳しくまとめています。root 権限のない環境では、WP-CLI の wp core verify-checksums と wp plugin verify-checksums --all を日次で実行する方法が代わりになります。
層 4: WordPress 側のログインとアカウントを監視する
OS 側の層が見えない共用サーバーでも、この層は使えます。
- ログイン試行の記録と制限: Wordfence や Limit Login Attempts Reloaded のようなプラグインが、失敗の記録と一時的な遮断を行います。導入手順はWordfence の初期設定を参照してください。
- 管理者アカウントの追加の監視: 侵入後によく行われるのが管理者ユーザーの追加です。
user_registerフックで通知を送るか、定期的にwp user list --role=administratorを確認します。 - 2 要素認証: パスワードが漏れても入られないようにする層です。検知ではなく予防ですが、ログの読み方を楽にします。
- ファイル変更のスキャン: Wordfence のスキャンは、WordPress.org のオリジナルと比べてコアとプラグインの改ざんを報告します。層 3 の代わりになります。
自前で最小限の通知を入れるなら、次のコードを子テーマの functions.php か小さなプラグインに置きます。
<?php
// 管理者ユーザーが追加されたらメールで通知する
add_action( 'set_user_role', function ( $user_id, $role ) {
if ( 'administrator' !== $role ) {
return;
}
$user = get_userdata( $user_id );
wp_mail(
get_option( 'admin_email' ),
'[' . get_bloginfo( 'name' ) . '] 管理者ユーザーが追加・変更されました',
"ユーザー: {$user->user_login}\nメール: {$user->user_email}\n時刻: " . current_time( 'mysql' ) . "\nIP: " . ( $_SERVER['REMOTE_ADDR'] ?? '' )
);
}, 10, 2 );
通知を受ける
検知の仕組みは、通知が届かなければ動いていないのと同じです。最低限、次の 3 つを用意します。
| 層 | 通知の方法 |
|---|---|
| fail2ban | action = %(action_mwl)s でメール(遮断した IP と該当ログを送る)。遮断の件数が急に増えたときに気づける |
| ファイル改ざん検知 | AIDE / Tripwire の日次レポートをメールで受け取る。差分が無い日は短い |
| WordPress | プラグインの通知メールか、上のような自前のフック |
メールが埋もれるなら、chat(Slack や Teams の Incoming Webhook)へ送る小さなスクリプトを挟みます。重要なのは、「普段は静かで、何かあったときだけ鳴る」状態に調整することです。毎日大量に届く通知は読まれなくなります。
IDS / IPS について
Suricata や Snort のようなネットワーク型の侵入検知システム(IDS)、OSSEC / Wazuh のようなホスト型の IDS もあります。これらは上の 4 層をまとめて扱える代わりに、導入と調整に時間がかかり、1 台の WordPress サーバーでは過剰になりがちです。複数台を運用している、あるいは監査の要件がある場合に検討してください。1 台なら、この記事の 4 層で実用上の多くが賄えます。
よくある質問
毎日何千件も Failed password が出ます。侵入されていますか
公開サーバーでは普通の状態です。自動化された総当たりで、鍵認証だけにしていれば成功しません。見るべきは Accepted の行に見知らぬ IP が無いかどうかです。件数自体を減らしたいなら、fail2ban と SSH の IP 制限、ポート番号の変更が効きます。
fail2ban で自分が遮断されました
sudo fail2ban-client set sshd unbanip <自分の IP> で解除し、jail.local の ignoreip に自分の IP を加えてください。固定 IP が無い場合は、VPN や踏み台サーバーの IP を登録します。
Cloudflare を使っていると fail2ban が効きません
アクセスログに記録される IP が Cloudflare のものになっているためです。Nginx の set_real_ip_from と real_ip_header CF-Connecting-IP で実 IP に戻してから fail2ban を動かします。Cloudflare 側の WAF でレート制限をかける方法もあります(Cloudflare の設定)。
共用サーバーでは何ができますか
OS 側のログや fail2ban は触れないので、層 4(WordPress 側)に集中します。ログイン試行の制限、2 要素認証、ファイル変更のスキャン、管理者追加の通知の 4 つです。サーバー会社が提供する WAF やログの閲覧機能があれば併用してください。
侵入の痕跡を見つけたらどうすればよいですか
まずサイトの公開を止めるかパスワードをすべて変え、ログとファイルを消さずに複製して保全します。その後に駆除か再構築です。手順はサーバーがハッキングされたときの初動対応とWordPress のハッキング復旧手順にまとめています。自分で進めるのが難しい場合の依頼の流れは乗っ取り・感染時の復旧依頼を参照してください。
まとめ
- 不正アクセスの検知は、認証ログ・fail2ban・ファイル改ざん検知・WordPress のログイン監視の 4 層で行い、どの層も通知までつなげます。
- SSH は鍵認証と
jail.localのsshdで総当たりの大半が止まり、見るべきは成功した見知らぬログインです。WordPress のログインはwp-login.phpへの POST を fail2ban で数えるか、プラグインで制限します。 - 入られた後に気づく層として AIDE / Tripwire か WP-CLI の checksums を日次で回し、管理者アカウントの追加は即時に通知します。
関連記事
- Tripwire でファイルの改ざんを検知する方法|ポリシーの書き方・WordPress の PHP ファイルを監視する設定
- nmap の使い方とポートスキャンの基本|自分のサーバーの公開ポートを確認する手順
- Wordfence の初期設定
- WordPress の XML-RPC を無効化してセキュリティを高める
- サーバーがハッキングされたときの初動対応
参考: fail2ban – How fail2ban works(GitHub Wiki)、jail.conf(5) マニュアル、AIDE – Advanced Intrusion Detection Environment、Open Source Tripwire
更新履歴: 2026-11-09 全面改訂(定型文の本文を、認証ログの読み方、fail2ban の設定と WordPress 用 jail、ファイル改ざん検知、WordPress 側の監視と通知の 4 層構成に置き換え)。この記事はワードプレス博士(ライトセンド株式会社)が運営しています。