2026年5月20日

2026年5月20日

WordPress の xmlrpc.php(XML-RPC)を無効化する方法|フィルターの限界と Apache 2.4・Nginx での遮断

XML-RPC(xmlrpc.php)は、外部のアプリやサービスがWordPressに投稿したり、ピンバックを送ったりするための古いAPIです。現在の多くの用途はREST APIに移っていますが、2026年10月時点でもWordPress本体では既定で有効です。使っていないサイトでは、パスワードの総当たりやピンバックの悪用の入口になるため、止めておくと攻撃の対象を減らせます。

この記事では、XML-RPCが使われているかを確かめたうえで、WordPress側の設定とWebサーバー側の設定で無効化する手順を説明します。

XML-RPCで狙われる点

  • パスワードの総当たり:wp.getUsersBlogs などの認証付きメソッドに、ユーザー名とパスワードを送り付けて試す攻撃です。WordPress 4.4以降は、system.multicall で1回のリクエストに多数のログイン試行を詰め込んでも、最初の失敗以降は認証を行わずに失敗を返すようになっています。それでもリクエストの数だけPHPが動くため、サーバーの負荷にはなります
  • ピンバックの悪用:pingback.ping を使うと、サイトに「このURLから言及された」と通知できます。WordPressはその確認のために相手のURLへアクセスするため、多数のサイトを使って特定のサーバーに大量のアクセスを送る攻撃(リフレクション)に使われることがあります

手順1:XML-RPCが使われているか確認する

止める前に、自分のサイトでXML-RPCを使っているものがないかを確認します。代表的な利用者は次のとおりです。

  • Jetpack(WordPress.comのサーバーとの通信に xmlrpc.php を使う)
  • XML-RPCで投稿する外部のアプリや投稿ツール、古い連携サービス
  • 他サイトからのピンバック

アクセスログを見ると、実際に誰が使っているかが分かります。

# xmlrpc.php へのPOSTの件数(Nginxの例。Apacheなら /var/log/apache2/access.log など)
grep -c 'POST /xmlrpc.php' /var/log/nginx/access.log

# アクセス元IPの上位
grep 'POST /xmlrpc.php' /var/log/nginx/access.log | awk '{print $1}' | sort | uniq -c | sort -rn | head -20

プラグインがXML-RPCに関わるコードを持っているかも確認できます。名前が挙がったプラグインは、説明やドキュメントでXML-RPCが必要かを確かめてください(コード中に文字列があるだけで、使っていない場合もあります)。

cd /var/www/html
grep -rlE 'xmlrpc|XMLRPC' wp-content/plugins --include='*.php' | cut -d/ -f3 | sort -u

どのメソッドが呼ばれているかまで知りたい場合は、一時的に次のコードを wp-content/mu-plugins/log-xmlrpc.php として置き、数日分を記録します。記録はPHPのエラーログ(WP_DEBUG_LOG を有効にしていれば wp-content/debug.log)に出ます。調査が終わったらファイルを削除してください。

<?php
/**
 * Plugin Name: Log XML-RPC calls
 * Description: 無効化の前に、XML-RPC がどこから・どのメソッドで使われているかを記録する(調査が終わったら削除する)。
 */

add_action(
	'xmlrpc_call',
	function ( string $method ): void {
		error_log(
			sprintf(
				'[XMLRPC] method=%s ip=%s ua=%s',
				$method,
				$_SERVER['REMOTE_ADDR'] ?? 'unknown',
				$_SERVER['HTTP_USER_AGENT'] ?? 'unknown'
			)
		);
	}
);

手順2:現在の状態を確かめる方法を知っておく

設定の前後で、次のコマンドを実行して結果を比べます。存在しないユーザー名とパスワードでログインが必要なメソッドを呼び、応答の違いで状態を判断します。

curl -s -o /dev/null -w '%{http_code}\n' -X POST https://example.com/xmlrpc.php \
  -H 'Content-Type: text/xml' \
  -d '<?xml version="1.0"?><methodCall><methodName>wp.getUsersBlogs</methodName><params><param><value>nobody</value></param><param><value>wrong</value></param></params></methodCall>'
応答 状態
200(本文に faultCode 403 の「Incorrect username or password.」) XML-RPCは有効。認証まで処理されている
405(本文に「XML-RPC services are disabled on this site.」) WordPress側で xmlrpc_enabled により無効化されている
403(WebサーバーやWAFのエラーページ) Webサーバー側で遮断されている。PHPは動いていない

なお、ブラウザーで xmlrpc.php を開いたときの「XML-RPC server accepts POST requests only.」という表示(ステータス405)は、POST以外のリクエストに対する通常の応答です。有効・無効の判断には使えません。

手順3:WordPress側で無効化する

xmlrpc_enabled フィルターで止まる範囲

よく紹介される add_filter( 'xmlrpc_enabled', '__return_false' ); は、公式のリファレンスにあるとおり、認証が必要なメソッドだけを止めるフィルターです。止めたメソッドを呼ぶと、ステータス405とともに「XML-RPC services are disabled on this site.」のエラーが返ります。

一方で、次のものはこのフィルターでは止まりません。

  • pingback.ping などの認証が不要なメソッド
  • system.listMethods、system.multicall などのシステムメソッド
  • xmlrpc.php へのリクエストそのもの(PHPは毎回起動する)

そのため、ピンバックのメソッドは xmlrpc_methods フィルターで別に外します。

設定するコード

テーマを変えても効くように、テーマの functions.php ではなく、wp-content/mu-plugins/disable-xmlrpc.php として置くことをおすすめします(mu-plugins ディレクトリが無ければ作成します)。

<?php
/**
 * Plugin Name: Disable XML-RPC
 * Description: XML-RPC の認証が必要なメソッドとピンバックを止め、関連するヘッダーとリンクを出さない。
 */

// 認証が必要なメソッド(投稿・ログインなど)を止める
add_filter( 'xmlrpc_enabled', '__return_false' );

// ピンバックのメソッドを外す(認証が不要なため xmlrpc_enabled では止まらない)
add_filter(
	'xmlrpc_methods',
	function ( array $methods ): array {
		unset( $methods['pingback.ping'], $methods['pingback.extensions.getPingbacks'] );
		return $methods;
	}
);

// ページの応答ヘッダーから X-Pingback を外す
add_filter(
	'wp_headers',
	function ( array $headers ): array {
		unset( $headers['X-Pingback'] );
		return $headers;
	}
);

// <head> の RSD リンク(xmlrpc.php?rsd)を出さない
remove_action( 'wp_head', 'rsd_link' );

X-Pingback ヘッダーは、ピンバックを受け付ける個別の投稿ページで送られ、ピンバックの送り先(xmlrpc.php)を知らせます。メソッドを外したら、ヘッダーも出さないようにしておきます。

WordPress 7.1以降では、WP_ENVIRONMENT_TYPE が本番(production)以外の環境で、pingback.ping が自動的に外されます。本番サイトでは上記の設定が必要です。

手順4:Webサーバー側で遮断する

WordPress側の設定だけでは、xmlrpc.php へのリクエストのたびにPHPとWordPressが起動します。大量のアクセスを受けている場合は、Webサーバー側で遮断するとPHPまで届かず、負荷を下げられます。

Apache 2.4(.htaccess またはバーチャルホストの設定)

Apache 2.4では、アクセス制御に Require を使います。Order Deny,Allow と Deny from all はApache 2.2の書き方で、2.4では互換モジュール(mod_access_compat)が読み込まれている場合にしか動きません。

# xmlrpc.php へのアクセスをすべて拒否する
<Files "xmlrpc.php">
    Require all denied
</Files>
  • .htaccess に書く場合は、WordPressが書き換える # BEGIN WordPress から # END WordPress の範囲の外に書きます。範囲内に書くと、パーマリンクの保存時に消えます
  • .htaccess で Require を使うには、そのディレクトリで AllowOverride に AuthConfig(または All)が許可されている必要があります。許可されていないと500エラーになります。サーバーの設定を変えられる場合は、バーチャルホストの設定に書けば、AllowOverride の影響を受けません

書いたら、設定を確かめます。

# バーチャルホストの設定に書いた場合は、構文を確認してから再読み込み
sudo apachectl configtest
sudo systemctl reload apache2   # RHEL系は httpd

# 403 が返ること
curl -s -o /dev/null -w '%{http_code}\n' -X POST https://example.com/xmlrpc.php

Nginx

サーバーブロックに、xmlrpc.php だけに一致する location を追加します。location =(完全一致)は、PHPファイル全般を処理する location ~ \.php$ より優先されます。

location = /xmlrpc.php {
    deny all;
    access_log off;
    log_not_found off;
}
sudo nginx -t && sudo systemctl reload nginx

アクセスログを残さない設定にしていますが、攻撃の状況を見たい場合は access_log off; を外してください。

Jetpackを使っている場合

Jetpackは、WordPress.comのサーバーから xmlrpc.php にアクセスして通信します。Jetpackの公式サポートページでは、xmlrpc.php をすべての相手に対して遮断するとJetpackとの接続が動かなくなるとしたうえで、Jetpackのサーバーのアドレスだけを許可し、それ以外を拒否する方法を案内しています。Jetpackの設定に、XML-RPCを使わずREST APIだけで接続するよう切り替える項目はありません。

2026年10月時点で公式ページに掲載されている許可対象のアドレスは次のとおりです。変更されることがあるため、設定する前と定期的に、Jetpackの公式サポートページで最新の一覧を確認してください。

122.248.245.244/32
54.217.201.243/32
54.232.116.4/32
192.0.80.0/20
192.0.96.0/20
192.0.112.0/20
195.234.108.0/22
192.0.64.0/18

この場合は、手順3の xmlrpc_enabled フィルターは入れず、公式の案内どおりWebサーバー側の許可リストで制限します。フィルターを入れる場合は、Jetpackの接続と使っている機能が動くことを確かめてから本番に反映してください。

Apache 2.4の例です。

<Files "xmlrpc.php">
    <RequireAny>
        Require ip 122.248.245.244/32 54.217.201.243/32 54.232.116.4/32
        Require ip 192.0.80.0/20 192.0.96.0/20 192.0.112.0/20
        Require ip 195.234.108.0/22 192.0.64.0/18
    </RequireAny>
</Files>

Nginxでは、許可したアクセスをPHPに渡す必要があるため、location の中にPHPの処理も書きます。PHP-FPMへの渡し方は、既存の location ~ \.php$ の中身に合わせてください(例は2026年10月時点のDebian/UbuntuのPHP 8.3の場合です)。

location = /xmlrpc.php {
    allow 122.248.245.244/32;
    allow 54.217.201.243/32;
    allow 54.232.116.4/32;
    allow 192.0.80.0/20;
    allow 192.0.96.0/20;
    allow 192.0.112.0/20;
    allow 195.234.108.0/22;
    allow 192.0.64.0/18;
    deny all;

    include snippets/fastcgi-php.conf;
    fastcgi_pass unix:/run/php/php8.3-fpm.sock;
}

CDNやロードバランサーの後ろにサーバーがある場合、Webサーバーから見える接続元はCDNやロードバランサーのアドレスになり、IPアドレスによる許可が正しく働きません。Apacheなら mod_remoteip、Nginxなら real_ip の設定で、本来の接続元を取り出してから制限してください。

設定後は、Jetpackの管理画面で接続の状態に問題が出ていないかを確認します。

無効化した後に起きること

  • XML-RPCで投稿していたアプリや外部ツールは使えなくなります。REST APIに対応したツールであれば、アプリケーションパスワードで認証する方法に切り替えられます
  • 他サイトからのピンバックは届かなくなります。WordPress本体の「設定」→「ディスカッション」にあるピンバック・トラックバックの受け付けの設定も、あわせて見直してください
  • 管理画面からのログインは影響を受けません。ログイン画面への総当たり対策は別に必要です(WordPressのブルートフォース攻撃対策)

まとめ

  • 止める前に、アクセスログと xmlrpc_call の記録で、XML-RPCを使っているものがないかを確認する
  • xmlrpc_enabled フィルターが止めるのは認証が必要なメソッドだけ。止めるとステータス405が返る。ピンバックは xmlrpc_methods で別に外す
  • 負荷まで減らすには、Apache 2.4の Require all denied やNginxの deny all でPHPに届く前に遮断する
  • Jetpackを使う場合は、公式ページのアドレスだけを許可し、それ以外を拒否する。一覧は変わることがあるため定期的に確認する
  • 確認は、存在しないユーザーで wp.getUsersBlogs を呼び、200・405・403のどれが返るかで判断する

関連記事:

お気軽にご相談ください

お見積りへ お問い合わせへ
▲