WordPress のユーザー名は、初期状態だと外から見えます。
アドレスの後ろに ?author=1 を付けると、投稿者のページに転送されて、そのURLにユーザー名が入っている。これは有名な話で、対策を書いた記事もたくさんあります。
自分も、ひととおりやっていました。転送を止めて、REST API を塞いで、表示名を別のものにして。これで隠せたと思っていました。
ところが先日、セキュリティプラグインの週次レポートを見て、手が止まりました。
失敗したログインの一覧に、自分のユーザー名が「既存ユーザー」として並んでいたからです。

まず、レポートの話
その週の記録は、こうでした。ユーザー名は仮名にしています。
ユーザー名 ログイン試行回数 既存ユーザー
taro 4 はい
たろう 4 いいえ 下の「たろう」は存在しないユーザー名なので、ただの総当たりです。当たりません。
問題は上です。 実在するユーザー名が、正確に指定されている。
つまり、隠したつもりのものが、どこかから漏れていました。
「隠す方法」の記事が、たくさんある理由
調べると、対策の記事がいくらでも出てきます。それだけ知られている問題だということです。
実際、18万サイトを対象にした調査では、約15%のサイトでユーザーIDが見える状態だったという報告もあります。ログイン画面がそのままになっているサイトは、4割にのぼるそうです。
ただ、記事を読んでいて気づいたことがあります。
ほとんどが「1つか2つの経路を塞ぐ方法」で終わっているんです。投稿者アーカイブを止める。REST API を塞ぐ。それで「隠せました」と書いてある。
経路は、もっとあります。
漏れる経路を、並べてみる
自分が確認できた範囲で挙げます。
投稿者アーカイブ
いちばん有名な経路です。?author=1 でアクセスすると、投稿者ページに転送されます。
投稿者ページを使っていなくても起きます。 テーマに author.php がなくても、転送そのものは発生します。
REST API
/wp-json/wp/v2/users にアクセスすると、投稿しているユーザーの一覧が返ります。
ここには、表示名だけでなくスラッグも含まれます。 そしてスラッグは、初期状態だとユーザー名と同じです。
oEmbed
記事の埋め込み情報にも、投稿者の名前が入ります。/wp-json/oembed/1.0/embed?url=記事のURL のような形で取得できます。
REST API を塞いだつもりでも、こちらが残っていることがあります。
本文以外のHTML
テーマによっては、<body> タグのクラス属性に投稿者名が入っています。
画面上には表示されていなくても、ソースを見れば分かります。
コメント欄
管理者が自分のサイトにコメントを書くと、多くのテーマで投稿者名が表示されます。
RSS フィード
フィードにも、投稿者の情報が含まれます。
サイトマップ
WordPress が自動で出力するサイトマップに、投稿者アーカイブのURLが載っていることがあります。
対策しても、抜けることがある
ここが、いちばん書きたかった部分です。
投稿者アーカイブの対策としてよく紹介されるのが、functions.php に転送を止めるコードを書く方法です。
これを入れると、ブラウザで ?author=1 を開いても、トップページや404に飛ばされます。見た目には、隠せています。
ところが、コマンドラインから同じURLを叩くと、転送先のURLが見えることがあります。
curl -sI "https://自分のサイト/?author=1" | grep -i location ここに /author/ユーザー名/ のような値が出てきたら、ブラウザからは見えなくても、外からは分かる状態です。
転送の中身を止めるのと、転送そのものを止めるのは、違うということでした。
自分のサイトを確認する
攻撃の手順というより、自分の状態を知るための確認です。ひととおり見ておくと安心できます。
1. 投稿者アーカイブ
curl -sI "https://自分のサイト/?author=1" | grep -i location 何も出なければ、この経路は塞がっています。
2. REST API
curl -s "https://自分のサイト/wp-json/wp/v2/users" rest_no_route や空の配列が返れば、塞がっています。名前の一覧が返ってきたら、見えています。
3. oEmbed
curl -s "https://自分のサイト/wp-json/oembed/1.0/embed?url=https://自分のサイト/記事のURL" author_name が返ります。 ここが表示名になっているか、ユーザー名のままかを確認してください。
4. ページのソース
ブラウザで記事を開いて、ソースを表示し、自分のユーザー名で検索してみてください。
<body> のクラス、コメント欄、フィードへのリンク。思わぬところに入っていることがあります。
やっておく価値がある対策
「隠しきれない」と書きましたが、対策が無意味という意味ではありません。
経路が減れば、それだけ手間が増えます。簡単に見つかる状態より、ずっといい。
表示名を、ユーザー名と別にする
これがいちばん基本で、いちばん効きます。
管理画面の「ユーザー」→「プロフィール」で、ブログ上の表示名を変更できます。ユーザー名とは別の文字列にしてください。
スラッグを変える
表示名を変えても、URLに使われるスラッグは初期状態だとユーザー名のままです。
ここを変えるプラグインがあります。表示名だけ変えて安心しないでください。
セキュリティプラグインを入れる
投稿者アーカイブ、REST API、ログイン画面。まとめて設定できるものがあります。
自分でコードを書くより、抜けが少ないと思います。
ログインの試行回数を制限する
名前が漏れても、回数を制限すれば総当たりは通りません。
冒頭のレポートで4回で止まっていたのも、この仕組みが働いた結果です。
それでも、前提は変わらない
ひととおりやってから、あらためて思ったことがあります。
これらは全部、「名前が漏れたら困る」という前提の上に立っています。
そして、経路は今後も増えます。プラグインを入れれば、そのプラグインが新しい経路を作るかもしれない。テーマを変えれば、また変わる。
塞ぎ続けるしかない、という構造です。
名前が漏れた時点で、残る壁はパスワードだけになります。だから、パスワードを強くする方向に努力が向きます。
長くする。使い回さない。管理ソフトに入れる。回数を制限する。二段階認証を足す。
どれも有効です。ただ、どれも「破られる可能性」を前提にしています。
前提のほうを変える
それで、別の方向を考えるようになりました。
パスワードそのものを使わない方法です。指紋や顔でログインする、パスキーという仕組みがあります。買い物のサイトなどで、見たことがある方も多いと思います。
パスキーでは、サーバー側に「破れば通る秘密」が保存されません。 秘密の鍵は、利用者の端末から出ないからです。
そして、認証のときにドメインが照合されます。 偽のサイトでは成立しないので、フィッシングにも強い。
名前が漏れていても、それだけでは何もできません。
ユーザー名を隠す努力は続けるとして、そこが最後の防衛線ではない状態にしておく。そちらのほうが、気が楽になりました。
自分でも WordPress 向けのパスキープラグインを作って、公開しています。無料で試せます。
まとめ
- ユーザー名が漏れる経路は、投稿者アーカイブだけではない
- REST API、oEmbed、ページのソース、コメント欄、フィード、サイトマップ
- 対策コードを入れても、コマンドラインからは見えることがある
- 自分のサイトは
curlで確認できる。まず現状を知る - 表示名を変えるだけでは足りない。スラッグも変える
- 対策は無意味ではない。経路が減れば手間が増える
- ただし塞ぎ続ける構造で、経路は今後も増える
- 名前が漏れた時点で、残る壁はパスワードだけになる
- パスキーなら、名前が割れていても総当たりの対象がない
隠す努力をやめる必要はありません。ただ、それを最後の砦にしないほうが、安心できると思います。

