最近 WordPress でコーポレートサイトを新規に立ち上げる機会があったため、備忘録として記録します。
概要
複数人で管理するため、管理用アカウントや投稿用アカウントなど、用途や利用者毎にアカウントを発行することになると思いますが、Wordpress ではWordPress REST API や author 情報などの機能を利用すると、これらのアカウント名を簡単に特定出来るようになっています。
適切にアカウント名やパスワードを管理していれば問題はないと思いますが、使用する人数が増えると意図しない管理を行う社員も出てきますし、教育だけでは100%防ぐことはできません。管理者としてはなかなか悩ましいですが、だからといって放置する訳にもいきません。
アカウント情報が漏れた場合、ブルートフォースアタックの被害に遭ったり、ウェブサイトが改ざんされて悪用されたりする場合があります。
そこで、少しでも確率を減らすためにユーザー名を特定されないようにする方法を紹介します。
この方法で確実に防ぐことができる保証はありませんが、最低限行うべきと考えます。
詳細
ユーザー名漏えいの原因
author 情報からの漏えい
WordPress ではユーザー毎に/author/ユーザー名
というURLで著者ページが存在するのですが、この「ユーザー名」の部分にニックネームなどではなく、ログイン時に使用するユーザー名がそのまま表示されてしまいます。
また、この著者ページはユーザー名を知らなくても、以下のURLでアクセスすることで、上記のページにリダイレクトされます。
サイトのURL/?author=1
他のアカウントを探す場合は?author=1
の「1」の部分を「2」「3」と順番に変えていくことで容易に探すことができます。防ぐためには上記のようなリクエストが行われた場合にスクリプトを終了したり、リダイレクトするような設定を行います。
WordPress REST API 機能からの漏えい
WordPress REST APIは、WP-CLIやURLベースで WordPress 外からウェブサイトのデータを取得できる仕組みです。これを利用することで、認証を必要とせずに WordPress の投稿や編集、削除などが行えますので、他システムとの連携をシームレスに行える利点があります。
活用できる機会があれば便利な機能なのですが、通常の運用をする際には使うことのない機能なのですが、この機能を利用して以下のURLでアクセすると、json 形式のユーザーのデーターが表示されます。
サイトのURL/wp-json/wp/v2/users
上記のように、容易にユーザー情報や投稿情報などが承認を通さずに取得できてしまいますので、Wordpress REST API を利用していない場合は、この機能を無効にしてしまいます。
ただ、無効にする場合に注意すべき点があります。
Contact Form7 や Jetpack など REST API を使用しているプラグインが存在します。これらのプラグインを有効にしている状態で REST API を無効にすると動作しなくなったりしますので、無効にする場合は一部のプラグインを除外するような設定が必要です。
利用しているテーマからの漏えい
便利な機能を持つテーマも多く、様々なデザインのウェブサイトをお手軽に構築できるため便利ですが、テーマの機能によっては上記でも紹介した著者ページへのリンクを自動で埋め込んでくれる場合があります。
私が利用しているテーマではプロフィールウィジェットを利用した際、名前の部分に著者ページへのリンクが埋め込まれていました。そのリンクのURLは/author/ユーザー名
の形式でしたので、ユーザー名にはログイン時に利用するユーザー名が表示されていました。
ユーザープロフィールからの漏えい
固定ページや投稿ページで著者を表示する機能があります。
ユーザープロフィールの設定を変更していない場合、著者の部分にログイン時に使用するユーザ名が表示されます。
コードで漏えいを防止する方法
author 情報が表示されないようにする
以下のいずれかの場所にコードを記述することで対応することができます。
functions.php に記述する方法
使用しているテーマの function.php ファイルに以下のコードを追加します。
if (!is_admin()) { // default URL format if (preg_match('/author=([0-9]*)/i', $_SERVER['QUERY_STRING'])) die(); add_filter('redirect_canonical', 'shapeSpace_check_enum', 10, 2); } function shapeSpace_check_enum($redirect, $request) { // permalink URL format if (preg_match('/\?author=([0-9]*)(\/*)/i', $request)) die(); else return $redirect; }
このコードの動作を要約すると以下になります。
- リクエストが WordPress の管理ページに対するものか確認します。
- URLが著者ページに対するものである場合は、リクエストをブロックします。
以下の部分で管理ページに対するリクエストか確認しています。
管理ページに対するものである場合は何もしません。
if (!is_admin())
管理ページに対するものでない場合は、チェック処理を行います。
パーマリンク設定で基本(Default)を設定している場合のチェック処理です。
著者ページ向けのリクエストの場合は、die()
でスクリプトを終了しています。
なので、ブラウザには真っ白の画面が表示されます。
if (preg_match('/author=([0-9]*)/i', $_SERVER['QUERY_STRING'])) die();
add_filter('redirect_canonical', 'shapeSpace_check_enum', 10, 2)
でリダイレクト時の処理に「shapeSpace_check_enum」関数を呼び出すように紐付けています。
add_filter('redirect_canonical', 'shapeSpace_check_enum', 10, 2);
「shapeSpace_check_enum」関数はパーマリンク設定で基本(Default)以外が設定されている場合のチェック処理です。こちらも同様に条件に一致する場合はスクリプトを終了します。
function shapeSpace_check_enum($redirect, $request) { // permalink URL format if (preg_match('/\?author=([0-9]*)(\/*)/i', $request)) die(); else return $redirect; }
このコードは「Stop User Enumeration in WordPress」で紹介されているものになります。
検索するとよく出てくるコードではif( $_GET['author'] || preg_match('#/author/.+#', $_SERVER['REQUEST_URI']) )
というものがよくありますが、著者曰く$_GET['author']
ではテーマやプラグインによっては競合する可能性が少なからずあるため、この方法をとっているとのことでした。私も競合をさけるため、この方法を利用しています。
このコードでは、リダイレクトせずにスクリプトを終了していますので、リダイレクトしたい場合は以下のように変更します。
if (!is_admin()) { // default URL format if (preg_match('/author=([0-9]*)/i', $_SERVER['QUERY_STRING'])){ wp_redirect( home_url('/404.php') ); exit; } add_filter('redirect_canonical', 'shapeSpace_check_enum', 10, 2); } function shapeSpace_check_enum($redirect, $request) { // permalink URL format if (preg_match('/\?author=([0-9]*)(\/*)/i', $request)){ wp_redirect( home_url('/404.php') ); exit; } else { return $redirect; } }
.htaccess に記述する方法
WordPress のインストールディレクトリにある .htaccess に追加します。
<IfModule mod_rewrite.c> RewriteCond %{QUERY_STRING} ^author=([0-9]*) RewriteRule .* https://example.com/? [L,R=302] </IfModule>
/?author=n
へのアクセスを「https://example.com」リダイレクトします。
WordPress REST API を無効にする
使用しているテーマの function.php ファイルに以下のコードを追加します。
function deny_restapi_except_plugins_demo( $result, $wp_rest_server, $request ){ $namespaces = $request->get_route(); //oembedの除外 if( strpos( $namespaces, 'oembed/' ) === 1 ){ return $result; } //Jetpackの除外 if( strpos( $namespaces, 'jetpack/' ) === 1 ){ return $result; } //Contact Form7の除外 if( strpos( $namespaces, 'contact-form-7/' ) === 1 ){ return $result; } return new WP_Error( 'rest_disabled', __( 'The REST API on this site has been disabled.' ), array( 'status' => rest_authorization_required_code() ) ); } add_filter( 'rest_pre_dispatch', 'deny_restapi_except_plugins_demo', 10, 3 );
上記のようにすることで、Contact Form7 などのプラグインを除外しつつ、REST API を無効にすることができます。こちらのコードはこちらの記事で解説されていました。
除外するプラグインを追加したい場合はif( strpos( $namespaces, 'contact-form-7/' ) === 1 )
のcontact-form-7/
の部分を除外したいプラグインのディレクトリ名に変更して追加します。
特に影響するプラグインが有効になっていない場合は以下のコードで REST API を無効にすることができます。
function disable_rest_api() { return new WP_Error( 'disabled', __( 'REST API is disabled.' ), array( 'status' => rest_authorization_required_code() ) ); } add_filter( 'rest_authentication_errors', 'disable_rest_api' );
テーマをカスタマイズする
テーマによってカスタマイズ方法がことなるため、私の場合の例を紹介します。
私は WordPress のテーマに Cocoon を利用しています。
このテーマでプロフィールウィジェットを利用した場合、名前の部分に著者ページへのURLがリンクとして埋め込まれます。
このリンクを無効にするためにこのテーマの function.php ファイルに以下のコードを追加します。
//プロフィールボックスの名前のタグを外す add_filter( 'the_author_box_name', function ($name){ return strip_tags($name); });
上記のコードはこのテーマのサポートページで紹介されていました。
プラグインで無効にする方法
WordPress REST API を無効にする機能だけがあるプラグインもありますが、私は他のセキュリティ対策もかねて「SiteGuard」というプラグインを利用しています。
詳細の説明は割愛しますが、ログインページをデフォルトのURLから変更したり、ログインに文字認証を追加したり、この記事で行うとしているユーザー名漏えいを防ぐ機能も搭載されています。
ここではこのプラグインの「ユーザー名漏えい防御」機能を利用します。
インストール方法などについては以下の記事をご参考ください。
設定方法も簡単ですので、プラグインに制約がなければこのプラグインを利用する方法をおすすめします。
author 情報が表示されないようにする
プラグインをインストールした後、メニューに追加された「SiteGuard」をクリックします。
ダッシュボードが表示されますので、「ユーザー名漏えい防御」をクリックします。
初期設定では「OFF」になっていますので、クリックして「ON」にします。
わかりにくいかもしれませんが、色の濃い方が選択された状態になります。
「ON」にした後、画面下の「変更を保存」をクリックします。
WordPress REST API を無効にする
プラグインをインストールした後、メニューに追加された「SiteGuard」をクリックします。
ダッシュボードが表示されますので、「ユーザー名漏えい防御」をクリックします。
「REST API 無効化」にチェックを入れます。
REST API の無効化を除外するプラグインをこの画面で設定することができます。
上の枠が除外するプラグインの一覧で、下が除外の対象になっていないプラグインの一覧です。
除外の対象にする場合は、上の枠内に手入力するか、下の枠内のプラグイン名をクリックして選択し、「除外プラグイン 追加」ボタンを押すかのいずれかの方法で設定することができます。
除外するプラグインも設定したら「変更を保存」をクリックします。
WordPress の設定で漏えいを防止する方法
ユーザープロフィールの設定を変更する
ユーザーを作成した直後はニックネームやブログ上の表示名がユーザー名と同じものになっていますので、「ニックネーム」と「ブログ上の表示名」を変更します。
「ニックネーム」を変更し、「ブログ上の表示名」のドロップダウンリストをクリックすると、先ほど入力したニックネーム「ほげ」が追加されていますので、「ほげ」をクリックします。
変更した後、「ユーザーを更新」をクリックします。
おわりに
ログイン時に使用するユーザー名を漏えいさせないための設定方法を紹介いたしました。
ユーザー名が漏れると攻撃の対象になります。その被害が自分だけで済めばまだいいのですが、サイトが改ざんされマルウェア感染の踏み台に利用されたりしますし信用も失います。そうならないために対策するようにしましょう。
今回の設定方法だけではすべてのケースに対応できるものではありませんので、セキュリティ対策の一つとして取り扱っていただけたらと思います。