WordPressのルートにあるxmlrpc.phpは、外部アプリからの投稿や他サイトからのピンバックを受け付ける窓口です。攻撃の入口として名前が挙がりやすく、「無効化しましょう」と勧める記事も大量にあります。ただ、そこで定番として紹介されるadd_filter( 'xmlrpc_enabled', '__return_false' );は、WordPressコアのコメント自身が「名前に反して、XML-RPCを完全に無効化するものではない」と書いている設定です。この記事では、現行のWordPress 7.1.3を手元で動かし、xmlrpc.phpが何に応答し、どの手段でどこまで止まるのかを実測で確かめました。PHP本体のXML-RPC拡張(php-xmlrpc)との関係、REST APIへの移行手順もあわせて整理します。
まとめ:xmlrpc.phpの扱いを決める判断軸
自社サイトがどれに当てはまるかで、打つべき手が変わります。
- 外部連携を一切使っていない…WebサーバーかWAFで
/xmlrpc.phpへのリクエストごと遮断します。PHPまで届かないので、認証系もピンバックも同時に止まります。 - ピンバックだけ止めたい…
xmlrpc_methodsフィルタでpingback.pingを外します。xmlrpc_enabledではピンバックは止まりません(7.1.3で実測)。 - 外部投稿を続けたい…REST APIへ移し、認証をアプリケーションパスワードに切り替えます。XML-RPCを残す場合も、アプリケーションパスワードなら主パスワードを外部ツールに渡さずに済みます。
- レンタルサーバーの「国外アクセス制限」に任せている…主に国外IPからの接続を制限する機能ですが、国内IPの一部も対象にするサービスや、Jetpackなどを除外するサービスがあります。すべての接続を遮断する機能ではないため、全面遮断の代わりにはなりません。
- 「php-xmlrpc」を入れるべきか迷っている…WordPressもJetpackもPHPのxmlrpc拡張を使いません。PHP 8.0でバンドルから外れていても、xmlrpc.phpの動作には関係しません。
XML-RPC以外のログイン画面・プラグイン・権限・サーバー設定まで含めた対策の全体像は、WordPressセキュリティ対策:攻撃面ごとの設定とWP-CLIでの確認手順【2026年10月・7.1.3対応】で扱っています。
xmlrpc.phpが受け付けているものとXML-RPC仕様の位置づけ
XML-RPCの仕様と、WordPressで今も保守されている理由
XML-RPCは、HTTPのPOSTでXMLを送り、サーバー側の手続きを呼び出す仕組みです。仕様書はxmlrpc.comに置かれ、Dave Winer名義で1999年6月15日に公開、ページ上の更新記録は2003年6月30日で止まっています。リクエストはContent-Type: text/xmlで送り、本文は<methodCall>1つだけという簡素な構造です。
WordPress VIPのドキュメントは「The XML-RPC endpoint is enabled on new WordPress sites by default since the release of WordPress version 3.5.」と書いています。3.5より前は管理画面に有効・無効のスイッチがありましたが、現在は設定画面から切り替える手段がありません。標準状態では常に開いている、と考えてください。
古い仕組みなのでそのうち消える、という見方もありますが、廃止や非推奨を告知した公式アナウンスは出ていません。2026年9月17日公開のWordPress 7.1.1では、XML-RPC経由でcustomize_changesetを公開しedit_cssの権限チェックを迂回できる問題が修正されました。現役の保守対象です。現行版は2026年10月6日公開の7.1.3(セキュリティ修正7件)で、マイナー版の自動更新を止めていないかも合わせて確認してください。
登録メソッド77個の内訳と認証の要否
7.1.3のソースでwp_xmlrpc_serverのコンストラクタが登録するメソッドは77個です。これに親クラスIXR_Serverのsystem.getCapabilities・system.listMethods・system.multicallが加わり、手元の7.1.3にsystem.listMethodsを投げると80個が返りました。
| 名前空間 | メソッド数 | 用途 | 認証 |
|---|---|---|---|
| wp.* | 50 | 投稿・タクソノミー・ユーザー操作 | 必要 |
| metaWeblog.* | 8 | MetaWeblog API互換の投稿 | 必要 |
| mt.* | 8 | Movable Type API互換 | 3個は不要 |
| blogger.* | 7 | Blogger API互換(旧式) | 必要 |
| pingback.* | 2 | ピンバックの受信・一覧 | 不要 |
| demo.* | 2 | 疎通確認用 | 不要 |
認証なしで呼べるのは、pingback.*とdemo.*の4個に、mt.supportedMethods・mt.supportedTextFilters・mt.getTrackbackPingsを足した7個です。この7個に加え、親クラスが提供するsystem.getCapabilities・system.listMethods・system.multicallも、xmlrpc_enabledをfalseにするだけでは止まりません。ただし、multicall内で呼び出す認証必須メソッドは停止対象です。RPCという呼び出し方式の考え方はgRPCとは?UDPは使うのかをTCP・HTTP/3で実測|仕組み・RESTとの違い・実装例でも扱っています。
xmlrpc.phpが有効かを確かめる3つの応答
GETで返る「XML-RPC server accepts POST requests only.」の意味
ブラウザで/xmlrpc.phpを開くと、XML-RPC server accepts POST requests only.という1行だけが表示されます。この応答はGETがXML-RPCの処理まで届いたことを示しますが、POSTでのメソッド実行や認証の正常動作までは保証しません。手元の7.1.3で確かめると、応答は次のとおりでした。
$ curl -si http://127.0.0.1:9431/xmlrpc.php
HTTP/1.1 405 Method Not Allowed
Allow: POST
Content-Type: text/plain
...
XML-RPC server accepts POST requests only.
この文言はIXR_Server::serve()が出しています。POST以外のリクエストにはstatus_header( 405 )とAllow: POSTを付けて終了する実装です。逆に403や404が返っても、遮断されたのはGETだけかもしれません。攻撃に使われるのはPOSTなので、判定は次のPOSTで行います。
curl -s -X POST -H "Content-Type: text/xml" \
--data '<?xml version="1.0"?><methodCall><methodName>system.listMethods</methodName></methodCall>' \
https://example.com/xmlrpc.php | grep -o "<string>" | wc -l
標準の7.1.3なら80前後の数字が返ります。0という件数だけではPOSTの遮断を判定できません。リダイレクトや空の応答、通信失敗でも0になるため、HTTPステータス・応答本文・curlの終了コードを確認し、設定した遮断ルールがPOSTにも適用されていることを確かめてください。
xmlrpc.php?rsdとEditURIによるAPI接続先の通知
?rsdを付けて開くと、RSD(Really Simple Discovery)というXMLが返ります。7.1.3の出力には、WordPress・Movable Type・MetaWeblog・BloggerのAPIがすべて同じxmlrpc.phpを指す形で並び、最後にREST APIの/wp-json/もWP-APIとして載っていました。外部の投稿ツールは、この一覧を見て使えるAPIを判断します。
このRSDの所在は、コアのrsd_link()がwp_head経由で全ページの<head>に<link rel="EditURI" type="application/rsd+xml" ...>として出力しています。攻撃側はトップページを1回取得するだけでエンドポイントを把握できるということです。remove_action( 'wp_head', 'rsd_link' );で消せますが、xmlrpc.phpの場所は固定なので、隠しても守りにはなりません。
X-Pingbackヘッダで分かるピンバックの受付状態
ピンバックを受け付けている投稿には、レスポンスヘッダにX-Pingbackが付きます。
curl -sI https://example.com/your-post/ | grep -i x-pingback
X-Pingback: https://example.com/xmlrpc.php
WordPress 4.4以降、このヘッダはピンを受け付けている個別投稿にだけ付きます。7.1.3の実測でも、トップページには無く、初期投稿(?p=1)には付いていました。wp_headersフィルタやプラグインでヘッダだけ消している環境もあるため、行が返らないことは「ピンバックが止まっている」証明になりません。
xmlrpc_enabledフィルタが止めない範囲
xmlrpc_enabledの公式仕様と認証メソッドへの適用範囲
xmlrpc_enabledはWordPress 3.5で導入されたフィルタで、多くの解説記事が「これでxmlrpc.phpを無効化できる」と紹介しています。しかし公式コードリファレンスで読めるwp_xmlrpc_server::set_is_enabled()のコメントは、その理解をはっきり否定しています。
Contrary to the way it's named, this filter does not control whether XML-RPC is *fully* enabled, rather, it only controls whether XML-RPC methods requiring authentication - such as for publishing purposes - are enabled. Further, the filter does not control whether pingbacks or other custom endpoints that don't require authentication are enabled.
名前に反してXML-RPC全体を制御するものではなく、投稿のように認証が要るメソッドの可否だけを決める、ピンバックなど認証不要のエンドポイントは対象外、という内容です。実装を追うと理由が分かります。このフラグを見ているのはlogin()と、エラー応答のHTTPステータスを決めるerror()だけで、pingback_ping()には判定が一度も出てきません。
WordPress 7.1.3でのxmlrpc_enabled適用前後の応答比較
@wp-playground/cliで動かしたWordPress 7.1.3(PHP 8.3)に、フィルタを入れない状態と__return_falseを入れた状態でリクエストを投げ比べました。
| リクエスト | フィルタなし | xmlrpc_enabled=false |
|---|---|---|
| system.listMethods | 80個 | 80個(変わらない) |
| demo.sayHello | Hello! | Hello! |
| mt.supportedMethods | 一覧を返す | 一覧を返す |
| pingback.ping | 検証処理に入る | 検証処理に入る |
| wp.getUsersBlogs(正しいパスワード) | サイト情報を返す | HTTP 405・faultCode 405 |
止まったのは認証が要るwp.getUsersBlogsだけで、応答はXML-RPC services are disabled on this site.でした。HTTPステータスも405になるため、クライアント側では通信エラーとして扱われることがあります。一方、pingback.pingは存在しないメソッドとして弾かれず、ピンバックの検証処理に入りました(今回は架空のリンク元を指定したため、URLの検証段階でfaultCode 0が返っています)。後述するDDoSの踏み台は、まさにこの経路です。攻撃を止めるつもりでこのフィルタだけを入れると、実際に使われる穴は開いたままになります。
比較のためxmlrpc_methodsでpingback.pingとpingback.extensions.getPingbacksを外すと、system.listMethodsは78個に減り、pingback.pingは-32601(requested method pingback.ping does not exist.)で拒否されました。手段ごとの守備範囲をまとめます。
| 手段 | 認証メソッド | ピンバック | PHP実行 |
|---|---|---|---|
| xmlrpc_enabled を false | 止まる | 止まらない | される |
| xmlrpc_methods でメソッド削除 | 選択可 | 選択可 | される |
| 投稿のピン受付を閉じる | 止まらない | その投稿は受付停止 | される |
| .htaccess・nginx で遮断 | 止まる | 止まる | されない |
| WAF・エッジで遮断 | 止まる | 止まる | 到達しない |
PHPの実行有無を分けたのは、リクエストがPHPまで届くかどうかで負荷が変わるためです。ピンバックの仕組みと現在の位置づけはトラックバックとは?仕組み・ピンバックとの違いと現在の状況で整理しています。
xmlrpc.phpを狙う攻撃と、コアに入っている歯止め
pingback.pingを踏み台にするDDoSの経路
攻撃者は、無関係なWordPressサイトへ「この記事からあなたの記事へリンクした」というピンバックを送ります。受け取った側は、リンク元として申告されたURLへ自分から取得に行きます。この取得先を攻撃対象に指定すると、多数のWordPressサイトが一斉に対象へアクセスする構図ができあがります。
7.1.3のpingback_ping()は、この外向き取得をwp_safe_remote_get()で行い、タイムアウト10秒、リダイレクト追従0回、レスポンス上限153,600バイト(150KB)という制約を付けています。wp_safe_remote_get()はループバック・RFC 1918のプライベートアドレスに加え、クラウドのメタデータサービスが使う169.254.0.0/16も宛先から外すため、内部ネットワークの探索には使いにくい設計です。User-Agentにはverifying pingback from <送信元IP>が入り、X-Pingback-Forwarded-Forヘッダにも送信元IPが載ります。攻撃対象側でこれらのヘッダを記録していれば、踏み台が認識した接続元を追う手掛かりになりますが、プロキシ経由もあるため攻撃元の確定情報としては扱えません。
見落とされがちなのが、受け取る側自身の負荷です。コアは外向き取得の直前にsleep( 1 )を挟んでいます。リンク元の公開処理が終わる前に取りに行かないための待機で、この処理まで到達したピンバックはPHPのワーカーを最低1秒占有します。URLや対象投稿の検証などで先に拒否されるリクエストは、この待機に到達しません。同時に大量に送られると、踏み台として外へ迷惑をかける前に、自サイトのPHPプロセスが足りなくなります。初期値のdefault_ping_statusはopenなので、何もしていなければ新規投稿はすべて受け付ける側です。
system.multicallによる総当たりと認証失敗フラグ
もう1つの定番がログイン試行の増幅です。system.multicallは複数の呼び出しを1リクエストにまとめる仕組みで、2015年にSucuriが報告した手口は、1回のHTTPリクエストに数百個のパスワードを詰め込むものでした。
現在のコアには歯止めがあります。wp_xmlrpc_server::login()は認証に1回失敗するとauth_failedフラグを立て、同じリクエスト内の以降の認証をlogin_preventedとして扱います。7.1.3に3件まとめたmulticallを送って確かめました。
| multicallの中身(順番どおり) | 1件目 | 2件目 | 3件目 |
|---|---|---|---|
| 誤 → 誤 → 正しいパスワード | 403 | 403 | 403 |
| 正 → 誤 → 正しいパスワード | 成功 | 403 | 403 |
1度失敗した後は、正しいパスワードでもIncorrect username or password.(faultCode 403)が返りました。同じリクエスト内では、最初の失敗以降の認証がすべて拒否されます。失敗より前の呼び出しは通常どおり認証されるので、1リクエストで試せるのは「最初に外れるまで」です。WordPress VIPのドキュメントも「The XML-RPC server in WordPress Core code prevents more than one failed authentication attempt per a system.multicall request.」と明記しています。ただし、攻撃側がリクエストの本数を増やせば総当たり自体は続けられます。止める対象は「1リクエストあたりの試行数」から「リクエストの頻度」に移った、と考えるのが正確です。
リクエスト全体の大きさに対する制限は緩めです。xmlrpc_element_limitの初期値は30,000で、判定は本文中の「<」の数が上限の2倍を超えたら拒否する式です。終了タグも数に入るため、開閉が対になる通常の構造なら約3万要素が目安になります。頻度の制限には、WordPress VIPが標準として公開している「/xmlrpc.php宛てに30秒で10リクエストを超えたIPを1時間ブロック」という値が参考になります。XML-RPC以外にも、未認証で任意コードが実行される深刻な脆弱性が出ています(wp2shellとは?WordPress未認証RCE(CVE-2026-63030・CVE-2026-60137)の仕組みと影響バージョン・確認手順【2026年10月】)。xmlrpc.phpを閉じたら対策完了、とは考えないでください。
目的別に選ぶxmlrpc.phpの止め方
Webサーバー設定によるXML-RPCの全面遮断
外部連携を使っていないなら、これが最も確実です。ApacheのVirtualHostまたは.htaccessに書く場合は次のとおりです。
<Files "xmlrpc.php">
Require all denied
</Files>
Apache 2.2時代のOrder deny,allowを載せた解説が今も多く残っていますが、2.4系でmod_access_compatが読み込まれていない場合、旧ディレクティブを.htaccessに書くと500エラー、本体設定に書くと設定検証や起動・再読み込みのエラーになります。nginxではserverブロックに次を加えます。サブディレクトリに設置している場合は実際のURLパスに合わせ、同じlocationの設定が既にあれば統合してください。
location = /xmlrpc.php {
deny all;
}
ファイル自体を削除する方法は勧めません。コア更新でファイル一式が展開し直されるため、次の自動更新で復活します。コアファイルを直接書き換える対処も同じ理由で巻き戻ります。
xmlrpc_enabledによる認証メソッドの停止
ピンバックは残したいが外部からの投稿は塞ぎたい、という場合に使います。テーマを変えても設定が残るよう、functions.phpではなくサイト固有プラグイン(wp-content/mu-plugins/に置くファイル)に書くことを勧めます。
<?php
// Plugin Name: Disable XML-RPC Auth Methods
add_filter( 'xmlrpc_enabled', '__return_false' );
xmlrpc_methodsによるピンバックメソッドの削除
投稿ツールとの連携を残したまま踏み台化を防ぐなら、メソッド一覧から該当分を取り除きます。上の実測で78個に減ったのはこのコードです。
<?php
// Plugin Name: Remove Pingback XML-RPC Methods
add_filter( 'xmlrpc_methods', function ( $methods ) {
unset( $methods['pingback.ping'] );
unset( $methods['pingback.extensions.getPingbacks'] );
return $methods;
} );
受付そのものを閉じたい場合は、管理画面の「設定」→「ディスカッション」で「新しい投稿に対し他のブログからの通知 (ピンバック・トラックバック) を受け付ける」のチェックを外します。変わるのは新規投稿の初期値だけなので、公開済みの記事は投稿一覧の一括編集で変更してください。
レンタルサーバーの国外アクセス制限で止まる範囲
国内の主要レンタルサーバーは、xmlrpc.phpへの国外からの接続を初期状態で制限しています。自分で設定した覚えがなくても、すでに一部は止まっている可能性があります。
| サーバー | 機能名 | 初期状態 |
|---|---|---|
| エックスサーバー | 国外アクセス制限(XML-RPC API) | ON |
| ConoHa WING | 海外アクセス制限(XML-RPC-API) | ON |
| ロリポップ | 海外アタックガード | 2017年10月23日以降の新規設定ドメインは自動有効 |
| さくらのレンタルサーバ | 国外IPアドレスフィルター(APIの制限) | フィルターは有効 |
根拠は各社の公式マニュアルです。エックスサーバーは「本機能は初期状態で『ON(有効)』」と書き、制限の対象を「国外及び一部の国内ホスティングサービス環境のアドレス」、Jetpackからのアクセスは対象外としています。ConoHa WINGは「デフォルトで全項目がON」、ロリポップはガード対象に/xmlrpc.phpを挙げています。さくらはフィルター自体が初期有効で、「APIの制限」の対象にxmlrpc.phpが入っていますが、項目ごとの初期値はコントロールパネルで確かめてください。
国外アクセス制限は、XML-RPCの全面遮断の代わりにはなりません。主に国外IPからの接続を制限しますが、一部の国内IPも対象になる場合や、特定サービスを許可する例外があります。制限対象外の接続元からはWordPressまでリクエストが届きます。外部連携を使っていないなら、前述のWebサーバー設定で/xmlrpc.php自体を閉じてください。逆に、国外のサービスからXML-RPCで投稿していて急に失敗するようになった場合は、接続元IPが制限対象に含まれていないか確認してください。
PHPのXML-RPC拡張(php-xmlrpc)とWordPressの関係
PHP 8.0でバンドルから外れたext/xmlrpc
「xmlrpc php」で検索すると、WordPressのxmlrpc.phpと並んで、PHPのマニュアルにあるXML-RPC関数(xmlrpc_encode_request()など)が出てきます。こちらはPHP本体の拡張モジュールext/xmlrpcで、WordPressのxmlrpc.phpとは別物です。
この拡張はPHP 8.0でPHP本体から外れました。php-srcのUPGRADINGは「The xmlrpc extension has been unbundled and moved to PECL.」と書いています。PECLのパッケージ説明は理由を「the underlying libxmlrpc has obviously been abandoned」とし、利用そのものの見直しを勧めています。PECLの最新リリースは2021年12月4日の1.0.0RC3で、状態はbetaのままです。PHPマニュアルの日本語版は今も「実験的」の警告とビルド時の--with-xmlrpcしか書いておらず、移管の事実は読み取れません。PHP 8系でxmlrpc_encode_request()が未定義になるのはこのためです。
WordPressはこの拡張を使いません。XML-RPCの解析は同梱のIXRライブラリが受け持ち、class-IXR-message.phpが使うのは標準のXML拡張のxml_parser_create()です。Jetpackの公式サポートも「Jetpack includes its own implementation of XML-RPC that does not rely on this PHP extension.」と明記しています。サーバーにphp-xmlrpcパッケージを入れる必要はなく、入っていないことがxmlrpc.phpを止める理由にもなりません。
PHPからXML-RPCを呼ぶならphpxmlrpcライブラリ
PHPでXML-RPCのクライアントやサーバーを書くなら、拡張ではなくComposerで入るpure PHPのライブラリphpxmlrpc/phpxmlrpcを使います。2026年10月26日時点の最新は4.11.5(2025年11月11日)で、必須拡張はext-xmlとext-ctypeですが、以下のHTTPS通信例にはext-curlも必要です。xmlrpc拡張の入っていないPHP 8.5.8(検証用のクライアント環境)から、7.1.3のxmlrpc.phpへ次のコードで接続できました。Webサーバー側のPHPは、2026年10月21日に緊急のセキュリティ修正が出た8.5.12・8.4.27などへ更新しておいてください。
<?php
// composer require phpxmlrpc/phpxmlrpc:^4.11
require __DIR__ . '/vendor/autoload.php';
use PhpXmlRpc\Client;
use PhpXmlRpc\Encoder;
use PhpXmlRpc\Request;
use PhpXmlRpc\Value;
$client = new Client( 'https://example.com/xmlrpc.php' );
// 認証不要のメソッドで疎通を確かめる
$resp = $client->send( new Request( 'demo.sayHello' ) );
echo $resp->faultCode() ? 'fault: ' . $resp->faultString() : ( new Encoder() )->decode( $resp->value() ), "\n";
// 認証が必要なメソッド(アプリケーションパスワードも使える)
$resp = $client->send( new Request( 'wp.getUsersBlogs', array(
new Value( 'editor', 'string' ),
new Value( 'xxxx xxxx xxxx xxxx xxxx xxxx', 'string' ),
) ) );
if ( $resp->faultCode() ) {
echo 'fault ', $resp->faultCode(), ': ', $resp->faultString(), "\n";
} else {
foreach ( ( new Encoder() )->decode( $resp->value() ) as $blog ) {
echo $blog['blogName'], ' ', $blog['xmlrpc'], "\n";
}
}
example.com・ユーザー名・パスワードを実環境の値に置き換え、対象メソッドが有効なら、Hello!とサイト名・エンドポイントが返ります。サイト側でxmlrpc_enabledをfalseにすると、2つ目の呼び出しはHTTP 405を受けてfault 5: Didn't receive 200 OK from remote serverになりました。ライブラリはHTTPの405を通信エラーとして扱い、WordPressが返したfaultの本文までは読みません。連携が急に止まったときにこの表示が出たら、サイト側でフィルタが入っていないかを疑ってください。
XML-RPCを止めた後の代替:REST APIとアプリケーションパスワード
アプリケーションパスワードの適用範囲とHTTPS要件
WordPress 5.6でコアに入ったアプリケーションパスワードは、ログインパスワードを渡さずに外部ツールへAPIアクセスを許す仕組みです。プロフィール画面で用途ごとに発行でき、生成される文字列は24文字。不要になればその分だけ失効させられます。
コアのwp_authenticate_application_password()には「By default, Application Passwords is available for the REST API and XML-RPC.」とあり、公式の管理者向け文書も認証先にXML-RPCを挙げています。上のphpxmlrpcのコードも、発行したアプリケーションパスワードでwp.getUsersBlogsが通りました。ただし権限は発行したユーザーのままなので、被害範囲を絞るには必要最小限の権限を持つ連携専用ユーザーで発行します。REST API専用にしたいときは、application_password_is_api_requestフィルタでXML-RPCからの利用を外せます。
前提条件が1つあります。wp_is_application_passwords_supported()の実装はis_ssl() || 'local' === wp_get_environment_type()で、標準で使えるのはHTTPSのサイトか環境種別がlocalのサイトだけです。手元のHTTP・production設定のPlaygroundでは、同じパスワードが403で拒否され、利用可否のフィルタをtrueにすると通りました。プロフィール画面に発行欄が出ないときは、まずSSLの状態を確認してください。
REST APIによる投稿作成と認証の実装例
XML-RPCのmetaWeblog.newPostに当たるのは、REST APIのPOST /wp-json/wp/v2/postsです。公式ハンドブックが示す標準の認証は、HTTPS上のBasic認証でユーザー名とアプリケーションパスワードを渡す方法です。
curl -X POST "https://example.com/wp-json/wp/v2/posts" \
-u "editor:abcd EFGH ijkl MNOP qrst UVWX" \
-H "Content-Type: application/json" \
-d '{"title":"API経由の下書き","content":"本文","status":"draft"}'
Pythonなら、WordPress専用ライブラリを使わずRequestsで呼べます。長く使われてきたpython-wordpress-xmlrpcはPyPI上の最新が2.3(2014年6月29日)のまま、READMEの動作確認基準もWordPress 3.5で止まっており、新規実装で選ぶ理由は残っていません。
import requests
from requests.auth import HTTPBasicAuth
res = requests.post(
"https://example.com/wp-json/wp/v2/posts",
auth=HTTPBasicAuth("editor", "abcd EFGH ijkl MNOP qrst UVWX"),
json={"title": "API経由の下書き", "content": "本文", "status": "draft"},
timeout=30,
)
res.raise_for_status()
print(res.json()["id"], res.json()["link"])
2つの方式の違いは次のとおりです。
| 観点 | XML-RPC | REST API |
|---|---|---|
| エンドポイント | /xmlrpc.php の1本 | リソースごとのURL |
| データ形式 | XML | JSON |
| HTTPメソッド | POSTのみ(GETは405) | GET・POST・PUT・DELETE |
| 認証 | パスワード/アプリPW | アプリPW・Cookie+nonce |
| 拡張 | xmlrpc_methods フィルタ | register_rest_route |
| 仕様の出自 | xmlrpc.com(2003年で更新停止) | WordPressコアが定義 |
OAuthはコア標準ではなくプラグインでの追加になります。基幹システムや外部サービスとの投稿連携をREST APIで作り直す場合は、API開発・システム連携として設計から相談いただけます。REST側の設計思想や制約はRESTとは?REST APIの仕組みと6原則・SOAP/GraphQLとの違いを実装目線で解説にまとめています。
よくある質問
xmlrpc.phpは削除してしまって問題ありませんか?
削除しても次のコア更新で復活するため、対策になりません。WordPressは既定でマイナー版の自動更新が有効なので、気づかないうちに元に戻ります。Webサーバーかエッジで/xmlrpc.phpへのリクエストを拒否してください。
add_filter( 'xmlrpc_enabled', '__return_false' ); だけで攻撃は止まりますか?
止まりません。7.1.3の実測でも、このフィルタで拒否されたのは認証が要るメソッドだけで、pingback.pingとdemo.sayHelloは応答を続けました。ピンバックまで止めるにはxmlrpc_methodsでの削除か、エンドポイント自体の遮断が必要です。
Jetpackや公式モバイルアプリを使っていてもXML-RPCを無効化できますか?
Jetpackは公式サポートが「Jetpack needs this file to connect to your website.」と書いており、全面遮断すると接続が切れます。WordPress VIPが「Only allow requests from Jetpack」という設定を用意しているのはこのためです。一方、WordPress・JetpackのiOSアプリ26.8以降は、XML-RPCを無効にした自己ホスト型サイトでも、アプリケーションパスワードを使ってCPTベースの投稿画面を利用できます。この画面はBETA扱いで、オフライン編集には対応していません。機能の内訳はJetpackとは?WordPressプラグインの機能・料金・SEO設定と必要かの判断で確認できます。
php-xmlrpcを入れないとWordPressのXML-RPCは動きませんか?
動きます。WordPressは同梱のIXRライブラリと標準のXML拡張でXML-RPCを処理しており、PHP 8.0でPECLへ移ったext/xmlrpcには依存していません。Jetpackも独自実装です。
REST APIならXML-RPCより安全ですか?
方式を変えただけでは安全になりません。どちらもコアで保守され、アプリケーションパスワードが使え、権限は発行ユーザーに従います。また/wp-json/wp/v2/usersでは公開投稿の著者の表示名やスラッグなどを取得できるため、公開範囲の確認はREST側でも必要です。ログイン名そのもの(username)は権限が必要なeditコンテキストでしか返りませんが、スラッグは既定でログイン名から作られるため、一致していることがあります。