2026年8月25日
2026年8月25日
WordPressのXML-RPC攻撃を防ぐセキュリティ対策
はじめに
「WordPressサーバーへのリクエストが異常に多くサーバー負荷が高い」「アクセスログにxmlrpc.phpへの大量アクセスが記録されている」「WordPressへの不正ログイン試行をブロックしたい」——XML-RPC攻撃はWordPressサイトへの最も一般的な攻撃経路の一つです。
症状・原因
xmlrpc.phpはJetpackやモバイルアプリの接続に使用されますが、system.multicallメソッドを悪用すると1リクエストで数百回のログイン試行ができます。使用していない場合は完全に無効化することを推奨します。
解決手順
ステップ1:xmlrpc.phpをWordPressのフックで無効化する
// functions.php: XML-RPCを完全に無効化
// (Jetpack・WP モバイルアプリを使用していない場合)
// XML-RPCを無効化
add_filter( 'xmlrpc_enabled', '__return_false' );
// XML-RPCのメソッドリストを空にする(さらに強固)
add_filter( 'xmlrpc_methods', function(): array {
return [];
} );
// ピンバック機能も無効化(DDoS増幅攻撃に悪用される)
add_filter( 'xmlrpc_methods', function( array $methods ): array {
unset( $methods['pingback.ping'] );
unset( $methods['pingback.extensions.getPingbacks'] );
return $methods;
} );
// ピンバックを送受信とも無効化
add_action( 'pre_ping', function( array &$links ): void {
$links = [];
} );
add_filter( 'pings_open', '__return_false' );
ステップ2:.htaccessでxmlrpc.phpへのアクセスをブロックする
# .htaccess: xmlrpc.php への全アクセスをブロック
# (Jetpack を使用している場合は Automattic の IP のみ許可)
# 方法1: 全ブロック(Jetpack未使用の場合)
<Files xmlrpc.php>
Order Deny,Allow
Deny from all
</Files>
# 方法2: 特定IPのみ許可(Jetpack使用の場合)
<Files xmlrpc.php>
Order Deny,Allow
Deny from all
# Automattic / Jetpack のIPレンジ(要最新確認)
Allow from 192.0.64.0/18
Allow from 198.181.116.0/22
</Files>
# 方法3: mod_rewrite でブロック(RewriteRule使用)
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteRule ^xmlrpc\.php$ - [F,L]
</IfModule>
ステップ3:Nginxでブロックする
# /etc/nginx/conf.d/wordpress.conf または server ブロック内
server {
# xmlrpc.php への全アクセスを403で拒否
location = /xmlrpc.php {
deny all;
access_log off;
log_not_found off;
return 403;
}
# wp-login.php へのブルートフォース対策(レート制限)
location = /wp-login.php {
# 1分間に10リクエストまで
limit_req zone=login burst=5 nodelay;
include fastcgi_params;
fastcgi_pass unix:/var/run/php/php8.2-fpm.sock;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
}
}
# http コンテキストでレート制限ゾーンを定義
http {
# IPアドレスごとに毎分10リクエストまで
limit_req_zone $binary_remote_addr zone=login:10m rate=10r/m;
limit_req_zone $binary_remote_addr zone=xmlrpc:10m rate=1r/m;
}
ステップ4:ログイン試行回数を制限する
// functions.php: ログイン失敗時にIPをロックアウト
// (Limit Login Attempts Reloaded プラグインの代替)
add_filter( 'authenticate', function( $user, string $username, string $password ) {
if ( empty( $username ) && empty( $password ) ) {
return $user;
}
$ip = $_SERVER['REMOTE_ADDR'] ?? '';
$cache_key = 'login_attempts_' . md5( $ip );
$attempts = (int) get_transient( $cache_key );
$max = 5; // 最大試行回数
$lockout = 15 * MINUTE_IN_SECONDS; // ロックアウト時間
if ( $attempts >= $max ) {
return new WP_Error(
'too_many_retries',
sprintf(
'ログイン試行回数が多すぎます。%d分後に再試行してください。',
ceil( $lockout / 60 )
)
);
}
return $user;
}, 20, 3 );
// ログイン失敗時に試行回数を記録
add_action( 'wp_login_failed', function( string $username ): void {
$ip = $_SERVER['REMOTE_ADDR'] ?? '';
$cache_key = 'login_attempts_' . md5( $ip );
$attempts = (int) get_transient( $cache_key );
set_transient( $cache_key, $attempts + 1, 15 * MINUTE_IN_SECONDS );
// 不審なIPをログに記録
if ( $attempts >= 3 ) {
error_log( sprintf(
'Suspicious login attempt: IP=%s Username=%s Attempts=%d',
$ip,
sanitize_user( $username ),
$attempts + 1
) );
}
} );
// ログイン成功時にリセット
add_action( 'wp_login', function( string $user_login ): void {
$ip = $_SERVER['REMOTE_ADDR'] ?? '';
$cache_key = 'login_attempts_' . md5( $ip );
delete_transient( $cache_key );
} );
ステップ5:攻撃IPをCloudflareやfail2banでブロックする
# fail2ban: WordPress ログイン失敗をブロック
# /etc/fail2ban/filter.d/wordpress.conf
# [Definition]
# failregex = ^<HOST> .* "POST /wp-login.php
# ^<HOST> .* "POST /xmlrpc.php
# ignoreregex =
# /etc/fail2ban/jail.local
# [wordpress]
# enabled = true
# port = http,https
# filter = wordpress
# logpath = /var/log/nginx/access.log
# maxretry = 5
# bantime = 3600
# findtime = 600
sudo systemctl restart fail2ban
sudo fail2ban-client status wordpress
# アクセスログからXML-RPC攻撃IPを確認
grep "xmlrpc.php" /var/log/nginx/access.log | \
awk '{print $1}' | sort | uniq -c | sort -rn | head -20
# 特定IPを手動ブロック
sudo fail2ban-client set wordpress banip 203.0.113.0
// CloudFlare Workers または Cloudflare Rules で xmlrpc.php をブロック
// (Cloudflare ダッシュボード → セキュリティ → WAF → カスタムルール)
// 条件: URI パス = /xmlrpc.php
// アクション: ブロック
// WordPress で攻撃者IPをブラックリスト化
function block_malicious_ips(): void {
$blocked_ips = get_option( 'blocked_ips', [] );
$client_ip = $_SERVER['REMOTE_ADDR'] ?? '';
if ( in_array( $client_ip, $blocked_ips, true ) ) {
status_header( 403 );
exit( 'Access denied.' );
}
}
add_action( 'init', 'block_malicious_ips', 1 );
注意事項
- JetpackプラグインはXML-RPCを使用します。Jetpackを使用している場合は完全ブロックではなくAutomatticのIPのみ許可するホワイトリスト方式を採用してください。
wp_login_failedフックでのIPブロックは、同一NAT配下のユーザーをまとめてブロックする可能性があります。クラウドサービスや企業ネットワークのIPブロックには注意が必要です。- サーバーレベル(
.htaccess/Nginx)でブロックするほうがWordPressのPHP実行前に処理されるため、サーバー負荷の観点で効果的です。
まとめ
XML-RPC攻撃対策は「xmlrpc_enabledフィルターで無効化→.htaccessので全アクセスブロック→Nginxのlimit_reqでwp-login.phpにレート制限→authenticateフックでIPロックアウト→fail2banとCloudflare WAFで多層防御」の流れで整備します。関連記事:WordPressにセキュリティヘッダーを設定する方法、WordPressのwp-config.phpを安全に設定する方法。