「WordPress 3分間フッキング」は、WordPressのフック(アクション・フィルター)を活用して、プラグインをインストールせずに簡単にサイトをカスタマイズする方法をわかりやすく解説するシリーズです。あの料理番組「3分間クッキング」のように、短時間で実用的なテクニックをマスターしていきましょう!
WordPress管理画面へのブルートフォース攻撃の脅威
WordPressは世界で最も普及しているCMSであるがゆえに、常に攻撃者のターゲットになっています。特に管理画面へのログインを総当たりで試みる「ブルートフォース攻撃」は、セキュリティ上の大きな脅威となっています。
こうした攻撃は一度に大量のログイン試行を行うため、パスワードが推測されるリスクが高まるだけでなく、サーバーに過剰な負荷をかけてサイトのパフォーマンス低下を引き起こすこともあります。
今回は wp_login_failed
アクションフックを使って、同一IPアドレスからのログイン失敗回数を制限し、ブルートフォース攻撃からサイトを守る方法をご紹介します!
アクションフックを使ってログイン失敗を監視する
今回使用するのは wp_login_failed
というアクションフックです。このフックはログイン失敗時に実行され、失敗したユーザー名を引数として受け取ります。これを利用して、同一IPアドレスからの失敗回数をカウントし、一定回数を超えた場合にログインを一時的にブロックします。

WordPressのアクションフックは、特定のタイミングで「アクション(処理)」を実行するためのフックです。今回はログイン失敗時にアクションを実行し、セキュリティを強化します。
では、具体的なコードを見ていきましょう!
コードの実装
以下のコードを functions.php
に追加します:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 |
// ログイン失敗回数を制限してセキュリティを高める function wp3min_limit_login_attempts($username) { // ログイン失敗のIPアドレスを取得 $ip_address = $_SERVER['REMOTE_ADDR']; // トランジェントの名前を生成(IPアドレスを含める) $transient_name = 'login_attempts_' . md5($ip_address); // 現在の失敗回数を取得(存在しない場合は0) $login_attempts = get_transient($transient_name); $login_attempts = $login_attempts ? $login_attempts : 0; // 失敗回数の上限 $max_attempts = 5; // ブロック時間(秒) $block_time = 1800; // 30分間 // 現在の失敗回数が上限に達しているか確認 if ($login_attempts >= $max_attempts) { // 残りのブロック時間を確認 $time_left = get_option('_transient_timeout_' . $transient_name) - time(); if ($time_left > 0) { // ブロック中のメッセージを表示 $minutes_left = ceil($time_left / 60); wp_die( sprintf( '<h1>ログインがブロックされました</h1>' . '<p>セキュリティのため、このIPアドレスからのログインは一時的にブロックされています。</p>' . '<p>%d分後に再試行してください。</p>' . '<p><a href="%s">サイトのトップページに戻る</a></p>', $minutes_left, home_url() ), 'ログイン制限', array('response' => 403) ); } } // 失敗回数を増やしてトランジェントを更新 $login_attempts++; set_transient($transient_name, $login_attempts, $block_time); // ログに記録(オプション) error_log('WordPress ログイン失敗: IP=' . $ip_address . ', ユーザー名=' . $username . ', 失敗回数=' . $login_attempts); } add_action('wp_login_failed', 'wp3min_limit_login_attempts'); // ログイン成功時に失敗カウンターをリセット function wp3min_reset_login_attempts() { // ログイン成功のIPアドレスを取得 $ip_address = $_SERVER['REMOTE_ADDR']; // トランジェントの名前を生成 $transient_name = 'login_attempts_' . md5($ip_address); // トランジェントを削除 delete_transient($transient_name); } add_action('wp_login', 'wp3min_reset_login_attempts'); |
コードの解説
1. wp3min_limit_login_attempts
関数を定義し、wp_login_failed
アクションフックに登録しています。この関数はログイン失敗時に呼び出されます。
2. アクセス元のIPアドレスを $_SERVER['REMOTE_ADDR']
から取得します。
3. トランジェント(一時的なデータ保存の仕組み)を使って、IPアドレスごとの失敗回数を追跡します。セキュリティのため、IPアドレスはハッシュ化しています。
4. 失敗回数が設定した上限(この例では5回)に達した場合、一定時間(この例では30分間)ログインをブロックします。
5. ブロック中にログインを試みた場合、残り時間を表示して wp_die()
で処理を終了します。
6. ログイン失敗のたびに失敗回数を1増やし、トランジェントを更新します。
7. wp3min_reset_login_attempts
関数を wp_login
フックに登録し、ログイン成功時には失敗カウンターをリセットします。
トランジェント関数はとても便利で、私もプラグイン開発では良く使っている関数の一つです。一時的にデータを保存したり、期限付きの情報を管理したりするのに最適で、このようなセキュリティ対策にも活用できます。
このコードはWordPressの標準機能であるトランジェントAPIを利用しているため、データベースへの負荷が少なく、効率的に動作します。また、ブロック時間が過ぎれば自動的にトランジェントが削除されるため、メンテナンスの手間もかかりません。
カスタマイズポイント
このコードは基本的な実装ですが、さらに発展させることもできます。以下にカスタマイズポイントを紹介します:
1. 管理者へのメール通知
一定回数のログイン失敗が検出された場合、管理者にメール通知を送る機能を追加できます:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
// 失敗回数が閾値を超えた場合にメール通知を送信 if ($login_attempts == $max_attempts) { $admin_email = get_option('admin_email'); $subject = '[セキュリティ警告] ' . get_bloginfo('name') . ' へのログイン失敗が多発しています'; $message = "以下のIPアドレスから複数回のログイン失敗が検出されました。\n\n"; $message .= "IPアドレス: " . $ip_address . "\n"; $message .= "ユーザー名: " . $username . "\n"; $message .= "失敗回数: " . $login_attempts . "\n"; $message .= "日時: " . date('Y-m-d H:i:s') . "\n\n"; $message .= "このIPアドレスからのログインは " . ($block_time / 60) . " 分間ブロックされます。\n"; $message .= "心当たりがない場合は、サイトのセキュリティを確認してください。\n\n"; $message .= "このメールは自動送信されています。"; wp_mail($admin_email, $subject, $message); } |
2. IPホワイトリストの設定
特定のIPアドレスをホワイトリストに登録して、制限対象から除外することも可能です:
1 2 3 4 5 6 7 8 9 10 11 |
// ホワイトリストのIPアドレス $whitelist_ips = array( '123.456.789.012', // オフィスのIP '98.765.432.10' // 自宅のIP ); // ホワイトリストに含まれる場合は制限をスキップ if (in_array($ip_address, $whitelist_ips)) { return; } |
3. ユーザーエージェントの確認
より高度なセキュリティのため、ユーザーエージェントも確認し、不審なアクセスを検出することができます:
1 2 3 4 5 6 7 8 9 10 11 12 |
// ユーザーエージェントの取得 $user_agent = isset($_SERVER['HTTP_USER_AGENT']) ? $_SERVER['HTTP_USER_AGENT'] : ''; // ボットのような不審なユーザーエージェントをブロック $suspicious_agents = array('bot', 'crawler', 'spider', 'curl', 'wget'); foreach ($suspicious_agents as $agent) { if (stripos($user_agent, $agent) !== false) { // 即座にブロック wp_die('アクセスが拒否されました', 'セキュリティ警告', array('response' => 403)); } } |
カスタマイズ | メリット | 考慮点 |
---|---|---|
基本実装 | シンプルで導入が容易 ブルートフォース攻撃を防止 |
単一のIPブロックのみ |
メール通知 | リアルタイムの警告 攻撃の検出と監視 |
大量のメールが送信される可能性 |
IPホワイトリスト | 正当なユーザーの利便性確保 誤ブロックの防止 |
IPリストの管理が必要 |
ユーザーエージェント確認 | より高度な攻撃検出 自動化ツールの遮断 |
誤検出のリスクがある |
このセキュリティ対策は効果的ですが、強力なパスワードの使用や二要素認証の導入など、他のセキュリティ対策と組み合わせることで、より堅牢なセキュリティを実現できます。単一の対策に頼らないことが重要です。
その他の関連するフック
WordPressのセキュリティを強化するために使えるその他のフックもいくつか紹介します:
- authenticate – ユーザー認証のカスタマイズに使用するフック
- login_errors – ログインエラーメッセージをカスタマイズするフック
- login_enqueue_scripts – ログイン画面のスクリプトやスタイルを変更するフック
- wp_authenticate_user – ユーザー認証の前に追加のチェックを行うフック
これらを組み合わせることで、より高度なセキュリティ対策が可能になります。
プラグイン vs 自作コード
セキュリティ対策としては、専用のセキュリティプラグインを使用することも選択肢の一つです。「Wordfence Security」や「Sucuri Security」などの人気プラグインは、より高度なブルートフォース対策を提供しています。
ただし、プラグインを追加せず自作コードで対応するメリットもあります:
- サイトの軽量さを維持できる
- 必要最小限の機能だけを実装できる
- コードの動作を完全に理解して制御できる
- セキュリティ対策の仕組みを学習できる
サイトの規模や重要性に応じて、適切なアプローチを選択しましょう。
FAQ
Q1. 正当なユーザーが間違えてブロックされた場合はどうすればよいですか?
A1. トランジェントデータはデータベースに保存されているため、管理者は以下の方法でブロックを解除できます:
- PHPMyAdminなどでデータベースに接続
- wp_optionsテーブルを開く
- 「_transient_login_attempts_」で始まるオプション名を検索
- 該当するレコードを削除
または、以下のコードを一時的に実行して特定のIPのブロックを解除することもできます:
1 2 3 4 5 6 7 8 9 |
// 特定のIPアドレスのブロックを解除 function unblock_ip($ip_address) { delete_transient('login_attempts_' . md5($ip_address)); echo "IPアドレス " . $ip_address . " のブロックを解除しました。"; } // 使用例 // unblock_ip('123.45.67.89'); |
Q2. 共有IPアドレス環境(企業ネットワークなど)での誤ブロックを防ぐ方法はありますか?
A2. 共有IPの環境では、失敗回数の閾値を高く設定するか、ユーザー名とIPの組み合わせでブロックする方法が考えられます:
1 2 3 4 5 6 |
// ユーザー名とIPの組み合わせでトランジェント名を生成 $transient_name = 'login_attempts_' . md5($ip_address . '_' . $username); // 閾値も高く設定 $max_attempts = 10; // 共有IP環境向けに増加 |
Q3. トランジェントの代わりに他の保存方法を使うことはできますか?
A3. はい、以下のような代替方法があります:
- オプションテーブルに直接保存(小規模サイト向け)
- カスタムテーブルの作成(大規模サイト向け)
- ファイルベースのログ(データベース負荷を減らしたい場合)
- 外部キャッシュ(Redisなど)の利用(高トラフィックサイト向け)
ただし、WordPressの標準機能であるトランジェントAPIは、多くの場合で最も簡単で効率的な方法です。
Q4. このコードはCloudflareなどのプロキシサービスと互換性がありますか?
A4. デフォルトでは、$_SERVER['REMOTE_ADDR']
はCloudflareなどのプロキシを通すと、実際のユーザーIPではなくプロキシのIPを返します。Cloudflareと互換性を持たせるには:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
// 実際のクライアントIPを取得する関数 function get_real_ip_address() { if (!empty($_SERVER['HTTP_CF_CONNECTING_IP'])) { // Cloudflareを使用している場合 return $_SERVER['HTTP_CF_CONNECTING_IP']; } elseif (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) { // 他のプロキシを使用している場合 return $_SERVER['HTTP_X_FORWARDED_FOR']; } else { // 通常のケース return $_SERVER['REMOTE_ADDR']; } } // 使用例 $ip_address = get_real_ip_address(); |
まとめ
今回は wp_login_failed
アクションフックを使って、同一IPアドレスからのログイン失敗回数を制限し、ブルートフォース攻撃からサイトを守る方法を解説しました。
シンプルなコードにも関わらず、この実装はWordPressサイトの基本的なセキュリティを大幅に強化します。特にセキュリティプラグインを使いたくない場合や、最小限の機能だけを実装したい場合に便利です。
WordPressのフックシステムは非常に柔軟で強力です。プラグインに頼らずとも、簡単なコードで多くのカスタマイズが可能です。ぜひ今回のテクニックを活用して、あなたのサイトのセキュリティを向上させてください!
埼玉県川越市でWordPressサイトのセキュリティ対策や保守管理を行っています。セキュリティについてさらに詳しく知りたい方や、包括的なセキュリティ対策をご希望の方は、WordPress保守サポートサービスのご利用をご検討ください:https://edel-hearts.com/wordpress-maintenance-service/
また、WordPressのセキュリティについて相談したい場合は、WordPressトラブル対応・お悩み相談サービスもご利用いただけます:https://edel-hearts.com/wordpress-trouble-shooting/