SiteGuard WP Plugin でログイン保護
WordPressサイトのログインセキュリティを強化するには、「ログインURLを変更して攻撃対象を隠す」 + 「ログイン試行回数を制限して不正アクセスを防ぐ」 という2段階の防御が非常に有効です。
これらの対策は、別々のプラグイン(例:WPS Hide Login + Limit Login Attempts Reloaded)を組み合わせて導入する方法もありますが、SiteGuard WP Plugin を使えば、1つのプラグインだけで包括的なセキュリティ対策が可能です。
以下では、SiteGuard WP Plugin の導入から、各機能のポイント、設定の注意点、さらに .htaccess や PHP を使った Basic 認証の実装例まで、実践的なセキュリティ強化手法を解説します。
「ログインURLを忘れてしまった場合の対処法」などのトラブル対策も紹介しています。
関連ページ:
更新日:2025年07月11日
作成日:2025年07月10日
SiteGuard WP Plugin とは?
SiteGuard WP Plugin は、日本の EG セキュアソリューションズ社(旧ジェイピー・セキュア)が開発・提供する無料の WordPress 向け総合セキュリティプラグインです。ログイン画面保護を中心に、WordPress を狙った攻撃をカバーしており、日本語対応で解説や画面もわかりやすくできています。
主な機能
- ログインページURL変更機能(「/wp-login.php」→自由な URL に変更可能)
- ログイン試行回数制限(指定回数以上の失敗でロックアウト)
- ログインアラート(ログインがあった際に管理者へメール通知)
- 管理ページ、XML-RPC へのアクセス制限
- ログイン画面に日本語 CAPTCHA 追加
- プラグインやテーマ編集画面の無効化 など
詳細な情報やドキュメント:SiteGuard WP Plugin
SiteGuard WP Plugin のインストールと有効化
Conoha などサーバーによっては、すでに SiteGuard WP Plugin がインストールされている場合があります。その場合は、有効化のみを実行します。
WordPres 管理画面の左メニューから「プラグイン」→「プラグインを追加」をクリックします。
「SiteGuard WP Plugin」で検索し、プラグインが表示されたら「今すぐインストール」をクリックします。
「有効化」をクリックします。
有効化すると以下のようなメッセージが表示され、自動的に「ログインページのURL」が /wp-login.php から /login_xxxxx のような URL(xxxxx は5桁のランダムな数字)に置き換えられます。
例:https://example.com/wp-login.php → https://example.com/login_34259/
表示されたメッセージの「新しいログインページURL」の部分をクリックすると、変更された URL のログイン画面に遷移します。
また、WordPress に設定した管理者メールアドレス宛に以下のような、ログイン URL が記載されたメールが届きます(MAMP などのローカル環境では、メールが送信されない場合があります)。
ログインページの URL は、管理メニュー「SiteGuard」→「ダッシュボード」→「ログインページ変更」で確認、及び変更できます。
最低限変更すべき設定
SiteGuard WP Plugin をインストールして有効化するだけでも、基本的なセキュリティ対策は自動的に適用されます。例えば、ログインページのURLはデフォルトの /wp-login.php から別のURLに変更されます。
しかし、それだけではログインURLの秘匿性が完全とはいえません。
最低限変更すべき設定:「管理画面からログイン画面にリダイレクトしない。」
WordPress では、/wp-admin/ にアクセスすると、自動的にログインページにリダイレクトされる仕様があります。この挙動をそのままにしておくと、ログインページのURLが容易に推測されてしまい、ログインURLを変更した意味が薄れてしまいます。
WordPress 管理画面で「SiteGuard」→「ログインページ変更」を開き、「管理画面からログイン画面にリダイレクトしない。」にチェックを入れて、「変更を保存」をクリックします。
これにより、未ログイン状態で /wp-admin/ にアクセスしてもログインページへはリダイレクトされなくなり、ログインURLを隠す効果がより確実になります。
上記の設定に加えて、SiteGuard WP Plugin には他にも多くのセキュリティ機能が備わっています。
サイトの構成や利用状況など、必要に応じて各機能をカスタマイズすることで、さらにセキュリティ効果を高めることが可能です。
SiteGuard WP Plugin の設定
SiteGuard の設定は、管理メニューの「SiteGuard」をクリックして表示されるダッシュボードページで設定状況を確認でき、各項目のリンクからそれぞれの設定にアクセスします。
✔(チェックマーク)が緑色になっていない項目は無効になっています。
または、管理メニューの「SiteGuard」にマウスオーバーするとサブメニューが表示されるので、こちらからも直接各項目にアクセスすることができます。
管理ページアクセス制限
SiteGuard WP Plugin には、WordPressの管理ページ(/wp-admin/)を保護する「管理ページアクセス制限」機能があります。
この機能を有効化すると、ログインしていない接続元 IP アドレスから管理ページへのアクセスを禁止し、アクセスがあった場合は 404 Not Found を返して管理ページの存在自体を隠すことができます。
除外パスについて
一部のプラグインやテーマによっては、未ログイン状態でも /wp-admin/ 以下の特定のパスにアクセスする必要があるケースがあります。 その場合は「除外パス」に /wp-admin/ 以降の必要なパスを追加しておくことで、管理ページアクセス制限の影響を受けずに利用できます。
デフォルト設定と推奨設定
管理ページアクセス制限はデフォルトで無効になっています。
セキュリティをより強化したい場合は、SiteGuardの管理画面で「有効」にチェックを入れ、「変更を保存」をクリックすることで有効化できます。これにより、未ログイン時に /wp-admin/ へアクセスすると404を返すため、攻撃者に管理画面の存在を気づかせにくくなります。
ただし、除外パスの設定を誤ると、必要な管理系機能が正常に動作しなくなる可能性がありますので注意してください。
公式ドキュメントへのリンク(全ての設定画面で共通)
各設定画面の「この機能の操作説明はこちら」のリンク部分をクリックすると、操作に関する詳しい説明(公式ドキュメント)ページが表示されます。
操作説明:管理ページアクセス制限
ログインページ変更
SiteGuard では、WordPressのログインページ(/wp-login.php)のURLを自由に変更できます。
SiteGuard を有効化すると、自動的にランダムな文字列を含むログインページURLが生成され、既存の /wp-login.php は無効化されます。
この画面で任意の文字列に設定することで、推測されにくいオリジナルのログイン URL を作成できます。
例えば、「my-secure-login」と設定すると「https://example.com/my-secure-login/」が新しいログインURLになります(my-secure-login は推測しやすいので良くない例です)。
設定する文字列は英数字・ハイフン・アンダースコアが使用可能です。
推測されやすい単語や短すぎる文字列は避け、複雑でわかりにくい名前にするのがポイントです。
ログインページ URL を変更すると、「WordPress: ログインページURLが変更されました」という件名で、新しいログインページ URL が記載されたメールが届きます。
管理画面からのリダイレクト設定オプション
WordPressのデフォルト仕様では、ログインしていない状態で /wp-admin/ にアクセスすると自動的にログイン画面にリダイレクトされます。
つまり、攻撃者が /wp-admin/ にアクセスするだけでログインURLが露呈してしまいます。
オプションの「管理画面からログイン画面にリダイレクトしない」にチェックを入れると、未ログイン状態で /wp-admin/ にアクセスしてもリダイレクトが発生せず、ログイン画面に到達できないようになるため、ログインURLの秘匿性を維持できます。※ ログインURLを隠すためには必須の設定です。
操作説明:ログインページ変更
ログイン URL を忘れた場合
設定したログインページの URL を忘れてしまった場合、管理画面にアクセスできなくなってしましますが、WordPress のルートディレクトリにある .htaccess ファイルを確認することで、現在設定されているログインURLを特定できます。
.htaccess での確認方法
サイトの FTP やホスティングのファイルマネージャーで、WordPress ルートディレクトリにある .htaccess ファイルを開きます。
SiteGuard がログインページを変更した際、自動的に .htaccess に以下のような設定が追加されています。
#SITEGUARD_PLUGIN_SETTINGS_START
#==== SITEGUARD_RENAME_LOGIN_SETTINGS_START
<IfModule mod_rewrite.c>
RewriteEngine on
RewriteBase /
RewriteRule ^wp-signup\.php 404-siteguard [L]
RewriteRule ^wp-activate\.php 404-siteguard [L]
RewriteRule ^my-secure-login(.*)$ wp-login.php$1 [L]
</IfModule>
#==== SITEGUARD_RENAME_LOGIN_SETTINGS_END
#SITEGUARD_PLUGIN_SETTINGS_END
上記の以下の部分で、my-secure-login が現在設定されているログイン URL であることがわかります。
※ 設定したログインURLは必ずメモやブックマークするなどして、忘れないように管理しましょう。
SiteGuard は .htaccess を直接操作するプラグイン(参考)
SiteGuard WP Plugin は、WordPress の .htaccess ファイルを直接書き換えるタイプのセキュリティプラグインです。
たとえば、ログインページの変更やアクセス制限などの設定は .htaccess に自動的に追記されます。
そのため、WordPress 管理画面からプラグインを無効化した場合は、SiteGuard によって追加された .htaccess の設定も自動的に削除されます。
しかし、FTP やファイルマネージャーを使って手動でプラグインフォルダの名前を変更し、強制的に無効化した場合は、.htaccess の設定はそのまま残る点に注意が必要です。
この状態では、ログインページが変更されたままとなります。
画像認証(CAPTCHA)
SiteGuard には、ログインページ・コメント投稿ページ・パスワード確認ページ・ユーザー登録ページに画像認証を追加できる機能があります。
この機能を有効化することで、自動化されたブルートフォース攻撃やスパム行為を効果的に防止できます。
初期設定
SiteGuard を有効化すると、初期状態で画像認証機能は有効になっています。
このため特に設定を変更しなくても、標準でログインページなどに CAPTCHA が追加され、不正ログイン対策の強度が向上します。
文字種の選択
画像認証に表示される文字は以下のどちらかを選択できます。
- ひらがな(デフォルト)
- 英数字
海外からの攻撃を防ぎたい場合には、日本語(ひらがな)の画像認証を選択しておくと、海外の攻撃ボットは対応できない場合が多く、より高い防御効果が期待できます。
但し、日本語(ひらがな)の画像認証の場合、以下のように判別が難しいこともあります(以下は「へかそも」)。このような場合は、再読み込みすることで別の文字列が表示されます。
コメントページやユーザー登録ページにもCAPTCHAを追加することで、スパムコメントや不正ユーザー登録のリスクを減らせます。
操作説明:画像認証
ログイン詳細エラーメッセージの無効化
WordPressのデフォルト動作では、ログインに失敗した際に
- ユーザー名が存在しない
- パスワードが間違っている
- 画像認証が間違っている
など、それぞれの原因に応じた具体的なエラーメッセージが表示されます。
この挙動は、攻撃者にとっては以下のような攻撃の手がかりになってしまうため、ブルートフォース攻撃やユーザー名の特定を容易にしてしまいます。
- 正しいユーザー名の存在確認
- パスワード推測の成功・失敗の判断
SiteGuard の「ログイン詳細エラーメッセージの無効化」を有効にすることで、以下の動作になり、推測攻撃をより困難にできます。
- ログイン失敗時のエラーメッセージをすべて同じ内容に統一
- 攻撃者に失敗原因の情報を与えない
セキュリティを強化するには、この機能を有効にすることが推奨されます(デフォルトは有効です)。
操作説明:ログイン詳細エラーメッセージの無効化
ログインロック
SiteGuard には、短時間に連続してログイン試行を繰り返す接続元を自動的にブロックする「ログインロック機能」があります。
同一 IP アドレスからの連続したログイン失敗を検出すると、その接続元 IP を基にログインを一時的にロックし、ブルートフォース攻撃を防止できます。
初期状態で有効になっており、特別な理由がない限り有効のままにすることを推奨します。
次の3項目を調整できます。
連続試行間隔(ログインロックの期間)
短時間に何回ログインを試行したらロックするかを決める基準です。
- 1秒
- 5秒(デフォルト)
- 30秒
連続失敗回数(ロックを発動させる試行回数)
連続して何回失敗したらロックするかを設定します。
- 3回(デフォルト)
- 10回
- 100回
ロック時間
ロック発動後、どれだけの時間ログインをブロックするかを決めます。
- 30秒
- 1分(デフォルト)
- 5分
「5秒間にログインを3回失敗した場合、1分間そのIPからのログインができなくなる」ように初期設定されています。
ログインロックの注意点
連続試行間隔(期間)は最大30秒なので、攻撃者が30秒以上間隔を空けてゆっくり試行する攻撃には効果がありません。
また、同じIPアドレスからの連続失敗を条件にしているため、複数の異なるIPを使用して行われる分散型攻撃は防御できません。
操作説明:ログインロック
ログインアラート
SiteGuard には、ログインアラート機能があります。
この機能を有効化すると、管理者を含むユーザーがログインするたびに、WordPress に登録されている管理者メールアドレス宛てにメール通知が届きます。
不正ログインへの気づき
もし自分に心当たりがないタイミングでログイン通知メールを受信した場合は、不正ログインが行われた可能性が高いため、すぐに対処が必要です。
この機能を利用することで、不正アクセスを早期に発見できます。
設定内容
ログインアラートの有効・無効を切り替え可能です。
- デフォルトでは「管理者のみ」にチェックが入っており、管理者権限を持つユーザーのログインだけが通知対象になります。
- 必要に応じて、このチェックを外せば他の権限ユーザーのログインも通知対象にできます。
メール内容のカスタマイズ
サブジェクト(件名)やメール本文には変数を利用して、送信されるメール内容を自由に編集できます。 これにより、受信時にわかりやすい内容にしたり、独自の通知文を作成できます。
デフォルトでは以下のようなメールが届きます。
操作説明:ログインアラート
フェールワンス(Fail Once)
フェールワンス機能を有効化すると、正しいユーザー名とパスワードを入力しても、最初の試行は必ず失敗します。これにより攻撃者がユーザー名とパスワードのリストを使った総当たり攻撃(リスト攻撃)を行いにくくなります。
ログインの流れ
- フェールワンスが有効な場合、正しいログイン情報を入力しても1回目は失敗します。
- ユーザーは5秒以降、60秒以内に再度ログインする必要があります。この短時間内に再ログインしないと、再び最初からやり直しになるため、実際の利用者にとっては少し手間ですが、攻撃者にとっては大きな妨げになります。
設定内容
- 管理画面で有効・無効を切り替えられます。
- デフォルトは無効になっています。
- 「管理者のみ」にチェックを入れると、管理者権限を持つユーザーのみが対象になります。
正規ユーザーにとって不便になる可能性がある反面、リスト攻撃対策として有効です。
運用上問題ない範囲で有効化を検討する価値があります。
操作説明:フェールワンス
XMLRPC防御
XMLRPC 防御は、WordPress の脆弱性を突いた攻撃を防ぐために重要な機能です。
SiteGuardでは、以下の2種類の方法で XMLRPC を防御できます。
- ピンバック機能(リンク元からリンク先へリンクを張った際に通知を送る仕組み)を無効化する
- XMLRPC自体(xmlrpc.php)を完全に無効化する
デフォルト設定
初期状態ではXMLRPC防御は有効になっており、タイプは「ピンバック無効化」が選択されています。
この状態であれば、ピンバック攻撃によるDDoSやリソース枯渇攻撃を防げます。
XMLRPC全体を無効化する場合
「XMLRPC全体無効化」を選択すると、XMLRPCを使用した以下のようなプラグインや外部アプリケーションは動作しなくなります。
- スマホなどからの投稿管理
- Jetpackの一部機能
- XMLRPCを使う外部ツール
WordPressのXMLRPCとは?
XMLRPCは、WordPressの管理画面にログインせずに外部プログラムやアプリからWordPressを操作できる仕組みです。XML-RPC(Remote Procedure Call)は、XMLフォーマットでリクエストを送信し、HTTP経由でリモートの処理を実行するプロトコルです。XML形式のデータを用いて通信し、以下のようなことが可能になります。
- 外部ツールから投稿の作成・更新・削除
- コメント管理
- 一部プラグインのリモート機能
悪用されるケースとしては以下のようなものがあります。
- ブルートフォース攻撃:
- xmlrpc.php を使って短時間に多数のログイン試行を自動化する攻撃。
- wp-login.php とは異なり、CAPTCHA やログイン制限の回避がしやすいため狙われやすい。
- pingback DDoS 攻撃:
- pingback.ping メソッドを使って他サイトへの攻撃に悪用される(攻撃の踏み台)。
XMLRPC を使用しない場合は XMLRPC 全体を無効化する
WordPress4.7以降、REST APIが正式にコアに搭載され、最近のWordPressサイトではXMLRPCを使わないケースが圧倒的に多いのが実情です。
XMLRPC は利便性が高い反面、悪用されることが多く、特に使用予定がない場合は XMLRPC 全体を無効化することをおすすめします。
操作説明:XMLRPC防御
更新通知
更新通知機能は、WordPressコア、プラグイン、テーマに更新がある場合に、管理者メールアドレス宛にメールで通知してくれる機能です。
SiteGuard WP Plugin の管理画面で有効・無効を切り替えたり、詳細設定を行うことができます。
- テーマやプラグインの自動更新を有効にしていない場合は、更新通知を有効にすることで更新漏れを防げます。
- 逆に、自動更新を利用している場合は不要なので、更新通知は無効にしても問題ありません。
操作説明:更新通知
WAFチューニングサポート
WAF チューニングサポートは、JP-Secure 製の WAF(SiteGuard Lite)が Web サーバーに導入されている場合に利用できる機能です(※ JP-Secure 製 WAF が導入されていない環境では効果がありません)。
WordPress 内の正常な動作が WAF に誤検知され、403エラーなどの問題が発生するのを防ぐために、除外ルールを作成できます。
この機能が必要なケース
- WAF は Web サイトを攻撃から守る強力な防御機能ですが、WordPress の機能やプラグインによっては、正常な操作が攻撃と誤認される場合があります。
- 例えば、管理画面や特定のプラグインのリクエストがブロックされ、管理者が操作できなくなるなどの問題が起こります。
WAFチューニングサポートの役割
- 除外ルールを設定することで、特定の処理における誤検知を回避できます。
- 必要な機能を使えるようにしながら、サイト全体としてのWAFの防御機能は維持できます。
操作説明:WAFチューニングサポート
ログイン履歴
ログイン履歴機能では、ユーザーのログイン履歴を記録・表示することで、不正アクセスの兆候を早期に発見できます。
特に、普段と異なるIPアドレスからのアクセスや、短時間で複数回ログインしている形跡などは、不審な動きとして確認する価値があります。
主な機能
- ログインの日時、結果(成功、失敗、ロック、フェールワンス),ユーザー名、IPアドレス、タイプが一覧で表示されます。
- 結果、タイプ、ログイン名、IPアドレスの値で、絞り込み検索が行えます。
- 履歴は最大 10,000件まで記録 され、これを超えると 古い記録から自動で削除 されます。
- 表示は最新の履歴から順に並んでいるため、直近のログイン状況をすぐに確認可能です。
タイプには、ログインページ、XMLRPC の2種類があります。通常のログインページからのログインなのか、xmlrpc.php 経由のログインなのかを判別できます。
xmlrpc.php 経由のログインは、総当たり(ブルートフォース)攻撃で多用されるため、ログに頻繁に現れる場合は注意が必要です。
操作説明:ログイン履歴
ログイン URL に Basic 認証を設定
変更したログインページの URL に Basic 認証を設定して、さらに認証の層を追加することで、ブルートフォース攻撃やボットによる総当たりを高い確率で防ぐことができます。
ログイン URL が漏れた場合でも、Basic 認証が第2の防壁となるため、SiteGuard の設定と併用して堅牢な対策が可能です。
但し、Basic 認証を有効にすると、ログイン URL にアクセスするたびにブラウザ側で認証ダイアログが表示されるため、利用者にとって手間が増えるというデメリットがあります。
Basic 認証を導入するメリット
項目 | 内容 |
---|---|
二重の認証壁 | ログインフォームの前に ID・パスワードを求めることで、WordPress のログイン処理そのものに到達させない構成になります。 |
Bot や不正アクセスを遮断 | 多くの攻撃は WordPress のログイン画面にアクセスできて初めて試行されるため、その手前で止めることで無駄なリソース消費も防げます。 |
ログをきれいに保つ | 不要なログイン失敗記録やロックアウトを発生させずに済むため、正常なログ解析もしやすくなります。 |
.htaccess の記述例
SiteGuard WP Plugin と Basic 認証を併用する場合の .htaccess の記述例です。
この構成では、変更後のログインURL(例: /my-secure-login)に対して Basic 認証を追加し、それ以外のアクセスには影響を与えないようにしています。
前提
- WordPress のログインURLは SiteGuard によって /my-secure-login に変更されている。
- .htpasswd は安全な場所に設置済み。
- Webサーバーは Apache。
- .htaccess は WordPress インストールディレクトリにあります。
注意
- .htpasswd ファイルは、Webアクセス可能なディレクトリ内に置かないようにします。
- 推奨されるのは、ドキュメントルート外の安全な場所です(例:/home/youraccount/.htpasswds/yourdomain.com/.htpasswd)。
- また、HTTP 接続ではパスワードが平文で送信されるため、必ず HTTPS 環境で運用してください。
この例では、.htaccess の最上部に Basic 認証のカスタム設定を追加しています。
#SITEGUARD_PLUGIN_SETTINGS_START 〜 END および # BEGIN WordPress 〜 END の間は、プラグインや WordPress 本体が自動的に書き換える領域です。
# ==== Basic認証の保護(ログインURLに限定)====
<If "%{REQUEST_URI} =~ m#^/my-secure-login#">
AuthType Basic
AuthName "Restricted Area"
AuthUserFile /home/youraccount/.htpasswds/yourdomain.com/.htpasswd
Require valid-user
</If>
# ==== Basic認証ここまで ====
#SITEGUARD_PLUGIN_SETTINGS_START
#==== SITEGUARD_RENAME_LOGIN_SETTINGS_START
<IfModule mod_rewrite.c>
RewriteEngine on
RewriteBase /
RewriteRule ^wp-signup\.php 404-siteguard [L]
RewriteRule ^wp-activate\.php 404-siteguard [L]
RewriteRule ^my-secure-login(.*)$ wp-login.php$1 [L]
</IfModule>
#==== SITEGUARD_RENAME_LOGIN_SETTINGS_END
...
# 以下省略
<If "%{REQUEST_URI} =~ m#^/my-secure-login#"> の「my-secure-login」の部分は SiteGuard のログインURLに合わせて変更してください。
RewriteRule ^my-secure-login(.*)$ wp-login.php$1 [L] は SiteGuard によりログインURLを my-secure-login に変更している部分です。
記述 | 意味 |
---|---|
<If> |
Apache 2.4 以降で使用できる構文で、「指定した条件に一致した場合だけ、中の設定を有効にする」ために使います。 |
%{REQUEST_URI} |
アクセスされたURLのパス部分を表します。例えば https://example.com/my-secure-login がアクセスされた場合、%{REQUEST_URI} の値は /my-secure-login |
=~ |
「正規表現にマッチするかどうかを判定する」演算子です。 |
m#^/my-secure-login# |
m は「match(マッチ)」の略で、正規表現(パターンマッチ)を使う構文です。
|
.htpasswd の作成方法
以下はターミナルで htpasswd コマンドを使って bcrypt を生成する例です。
htpasswd -nbB ユーザー名 パスワード
オプション | 意味 |
---|---|
-n | 結果をファイルに保存せずに標準出力に出す |
-b | パスワードをコマンドライン引数で指定(非対話) |
-B | bcrypt を使用する(セキュリティ強) |
以下はユーザー名に foo、パスワードに foo123#$% を指定した実行例です。出力された値を .htpasswd に記述します。
% htpasswd -nbB foo foo123#$%
foo:$2y$05$JQjv6JN3gDR/KaUEQlIqIuA6JgsT8ddPOV5/cFsei0xowHm6uTPJ6 #出力
以下は -n の代わりに出力先のファイルパスを指定して、.htpasswd ファイルを生成する例です。この例ではローカル環境 MAMP に pwd ディレクトリを作成してその中に .htpasswd ファイルを保存しています。
-c を付けているので、新規ファイルとして作成され、既存のファイルがあれば内容は削除されます。
% htpasswd -cbB /Applications/MAMP/pwd/.htpasswd foo foo123#$%
追加登録するには、以下のように -bB として -c を指定しません。
% htpasswd -bB /Applications/MAMP/pwd/.htpasswd alice mySecurePass123
上記により、例えば以下のようなファイルが作成されます。
foo:$2y$05$oW/yoTZLvi7MVHDsBUfT9.GfZR9yyNiYHPH2wvsP21iBjbYLUcg7S
alice:$2y$05$0ZAt.1OkQNY0Qo39D6GB6u/cVETfWO8LheXm9bTaBibyDUoJswriC
関連ページ:
(参考)SiteGuard のカスタムログイン URL は仮想パス
SiteGuard WP Plugin の「ログインページ変更」機能で設定した /my-secure-login のような URL は、実際のファイルではなく仮想的なエンドポイントです。WordPress 本体の wp-login.php をリネームしているわけではありません。
それでも .htaccess で Basic 認証などの制御が可能なのは、SiteGuard が .htaccess に RewriteRule を追加することで、仮想ログインURLを物理的に存在するかのように振る舞わせているため、Apacheレベルでそのパスへのアクセスを制限することが可能になっています。
ログイン URL を動的に取得
前述の .htaccess に現在のログイン URL を指定して Basic 認証を設定する方法では、ログイン URL を変更した場合、.htaccess も変更が必要になります。
例えば、セキュリティポリシーとして「ログインURLを一定期間ごとに変更する」ような運用をしている場合(もしあれば)、.htaccess に毎回手動で書き換えを行うのは現実的ではありません。そのような場合やホスティング環境やサーバー設定により .htaccess が使用できない場合には、PHP 側で動的にログインスラッグを取得して認証処理を行うこともできます。
ただ、基本的には、WordPress ログインページへのアクセス制限を Basic 認証で実装する場合、可能であれば .htaccess を用いて Apache レベルで制御することを推奨します。
.htaccess で認証を行うメリット
- PHP が実行される前にアクセスを遮断できるため、サーバー負荷が軽く高速。
- .htpasswd によるユーザー・パスワードのチェックは Apache が直接行うため、パスワード検証ロジックを自前で書く必要がなく、安全性も高い。
- ブルートフォースアタックに対して早期にブロックできる。
PHP で Basic 認証を行う場合の注意点
- リクエストは WordPress およびプラグインの初期処理(init 以降)まで届いてしまうため、不要な処理が発生しサーバー負荷が高くなる。
- .htpasswd のハッシュ形式(bcrypt、APR1-MD5 など)によっては、PHPで検証するために複雑な処理が必要となる。
- PHP 側の認証処理に不備があると、セキュリティ上のリスクとなる可能性がある。
以下は、現在設定されている「ログインページ名」を自動的に取得して、PHP 側(functions.php)でその URL スラッグにだけ Basic 認証を設定する例です。
SiteGuard はログインページ名を WordPress のオプション(wp_options)に保存しているので、get_option() で取得できます。
phpMyAdmin で wp_options テーブルを調べてみると siteguard_config というオプション名で設定情報が保存されているのが見つかります。
または、以下の SQL 文を実行しても、siteguard_config というオプションが見つかります。
SELECT option_name, option_value
FROM wp_options
WHERE option_name LIKE 'siteguard%';
siteguard_config の値は、以下のようにシリアライズ形式の配列で保存されています。
a:36:{s:18:"show_admin_notices";s:1:"1";s:25:"admin_filter_exclude_path";s:57:"css,images,admin-ajax.php,load-styles.php,site-health.php";s:19:"admin_filter_enable";s:1:"0";s:16:"renamelogin_path";s:15:"my-secure-login";s:15:"redirect_enable";...
以下は、siteguard_config オプションの実データ(デシリアライズ後のPHP配列)の例です。
Array
(
[show_admin_notices] => 1
[admin_filter_exclude_path] => css,images,admin-ajax.php,load-styles.php,site-health.php
[admin_filter_enable] => 0
[renamelogin_path] => my-secure-login // ← ★リネーム後のログインページスラッグ
[redirect_enable] => 0
[renamelogin_enable] => 1
[captcha_enable] => 1
[captcha_login] => 1
[captcha_comment] => 1
[captcha_lostpasswd] => 1
[captcha_registuser] => 1
[same_login_error] => 1
[loginlock_enable] => 1
[loginlock_interval] => 5
[loginlock_threshold] => 3
[loginlock_locksec] => 60
[loginlock_fail_once] => 0
[fail_once_admin_only] => 1
[loginalert_enable] => 1
[loginalert_admin_only] => 1
[loginalert_subject] => %SITENAME%にログインがありました
[loginalert_body] => %DATE% %TIME%に%USERNAME%がログインしました。
== ログイン情報 ==
IPアドレス:%IPADDRESS%
リファラー:%REFERER%
ユーザーエージェント:%USERAGENT%
--
SiteGuard WP Plugin
[disable_xmlrpc_enable] => 0
[disable_pingback_enable] => 1
[block_author_query_enable] => 0
[disable_restapi_enable] => 0
[disable_restapi_exclude] => oembed,contact-form-7,akismet
[waf_exclude_rule_enable] => 0
[waf_exclude_rule] => Array
(
)
[notify_wpcore] => 1
[notify_plugins] => 2
[notify_themes] => 2
[notified] => Array
(
[core] =>
[plugin] => Array
(
)
[theme] => Array
(
)
)
[last_check_time] => 1752075260
[updates_notify_enable] => 1
[version] => 1.7.8
)
SiteGuard はログインページのスラッグを WordPress の wp_options テーブルの siteguard_config というオプションに、シリアライズ形式の配列で保存していて、その中のキー renamelogin_path にリネーム後のログイン名(この例では my-secure-login)が入っているのがわかります。
但し、将来的に SiteGuard WP Plugin の仕様変更やバージョンアップに伴って、siteguard_config という option_name 自体が変更される可能性があります。そのため、オプションの取得では、存在確認を必ず行うようにします。
ログインページ名を自動的に取得して Basic 認証を設定
以下は PHP 側で SiteGuard で設定したログインページ名を自動的に取得して Basic 認証を設定するコードです。※ .htaccess の Basic 認証は不要なので、記述してある場合は削除します。
この例では、.htpasswd に保存された bcrypt ハッシュと password_verify() を用いて認証を行っています。そのため、.htpasswd が APR1-MD5 や crypt 形式だと以下のコードでは認証できません。
// SiteGuard に Basic 認証を追加
add_action('init', function () {
// SiteGuard WP Plugin の設定を WordPress のオプションから取得(シリアライズされた配列)
$config = get_option('siteguard_config');
// SiteGuard の設定が取得できなかった場合、またはログインページのスラッグが設定されていない場合(オプションの存在確認)
if (empty($config) || empty($config['renamelogin_path'])) {
// ログに警告メッセージを出力して、処理を中断(例: Basic認証などをスキップ)
error_log("SiteGuard login name not found. Skipping Basic Auth.");
return;
}
// ログインページのスラッグ(例: 'my-secure-login')を取得
$target_slug = $config['renamelogin_path'];
// 現在のリクエストパスを取得(クエリ除去)
$request_path = parse_url($_SERVER['REQUEST_URI'] ?? '', PHP_URL_PATH);
// スラッグと現在のパスが一致するかチェック
if (!preg_match('#/' . preg_quote($target_slug, '#') . '/?$#', $request_path)) {
return; // 対象スラッグでない場合はスルー
}
// Basic認証を要求して401を返す関数
function sg_send_auth_request($message = 'Authentication required.') {
header('Content-Type: text/plain; charset=utf-8');
header('WWW-Authenticate: Basic realm="Restricted Login Page"');
header('HTTP/1.0 401 Unauthorized');
echo $message;
exit;
}
// 認証ヘッダーが未送信の場合は要求
if (!isset($_SERVER['PHP_AUTH_USER'], $_SERVER['PHP_AUTH_PW'])) {
sg_send_auth_request();
}
// 認証情報の取得
$username = $_SERVER['PHP_AUTH_USER'];
$password = $_SERVER['PHP_AUTH_PW'];
// htpasswd ファイルの絶対パス(環境に合わせて適切な絶対パスに変更)
$htpasswd_path = '/path/to/.htpasswd';
// 実際のファイルパスを解決(シンボリックリンクや相対パスも正規化される)
$resolved_path = realpath($htpasswd_path);
// .htpasswd ファイルの存在と読み込み権限を確認
if ($resolved_path === false || !is_readable($resolved_path)) {
error_log("htpasswd file not found or unreadable: $htpasswd_path");
header('HTTP/1.0 500 Internal Server Error');
echo 'Server error.';
exit;
}
// .htpasswd の各行を取得(空行や改行を除く)
$lines = file($resolved_path, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
$authenticated = false;
// .htpasswd ファイルの各行(ユーザー名:ハッシュ)を処理して、該当するユーザー名があるか確認
foreach ($lines as $line) {
// ユーザー名とハッシュに分割(.htpasswd にある各行を $user と $hash に分解)
list($user, $hash) = explode(':', $line, 2);
// 入力ユーザー名が一致し、password_verify() でパスワードも正しければ認証成功
if ($user === $username && password_verify($password, $hash)) {
$authenticated = true;
break;
}
}
// 認証に失敗した場合
if (!$authenticated) {
sg_send_auth_request('Invalid credentials.');
}
});
APR1-MD5 形式にも対応
.htpasswd ファイルに APR1-MD5 形式のパスワードが使われている場合、PHP での認証には追加の実装が必要です。
APR1-MD5とは?
- Apache HTTP Server が .htpasswd で使用するパスワードハッシュ形式のひとつです。
- ハッシュ文字列は $apr1$ で始まり、$apr1$ソルト$ハッシュ のような構造をしています。
- bcrypt ほどの強度はありませんが、古い環境や一部ツールとの互換性のために今でも使われることがあります。
- PHPの crypt() 関数でも一部の環境では検証できますが、環境依存のため確実に動作させるには 自前のAPR1-MD5実装を使うのが安全です。
password_verify() は bcrypt 等のモダンな形式にしか対応していません。
APR1-MD5 に対応するには、次のように sg_apr1_verify() という関数を自作し、条件分岐で使い分けます。
if ($user === $username) {
// ハッシュ文字列が $apr1$ で始まる場合
if (strpos($hash, '$apr1$') === 0) {
if (sg_apr1_verify($password, $hash)) {
$authenticated = true;
break;
}
} else {
if (password_verify($password, $hash)) {
$authenticated = true;
break;
}
}
}
以下は APR1-MD5 形式の .htpasswd にも対応できるように書き換えたコードの例です。
動作確認済みですが、APR1-MD5 の仕様を完全に理解しているわけではないため、ご利用の際は内容を確認のうえ慎重にご使用ください。
また、APR1-MD5 の仕様(反復処理・salt処理・base64変換など)は複雑であり、実装の正当性を完全に検証したわけではないため、セキュリティ要件が高い場面では注意が必要です。
add_action('init', function () {
$config = get_option('siteguard_config');
if (empty($config) || empty($config['renamelogin_path'])) {
error_log("SiteGuard login name not found. Skipping Basic Auth.");
return;
}
$target_slug = $config['renamelogin_path'];
$request_path = parse_url($_SERVER['REQUEST_URI'] ?? '', PHP_URL_PATH);
if (!preg_match('#/' . preg_quote($target_slug, '#') . '/?$#', $request_path)) {
return;
}
if (!isset($_SERVER['PHP_AUTH_USER'], $_SERVER['PHP_AUTH_PW'])) {
sg_send_auth_request();
}
$username = $_SERVER['PHP_AUTH_USER'];
$password = $_SERVER['PHP_AUTH_PW'];
// htpasswd ファイルの絶対パス(環境に合わせて適切な絶対パスに変更)
$htpasswd_path = '/path/to/.htpasswd';
$resolved_path = realpath($htpasswd_path);
if ($resolved_path === false || !is_readable($resolved_path)) {
error_log("htpasswd file not found or unreadable: $htpasswd_path");
header('HTTP/1.0 500 Internal Server Error');
echo 'Server error.';
exit;
}
$lines = file($resolved_path, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
$authenticated = false;
foreach ($lines as $line) {
list($user, $hash) = explode(':', $line, 2);
// 入力ユーザー名が一致
if ($user === $username) {
if (strpos($hash, '$apr1$') === 0) {
// .htpasswd が APR1-MD5 形式の場合
if (sg_apr1_verify($password, $hash)) {
$authenticated = true;
break;
}
} else {
// .htpasswd が bcrypt 形式の場合
if (password_verify($password, $hash)) {
$authenticated = true;
break;
}
}
}
}
if (!$authenticated) {
sg_send_auth_request('Invalid credentials.');
}
});
// Basic認証を要求して401を返す関数
function sg_send_auth_request($message = 'Authentication required.') {
header('Content-Type: text/plain; charset=utf-8');
header('WWW-Authenticate: Basic realm="Restricted Login Page"');
header('HTTP/1.0 401 Unauthorized');
echo $message;
exit;
}
// 入力されたパスワードと .htpasswd の APR1-MD5 ハッシュを比較し、一致すれば true を返す
function sg_apr1_verify($password, $hash) {
// ハッシュが APR1-MD5形式で始まっていなければ false を返す
if (strpos($hash, '$apr1$') !== 0) {
return false;
}
// ハッシュ内のソルトを取り出して、パスワードと組み合わせて APR1-MD5を再計算
// その結果とオリジナルのハッシュが一致すれば true(認証成功)
return $hash === sg_apache_md5($password, sg_extract_apr1_salt($hash));
}
// APR1-MD5 形式のハッシュから salt を抽出する(例: $apr1$SALT$HASH の SALT 部分)
function sg_extract_apr1_salt($hash) {
$parts = explode('$', $hash); // $parts[2] が salt に相当
return $parts[2] ?? ''; // salt が存在しない場合は空文字
}
// 入力されたパスワードとソルトから APR1-MD5 形式のハッシュを生成する関数(Apache 互換)
function sg_apache_md5($password, $salt) {
// ソルトは最大8文字まで(Apache仕様)
$salt = substr($salt, 0, 8);
$len = strlen($password);
// 初期テキストを生成(パスワード + $apr1$ + ソルト)
$text = $password . '$apr1$' . $salt;
// パスワード + ソルト + パスワード の MD5 をバイナリで取得
$bin = md5($password . $salt . $password, true);
// パスワード長に応じて、bin を繰り返し追加
for ($i = $len; $i > 0; $i -= 16) {
$text .= substr($bin, 0, min(16, $i));
}
// パスワード長のビットによって異なる追加処理(0ビット:先頭文字、1ビット:null文字)
for ($i = $len; $i > 0; $i >>= 1) {
$text .= ($i & 1) ? chr(0) : $password[0];
}
// 最初のハッシュを生成(バイナリ形式で)
$bin = pack("H*", md5($text));
// 1000回のハッシュループ(ストレッチング)
for ($i = 0; $i < 1000; $i++) {
$new = '';
$new .= ($i & 1) ? $password : $bin;
if ($i % 3) $new .= $salt;
if ($i % 7) $new .= $password;
$new .= ($i & 1) ? $bin : $password;
$bin = pack("H*", md5($new));
}
// バイト順を特定順で再構成(Apache の出力順に合わせる)
$output = '';
$order = [12, 6, 0, 13, 7, 1, 14, 8, 2, 15, 9, 3, 5, 10, 4, 11];
foreach ($order as $i) {
$output .= $bin[$i];
}
// 出力を Base64 ではなく Apache独自の64進数でエンコード
$encoded = '';
$encoded .= sg_to64((ord($bin[0]) << 16) | (ord($bin[6]) << 8) | ord($bin[12]), 4);
$encoded .= sg_to64((ord($bin[1]) << 16) | (ord($bin[7]) << 8) | ord($bin[13]), 4);
$encoded .= sg_to64((ord($bin[2]) << 16) | (ord($bin[8]) << 8) | ord($bin[14]), 4);
$encoded .= sg_to64((ord($bin[3]) << 16) | (ord($bin[9]) << 8) | ord($bin[15]), 4);
$encoded .= sg_to64((ord($bin[4]) << 16) | (ord($bin[10]) << 8) | ord($bin[5]), 4);
$encoded .= sg_to64(ord($bin[11]), 2);
// 最終的な APR1-MD5形式のハッシュ文字列を返す
return '$apr1$' . $salt . '$' . $encoded;
}
// Apache 独自の 64進数(Base64とは異なる)エンコード関数
function sg_to64($v, $n) {
$itoa64 = './0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'; // Apacheの順番
$ret = '';
while (--$n >= 0) {
$ret .= $itoa64[$v & 0x3f]; // 下位6ビットでマッピング
$v >>= 6; // 6ビット右シフト
}
return $ret;
}