2026年6月2日
2026年6月2日
WordPressマルチサイトのセキュリティを強化する方法
はじめに
WordPressマルチサイトは1つのWordPressインストールで複数サイトを管理できますが、1か所の脆弱性がネットワーク全体に影響します。スーパー管理者権限の管理とサイト間の適切な分離が重要です。
症状・原因
- マルチサイトのサブサイトが不正に作成されている
- スーパー管理者権限が不必要なユーザーに付与されている
- あるサブサイトのマルウェアがネットワーク全体に波及した
- ユーザー登録を悪用されてスパムサイトが大量生成されている
解決手順
ステップ1:スーパー管理者の権限を最小化する
// wp-config.php または network-wide functions.php
// スーパー管理者の一覧を確認・管理
function audit_super_admins(): void {
$super_admins = get_super_admins(); // スーパー管理者ユーザー名の配列
foreach ($super_admins as $username) {
$user = get_user_by('login', $username);
if (!$user) {
// 存在しないユーザーをスーパー管理者から削除
revoke_super_admin($user->ID);
error_log("[Multisite] Removed ghost super admin: $username");
}
}
}
add_action('admin_init', 'audit_super_admins');
// スーパー管理者の追加を制限(特定IPからのみ許可)
add_filter('grant_super_admin', function(bool $grant, int $user_id): bool {
$allowed_ips = ['203.0.113.1']; // 管理者のIPアドレス
if (!in_array($_SERVER['REMOTE_ADDR'] ?? '', $allowed_ips, true)) {
error_log("[Multisite] Super admin grant blocked for user $user_id from " . ($_SERVER['REMOTE_ADDR'] ?? 'unknown'));
return false;
}
return $grant;
}, 10, 2);
ステップ2:新規サイト登録を制限する
// wp-config.php: マルチサイト登録設定
// 'all'=誰でも登録可 / 'none'=登録不可 / 'blog'=サイトのみ / 'user'=ユーザーのみ
// define('NOBLOGREDIRECT', 'https://example.com'); // 未登録ドメインをリダイレクト
// functions.php: サイト作成を承認制にする
add_action('wpmu_new_blog', function(int $blog_id, int $user_id): void {
// 新規サイトを即座にアーカイブ(停止)
update_blog_status($blog_id, 'archived', 1);
// 管理者に承認リクエストを送信
$admin_email = get_site_option('admin_email');
$site_url = get_blog_option($blog_id, 'siteurl');
wp_mail(
$admin_email,
'[要承認] 新規サイト登録: ' . $site_url,
"新規サイトが登録されました。\nURL: $site_url\n管理画面で承認してください。"
);
}, 10, 2);
ステップ3:ネットワーク全体にセキュリティポリシーを適用する
// mu-plugins/network-security.php: 全サブサイトに自動適用
// ① 全サイトで wp-config.php の直接アクセスを禁止
add_action('init', function(): void {
if (!is_admin()) return;
// 全サイトで wp_debug が本番環境でOFFになっているか確認
if (defined('WP_DEBUG') && WP_DEBUG && !defined('WP_ENVIRONMENT_TYPE')) {
error_log('[Multisite Security] WP_DEBUG is ON on site: ' . get_bloginfo('url'));
}
});
// ② ネットワーク全体のログイン試行制限
add_filter('authenticate', function($user, string $username): mixed {
$ip = $_SERVER['REMOTE_ADDR'] ?? '';
$key = 'login_fail_net_' . md5($ip);
$fails = (int) get_site_transient($key); // ネットワーク全体のトランジェント
if ($fails >= 5) {
return new WP_Error('too_many_attempts', 'ログイン試行回数が上限を超えました。');
}
return $user;
}, 30, 2);
add_action('wp_login_failed', function(): void {
$ip = $_SERVER['REMOTE_ADDR'] ?? '';
$key = 'login_fail_net_' . md5($ip);
$fails = (int) get_site_transient($key);
set_site_transient($key, $fails + 1, HOUR_IN_SECONDS);
});
ステップ4:サブサイト間のファイルアクセスを分離する
// mu-plugins/network-security.php: サブサイト間の分離強化
// アップロードディレクトリをサブサイトごとに分離(デフォルト動作の確認)
add_filter('upload_dir', function(array $dirs): array {
// マルチサイトではデフォルトで /wp-content/uploads/sites/{id}/ に分離済み
// 追加セキュリティ: 他サイトのアップロードパスへの直接アクセスをチェック
$current_site_id = get_current_blog_id();
$upload_path = $dirs['basedir'];
// 現在のサイトのパスに正しいIDが含まれているか確認
if (is_multisite() && strpos($upload_path, "/sites/$current_site_id") === false) {
error_log("[Multisite] Upload path mismatch on site $current_site_id: $upload_path");
}
return $dirs;
});
// .htaccess でサイト間のアップロードアクセスを制限
// /wp-content/uploads/sites/ ディレクトリの .htaccess:
/*
<FilesMatch "\.(php|php5|phtml|pl|py|cgi)$">
Require all denied
</FilesMatch>
*/
ステップ5:ネットワーク全体のセキュリティ監査ログを実装する
// mu-plugins/network-audit-log.php
// スーパー管理者ログインを記録
add_action('wp_login', function(string $username, WP_User $user): void {
if (!is_super_admin($user->ID)) return;
$log = sprintf(
'[%s] Super admin login: %s from %s on site %s',
current_time('Y-m-d H:i:s'),
$username,
$_SERVER['REMOTE_ADDR'] ?? 'unknown',
network_site_url()
);
error_log($log);
// ネットワーク管理者にメール通知
wp_mail(
get_site_option('admin_email'),
'[Multisite] スーパー管理者ログイン: ' . $username,
$log
);
}, 10, 2);
// サイトの作成・削除を記録
add_action('wpmu_new_blog', fn($id) => error_log("[Multisite] Site created: $id"), 10, 1);
add_action('wpmu_delete_blog', fn($id) => error_log("[Multisite] Site deleted: $id"), 10, 1);
注意事項
grant_super_adminフィルターはネットワーク管理画面からの操作にのみ適用されます。wp-cliや直接DBへの操作はバイパスされるため、DBアクセス制限も合わせて設定してくださいwpmu_new_blogでアーカイブ設定した場合、ネットワーク管理画面→サイト一覧から手動で「有効化」する必要がありますmu-plugins/に配置したファイルは全サブサイトで自動的に読み込まれます。バグがあるとネットワーク全体に影響するため、十分にテストしてください
まとめ
マルチサイトセキュリティは①get_super_admins()で権限監査・IP制限でスーパー管理者追加を制御、②wpmu_new_blogフックで新規サイトを即座にアーカイブして承認制に変更、③mu-plugins/にネットワーク全体ポリシーを配置してget_site_transient()でネットワーク共有のログイン制限を実装、④アップロードディレクトリのサイト間分離とPHP実行禁止の.htaccess設定、⑤スーパー管理者ログインをメール通知付きで監査ログに記録します。