WordPressのセキュリティ&アクセス制御の基本カスタマイズ集

カテゴリー その他

この回では、WordPress 初学者が最初に押さえておきたい「最低限のセキュリティまわり」を、functions.php ベースでまとめます。

  • ?author=1 などによるユーザー名列挙のブロック
  • REST API の制限
  • XML-RPC の無効化
  • ログイン画面のエラーメッセージ調整
  • ログイン画面ロゴ差し替え
  • テーマ/プラグイン編集の禁止

など、簡単だけど実戦投入しやすいスニペットが中心です。

大前提
ここで紹介するのは「守りの第一歩」であって、
WAF・ログ監視・バックアップなどを置き換えるものではありません。
あくまで「functions.php でできる範囲の補強」として捉えてください。

1. ?author=1 などによるユーザー列挙をブロック

何が問題なのか

WordPress では、
https://example.com/?author=1 のような URL にアクセスすると、

  • ID=1 のユーザーの投稿アーカイブページにリダイレクト
  • 結果として、そのユーザーの「ログインID(ユーザー名)」が露出する

という挙動があります。

総当たり攻撃の足がかりになるので、簡易的にでも塞いでおく価値はあります。

コード(functions.php)

// ?author=1 などによるユーザー列挙をブロック
add_action( 'init', function () {
  if ( ! is_admin() && isset( $_GET['author'] ) ) {
    wp_redirect( home_url( '/' ), 301 );
    exit;
  }
} );

これでどうなる?

  • ?author=1 にアクセスされても、常にトップページ(home_url(‘/’))へ 301 リダイレクト。
  • ユーザー名が URL に露出しにくくなります。

※ これだけで「完全に」ユーザー名を隠せるわけではありませんが、
よくある雑なスキャンをいくらか防げます。

2. REST API をログインユーザーのみに制限する

REST API とは

https://example.com/wp-json/wp/v2/posts のようなURLで、

  • 投稿リスト
  • 固定ページ
  • カスタム投稿

などを JSON 形式で取れる仕組みです。

便利ですが、外部公開の必要がなければ「見せなくていい情報」でもあります。

コード(functions.php)

// REST API をログインユーザーのみに制限
add_filter( 'rest_authentication_errors', function ( $result ) {
  if ( ! empty( $result ) ) {
    return $result;
  }

  if ( ! is_user_logged_in() ) {
    return new WP_Error(
      'rest_forbidden',
      'REST API はログインユーザーのみ利用可能です。',
      array( 'status' => 401 )
    );
  }

  return $result;
} );

効果

  • 未ログインで REST API にアクセスすると、常に 401 エラーが返るようになります。
  • ログイン中ユーザーは、従来どおり REST API を利用できます。

強い注意点

  • ブロックエディタ(Gutenberg)や、RESTベースのプラグインを使っている場合、機能が壊れる可能性が高いです。
  • headless CMS 的な構成や SPA と連携している場合もアウトです。

実務的には、

  • クラシックエディタ+REST非利用 のシンプルな企業サイト
  • 管理画面も最低限で、API公開の必要がない
    といった案件向けの設定です。

3. XML-RPC API を完全に無効化する

XML-RPC とは

  • 外部ブログエディタ(Windows Live Writer など)
  • モバイルアプリ
  • 一部のプラグイン(古い Jetpack など)

から WordPress を操作するための古い API です。

最近は REST API が主流になっており、
使っていないのに攻撃対象だけ残っているケースがよくあります。

コード

// XML-RPC API を完全に無効化
add_filter( 'xmlrpc_enabled', '__return_false' );

これでどうなる?

  • xmlrpc.php にアクセスされても、XML-RPC自体が無効になります。
  • 外部投稿ツールや古い連携機能は動かなくなります。

XML-RPC を本当に使っていないかどうかは、

  • Jetpack などのプラグイン仕様
  • 外部サービスとの連携
    を確認してから切るのが安全です。

4. ログインエラーメッセージをぼかす

デフォルトでは、

  • ユーザー名が違うとき
  • パスワードが違うとき

で、エラーメッセージの内容が微妙に違います。

これだと「ユーザー名が合っているかどうか」が推測しやすくなるため、
総当たり攻撃のヒントを与えてしまうことになります。

コード

// ログインエラーメッセージをぼかす
add_filter( 'login_errors', function () {
  return 'ユーザー名またはパスワードが違います。';
} );

効果

  • どんな条件で失敗しても、常に同じメッセージが表示されます。
  • 攻撃者側からは、「ユーザー名/パスワードのどちらが間違いか」を判別しづらくなります。

5. ログイン画面の WordPress ロゴを差し替える

セキュリティというより ブランド統一と心理的な「自分のサイト感」を出すための小ネタですが、
実案件でほぼ毎回聞かれるカスタマイズです。

想定

  • テーマディレクトリ配下に、assets/login-logo.png を用意しておく。

コード

// ログイン画面のWordPressロゴを差し替え
add_action( 'login_enqueue_scripts', function () {
  $logo = get_template_directory_uri() . '/assets/login-logo.png';
  echo '<style type="text/css">
  .login h1 a {
    background-image: url(' . esc_url( $logo ) . ');
    background-size: contain;
    width: 200px;
    height: 80px;
  }
  </style>';
} );

ポイント

  • width / height / background-size は、ロゴ画像のアスペクト比に合わせて調整します。
  • 細かくやるなら、このインラインCSSではなく login_enqueue_scripts で別CSSを読み込んでもOKです。

6. テーマ/プラグイン編集を禁止する

管理画面から、

  • 外観 → テーマファイルエディター
  • プラグインエディター

を経由して PHP を直接編集できてしまうのは、正直かなり危険です。

想定される事故:

  • クライアントが functions.php を触って真っ白にする
  • 攻撃者にログインされたとき、その場で Web Shell 的なコードを仕込まれる

など。

本来は wp-config.php に書く想定の定数ですが、
ここ(functions.php)で定義しても有効です。

コード

// テーマ/プラグイン編集を禁止
if ( ! defined( 'DISALLOW_FILE_EDIT' ) ) {
  define( 'DISALLOW_FILE_EDIT', true );
}

これでどうなる?

  • 「テーマファイルエディター」「プラグインエディター」が非表示になります。
  • ファイルの修正は、FTP や Git 経由に限定されます。

開発者目線では多少不便ですが、
本番環境では **「管理画面からPHPを触らない」文化を強制すること自体がセキュリティ」**とも言えます。

7. セキュリティ系スニペットのまとめコード例

実際の案件では、これらを1つのセクションとしてまとめておくと管理しやすいです。

/**
 * セキュリティ・アクセス制御系カスタマイズ
 */

// ?author=1 などによるユーザー列挙をブロック
add_action( 'init', function () {
  if ( ! is_admin() && isset( $_GET['author'] ) ) {
    wp_redirect( home_url( '/' ), 301 );
    exit;
  }
} );

// REST API をログインユーザーのみに制限(要注意)
add_filter( 'rest_authentication_errors', function ( $result ) {
  if ( ! empty( $result ) ) {
    return $result;
  }
  if ( ! is_user_logged_in() ) {
    return new WP_Error(
      'rest_forbidden',
      'REST API はログインユーザーのみ利用可能です。',
      array( 'status' => 401 )
    );
  }
  return $result;
} );

// XML-RPC API を完全に無効化
add_filter( 'xmlrpc_enabled', '__return_false' );

// ログインエラーメッセージをぼかす
add_filter( 'login_errors', function () {
  return 'ユーザー名またはパスワードが違います。';
} );

// ログイン画面のWordPressロゴを差し替え
add_action( 'login_enqueue_scripts', function () {
  $logo = get_template_directory_uri() . '/assets/login-logo.png';
  echo '<style type="text/css">
  .login h1 a {
    background-image: url(' . esc_url( $logo ) . ');
    background-size: contain;
    width: 200px;
    height: 80px;
  }
  </style>';
} );

// テーマ/プラグイン編集を禁止
if ( ! defined( 'DISALLOW_FILE_EDIT' ) ) {
  define( 'DISALLOW_FILE_EDIT', true );
}

Qiita に載せるときは、このブロックを出したうえで、
上で説明したような「何のためのコードか」「どんなときに使ってはいけないか」を補足してあげると、
「コピペで動く」だけでなく「判断材料としても使える」記事になります。

8. まとめ

今回のセキュリティ編の位置づけを整理すると:

項目分類現実的な効果
?author=1 ブロック情報露出低減攻撃者の足がかりを削る
REST API 制限公開面の制御REST非利用サイトでは情報露出を減らせる
XML-RPC 無効化古い攻撃ベクター封じ使っていないなら止めたほうが安全
ログインエラーぼかし情報露出低減ユーザー名特定を少し難しくする
ログインロゴ差し替えブランド/心理面クライアント満足度&「ちゃんと専用サイト感」
ファイル編集禁止権限削減誤操作&乗っ取り時の被害範囲を小さくする

「これを入れておけば絶対安全」というものではありませんが、
「何も考えずにデフォルトのまま」よりは明らかにマシになるライン
です。

その他の記事

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

日本語が含まれない投稿は無視されますのでご注意ください。(スパム対策)