この回では、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 無効化 | 古い攻撃ベクター封じ | 使っていないなら止めたほうが安全 |
| ログインエラーぼかし | 情報露出低減 | ユーザー名特定を少し難しくする |
| ログインロゴ差し替え | ブランド/心理面 | クライアント満足度&「ちゃんと専用サイト感」 |
| ファイル編集禁止 | 権限削減 | 誤操作&乗っ取り時の被害範囲を小さくする |
「これを入れておけば絶対安全」というものではありませんが、
「何も考えずにデフォルトのまま」よりは明らかにマシになるラインです。
