Produced by FOURIER

WordPressでユーザー名を非公開にする戦いの歴史

OhashiOhashi calender 2022.7.8

みなさんは WordPress を構築する際、ユーザー名を非公開にできていますか?

バージョンが上がるにつれユーザー名がさまざまな機能から公開されるようになりました。これには、なんとしてでもユーザー名を公開したいという WordPress の思いを感じざるを得ません。

これはそんな WordPress とのユーザー名の公開をかけた戦いの歴史と対策についての記事となっています。

はじめに

この記事は WordPress でユーザー名が公開されてしまう問題とそれに対する対策方法を記載しています。対策方法はfunctions.php に記述する方法とプラグインの 「All in one security」 を使用した方法を記述しています。また、ユーザーページを表示したいこともあるかと思いますのでその辺りも考慮した内容となっています。

All-In-One Security (AIOS) – Security and Firewall – WordPress プラグイン | WordPress.org 日本語

Protect your website investment with All-In-One Security (AIOS) – a comprehensive and easy to use security plugin designed especially for WordPress.

https://ja.WordPress.org/plugins/all-in-one-wp-security-and-firewall/

なぜユーザー名が表示されるとよくないのか

WordPress のユーザー名は管理画面へログインするためにも利用されているため、パスワードを一致させるだけでよくなり、ユーザー名とパスワードを一致させるよりも不正ログインのリスクが上がってしまうからです。

しかし、ユーザー名を非表示にしただけではセキュリティ対策としては不十分であり、以下の対策も併せて行うことを推奨します(以下の対応方法については本記事の対象外となります)。

  • ログインページのURLをデフォルトの /wp-login から変更
  • ログインページへのBasic認証やIP制限の追加
  • パスワードを半角英数(大文字 / 小文字)、記号を併用した強固なものにする
  • 2段階認証の導入

ユーザー名が表示される機能が追加された年

History – WordPress.org Forums

WordPress was born out of a desire for an elegant, well-architectured personal publishing system built on PHP and MySQL and licensed under the GPL. It is the official successor of b2/cafelog. WordP…

https://wordpress.org/support/article/history/

時期内容
① the_author()で投稿者名を取得した際にユーザー名が使用される
② ユーザーページが追加される
2015年12月08日WordPress 4.7 “Vaughan” がリリースされる
③ REST API がデフォルトで有効になる
2020年08月11日WordPress 5.5 “Eckstine” がリリースされる
④ サイトマップが作成されるようになる

ユーザー名を非表示にするための対策

前提として、管理画面の「 設定 > パーマリンク設定」が日付と投稿名(http://localhost:8080/2022/06/16/sample-post/ )で検証しています。その他の設定の場合はアクセスURL等が異なる場合があります。

また、functions.php を編集しても設定が反映されない場合は「管理画面 > 設定 > パーマリンク設定」で更新を行うことで反映されることがあります(何も変更しなくても問題ありません)。

それではそれぞれの機能でどのようにユーザー名が表示されるのかとその対策についてみていきましょう。

① the_author()等で投稿者名を取得した際にユーザー名が使用される

タイトル通りですがthe_author() で表示されるユーザー名が、何も設定していない場合はログインユーザー名と同様になり簡単にユーザー名を知ることができてしまいます。

そこで取得されるユーザー名を変更するためには、以下の手順で管理画面から設定を行う必要があります。

  1. 管理画面の「ユーザー > ユーザー一覧」を選択します
  1. 表示されるユーザー名を変更するユーザーを選択します
  1. ニックネームに入力したことのある内容がブログ上の表示名に設定可能なため、初めにニックネームを入力しブログ上の表示名を変更します
  1. 最後にユーザーを更新をクリックし設定を反映させ設定が完了になります

② ユーザーページが追加される

ユーザーページの内容には問題はないのですが、ユーザーページのURLが /author/<ユーザー名>/のようにユーザー名が使用されています。また、/?author=<ユーザーID> のようにアクセスすることで/author/<ユーザー名>/ にリダイレクトされるためユーザーIDを 1 から順に試すことでユーザー名が簡単にわかってしまいます。

他にも、/author/<ユーザー名> のように末尾に「/」がない場合、正しいユーザー名を指定すると/author/<ユーザー名>/ にリダイレクトされ、存在しないユーザー名の場合は404ページへリダイレクトされるのでこの方法でも確認可能です。

functions.php を使用した対策

ユーザーページを使用しないのであれば以下の方法が最もシンプルであり安全性も高いためこちらの方法で対策されるのが良いかと思います。

// authorページにアクセスされたらトップページにリダイレクトする
add_action('template_redirect', 'redirect_author_archive_to_top');
function redirect_author_archive_to_top() {
    if (is_author()) {
        wp_redirect(home_url());
        exit;
    }
}

しかしユーザーページを使用したいことも多々あるかと思います。その場合の例として、以下ではユーザーのロール(権限)とユーザー名で表示するユーザーを設定しています。

この方法を採用する場合の注意点としては、許可したユーザーのユーザー名はURLに表示されてしまうため、管理者のような権限の高いユーザーは極力表示しないようにする必要があります。そうしないと管理者として不正ログインされた場合には、サイトに対してあらゆる操作が可能となってしまうからです。

  1. 特定のロールのユーザーを表示するための定数を定義します
  // 表示したいユーザーのロールを記述
  define('ROLES_THAT_CAN_DISPLAY_AUTHOR_ARCHIVES', [
      // 'subscriber',    // 購読者
      // 'contributor',   // 寄稿者
      'author',        // 投稿者
      // 'editor',        // 編集者
      // 'administrator', // 管理者
  ]);
  1. 特定のユーザー名のユーザーを表示するための定数を定義します
// 表示したいユーザーのユーザー名を記述 ※表示名ではないことに注意
define('USER_NAMES_THAT_CAN_DISPLAY_AUTHOR_ARCHIVES', [
    'user',
]);
  1. 先ほど定義した定数を利用して表示可能なユーザーかどうかを判定する関数を定義します
/**
 * 表示が許可されているユーザーか判定
  *
  * @param \WP_User $user
  * @return boolean
  */
function can_display_user($user) 
{
    return in_array($user->user_login, USER_NAMES_THAT_CAN_DISPLAY_AUTHOR_ARCHIVES, true)
        || count(array_diff(ROLES_THAT_CAN_DISPLAY_AUTHOR_ARCHIVES, $user->roles)) < count(ROLES_THAT_CAN_DISPLAY_AUTHOR_ARCHIVES);
}
  1. ユーザーページにアクセスされた際、表示が可能なユーザー以外の場合にはトップページにリダイレクトするよう設定します
add_action('template_redirect', function () {
    if (!is_author()) {
        return;
    }

    if(!($author = get_userdata(get_query_var('author')))) {
        // 著者情報が取得できなかった場合
        return;
    }

    if (can_display_user($author)) {
        return;
    }

    wp_redirect(home_url());
    exit;
});

All in one security を使用した対策

こちらの方法では、/?author=<ユーザーID>へアクセスした際/author/<ユーザー名>/ へリダイレクトされることを防ぐことのみ可能です。なのでユーザーページが不要もしくは一部のユーザーのみユーザーページが必要な場合には functions.phpの方法で対策したほうが良いかと思います。

  1. 管理画面の「WP セキュリティ > その他」を選択します
  1. ユーザー番号を選択します
  1. 「ユーザー番号を無効化したい場合にはこれをチェックしてください。」をチェックし設定を保存します
  1. 実際に/?author=<ユーザーID> でアクセスし以下のように表示されていたら設定は完了になります

③ REST API にユーザー一覧の取得機能が追加される

REST API にはユーザー情報を取得する機能があり/wp-json/wp/v2/users へアクセスすることで全てのユーザー情報が取得可能となっています。

取得可能なユーザー情報として、もしtestという名前でユーザーを作成していた場合 /wp-json/wp/v2/usersへアクセスすることで以下のようなユーザー情報が取得可能となっており、ユーザー名が簡単にわかってしまいます。

[{
  "id": 1,
  "name": "test",
  // 省略
  "link":"http:\/\/localhost:8080\/author\/test\/",
  "slug":"test",
  // 省略
}]

そこで、REST API を使用しない場合は以下の方法で無効にすることが可能です。注意点として、管理画面の機能で REST API を使用しているのでログインしていない場合のみ無効にするようにする必要があります。

add_filter('rest_authentication_errors', function () {
  return is_user_logged_in() ?: new WP_Error('disabled', __('Unauthorized'), ['status' => rest_authorization_required_code()]);
});

ただし、上記の方法ですとプラグインでREST API を使用していた場合プラグインが動作しなくなってしまうためその場合は以下のような方法で対応することが可能です。

以下の方法の場合、/wp-json/wp/v2/users/wp-json/wp/v2/users/<ユーザーID> へのアクセスを無効化しています。

また別の方法として特定のプラグインのみ許可する方法もありますが、最近では REST API の使用が進んできており個別に対応するのは大変なため不要なエンドポイントを削除するようにしています。

add_filter('rest_endpoints', function ($endpoints) {
    if (isset($endpoints['/wp/v2/users'])) unset($endpoints['/wp/v2/users']);
    if (isset($endpoints['/wp/v2/users/(?P[\d]+)'])) unset($endpoints['/wp/v2/users/(?P[\d]+)']);

    return $endpoints;
});

All in one security を使用した対策

こちらの方法ですとREST APIを無効化する方法しかないため、プラグイン等で REST API を使用している場合は使用することができません。なのでその場合はfunctions.phpで行う必要があります。

  1. 管理画面の「WP セキュリティ > その他」を選択
  1. WP REST API を選択
  1. 「ログインしていないリクエストに対する REST API アクセスを停止したい場合にチェックを入れます。」をチェックし設定を保存
  1. 管理画面からログアウトした状態で /wp-json/wp/v2/users 等にアクセスし以下のようになっていたら設定が完了です

<img alt="" width=801" height="149" loading="lazy" src="/techblog/image/article/hide-username-in-wordpress/image12.png">

④ サイトマップが作成されるようになる

サイトマップの生成機能が追加され、 /wp-sitemap.xml にアクセスすると以下のようにサイトマップが表示されるようになりました。

このサイトマップにユーザーページへのリンクが含まれており、/wp-sitemap-users-1.xml のリンクをクリックするとユーザー名の入ったURLが表示されます。

以下はtestという名前でユーザーを作成していた場合に/wp-sitemap-users-1.xml へアクセスした際の表示となります。このように簡単にユーザー名を取得することができてしまいます。

functions.php を使用した対策

WordPressデフォルトのサイトマップを使用しない場合は以下のように対応することでサイトマップが作成されないようにすることが可能です。

しかし、サイトマップがないのはSEO的によろしくないので代替となるサイトマップ生成プラグインを追加することを推奨します。

add_filter('wp_sitemaps_enabled', '__return_false');

他にはサイトマップは使用したいが、ユーザーページを使用しておらずユーザーのサイトマップが不要な場合もあるかと思います。その場合は以下のように対応することでユーザーページ以外のサイトマップが作成されるようになります。

add_filter('wp_sitemaps_add_provider', function ($provider, $name) {
    return 'users' === $name ? false : $provider;
}, 10, 2);

また、ユーザーページと同様に特定のユーザーはサイトマップに表示させたい場合もあるかと思います。その場合は「ユーザーページが追加される」の章で作成した can_display_user 関数を利用し以下のようにすることで、表示させたいユーザーのみサイトマップに表示することが可能となります。

add_filter('wp_sitemaps_users_entry', function ($sitemap_entry, $user) {
    return can_display_user($user) ? $sitemap_entry : [];
}, 10, 2);

All in one security を使用した対策

こちらのプラグインでは機能がなく対応ができないため、functions.php で対応するかもしくは、サイトマップを生成するプラグインでは、WordPressデフォルトのサイトマップを無効しつつ、サイトマップに表示する項目を細かく設定できるようなプラグインも存在するためそちらで対応する必要があります。

さいごに

いかがでしたでしょうか?

ユーザー名を非表示にするだけでこれだけの作業が必要となるのです。今後もWordPressはバージョンアップを重ねさらに進化をしていきます。ですので、ユーザー名を非表示にするための戦いはまだまだこれからも続いていくことでしょう。

新しいメンバーを募集しています

Ohashi

Ohashi / Engineer

主にLaravelなどのバックエンドを中心にサーバー周りも担当しています。 目標は腕周り40cm 越え。