2026年5月20日
2026年5月20日
WordPressをCloudflare WAFで守る設定|カスタムルール・レート制限・マネージドルール
Cloudflare WAF は、Cloudflare を経由するリクエストをエッジ(Cloudflare 側)で調べ、条件に合うものをオリジンサーバーに届く前に止める仕組みです。サーバーに ModSecurity などを入れにくい共有サーバーでも、Cloudflare のダッシュボードから WordPress 向けの防御を足せます。
この記事では、プランごとに使える範囲を確認したうえで、WordPress でよく狙われる xmlrpc.php・wp-login.php・/wp-admin/ を守るカスタムルール、レート制限ルール、マネージドルールの設定と、Cloudflare を通したときにオリジンで訪問者の IP アドレスを正しく扱う方法を説明します。内容は2026年10月時点の Cloudflare の公式ドキュメント(developers.cloudflare.com)に基づいています。
前提: リクエストが Cloudflare を通っていること
WAF が働くのは、DNS レコードがプロキシ(オレンジの雲)になっていて、リクエストが Cloudflare を経由している場合だけです。次のコマンドで、応答に cf-ray ヘッダーが付くかを確認します。
curl -sI https://example.com/ | grep -iE "^cf-ray|^server"
# cf-ray: ... と server: cloudflare が出れば Cloudflare 経由
プランごとに使える範囲
WAF の機能はプランで上限が違います。主な違いは次のとおりです(2026年10月時点)。
| 項目 | Free | Pro | Business |
|---|---|---|---|
| カスタムルールの数 | 5 | 20 | 100 |
| カスタムルールで正規表現 | 不可 | 不可 | 可 |
| レート制限ルールの数 | 1 | 2 | 5 |
| レート制限の計測期間 | 10秒 | 最大1分 | 最大10分 |
| レート制限の対策時間 | 10秒 | 最大1時間 | 最大1日 |
| レート制限の条件に使える項目 | パス、検証済みボットか | ホスト、URI、パス、クエリなど | 上記に加えメソッド、送信元 IP、User-Agent など |
| Free Managed Ruleset | 可 | 可 | 可 |
| Cloudflare Managed Ruleset・OWASP Core Ruleset | 不可 | 可 | 可 |
Free プランでもカスタムルールは5つまで作れます。一方、WordPress 向けのルールを含む Cloudflare Managed Ruleset は Pro 以上です。
カスタムルールで WordPress の入口を守る
ダッシュボードでは、対象のドメインを開き、「Security rules」の画面で「Create rule」→「Custom rules」を選びます。ルール名を付け、「When incoming requests match」で条件、「Then take action」で動作を選んで「Deploy」で有効にします。条件は「Field」「Operator」「Value」を選んで組み立てるほか、「Edit expression」を選ぶと式(expression)を直接書けます。関数(starts_with() など)を使う条件は、式で書く必要があります。以下では、式の形で示します。
いきなり「Block」にせず、まず「Managed Challenge」で動かし、セキュリティイベントで何が引っかかっているかを確認してから「Block」に切り替えると、正規の利用を止めてしまう事故を防げます(「Log」動作は Enterprise プランのみ)。
ルール1: xmlrpc.php を止める
(http.request.uri.path eq "/xmlrpc.php")
動作: Block
XML-RPC は、古いリモート投稿の仕組みで、パスワードの総当たりに使われることがあります。ただし、Jetpack など XML-RPC を使うプラグインやアプリがあるので、使っていないことを確認してから止めてください。
ルール2: ログイン画面にチャレンジをかける
(http.request.uri.path eq "/wp-login.php")
動作: Managed Challenge
ログイン画面を開いた時点で Cloudflare の確認が入り、通過したブラウザーだけがログインフォームを使えます。ボットによる自動のログイン試行を減らせます。
ルール3: 管理画面を特定の IP アドレスに限る
固定の IP アドレスから管理する場合は、それ以外からの /wp-admin/ を止められます。203.0.113.10 は自分の IP アドレスに置き換えます。
(starts_with(http.request.uri.path, "/wp-admin/") and http.request.uri.path ne "/wp-admin/admin-ajax.php" and not ip.src in {203.0.113.10})
動作: Block
/wp-admin/admin-ajax.php は、フロント側の検索・フォーム・カートなどがログインしていない訪問者からも呼び出すため、除外しています。テーマやプラグインによっては /wp-admin/admin-post.php も訪問者向けのフォームで使われるので、問い合わせフォームなどが動くかを確認してください。
外出先や自宅のように IP アドレスが変わる環境から管理する場合、このルールでは自分も締め出されます。その場合は IP アドレスで止める代わりに、動作を「Managed Challenge」にするか、Cloudflare Access(Zero Trust)のような認証の仕組みを検討してください。
レート制限ルールでログインの試行回数を抑える
レート制限ルールは、同じ IP アドレスからのリクエスト数が決めた数を超えたときに、一定時間ブロックやチャレンジをかける仕組みです。「Security rules」で「Create rule」→「Rate limiting rules」から作ります。
Free プランの例です。Free では条件にパスしか使えず、計測期間と対策時間はともに10秒です。
| 項目 | 設定例 |
|---|---|
| 条件 | URI Path が /wp-login.php と等しい |
| 数える単位 | IP |
| しきい値 | 10秒間に5リクエスト |
| 動作 | Block(10秒間) |
Free プランではメソッド(POST)を条件にできないため、ログイン画面の表示(GET)も数に入ります。1回のログインで画面表示と送信の2リクエストになることを考えて、しきい値を決めてください。Pro 以上では計測期間を1分まで延ばせ、Business 以上では http.request.method eq "POST" を条件に加えられます。
REST API(/wp-json/)にもレート制限をかけたくなりますが、ブロックエディターや多くのプラグインが REST API を頻繁に使います。かける場合は、編集作業中に止まらないか確かめながら、しきい値を緩めに設定してください。
マネージドルールを有効にする
マネージドルールは、Cloudflare が用意し更新するルールの集まりです。
- Free Managed Ruleset: すべてのプランで使えます。影響の大きい既知の脆弱性に対する基本的なルールです。
- Cloudflare Managed Ruleset: Pro 以上で使えます。ルールには
wordpressなどのタグが付いており、タグ単位でまとめて動作を設定できます。 - OWASP Core Ruleset: Pro 以上で使えます。誤検知が出やすいので、感度を低めにして様子を見ながら使います。
マネージドルールで正規の操作(記事の保存、フォームの送信など)が止まった場合は、セキュリティイベントで該当のルールを確認し、そのルールだけを無効にするか例外を作ります。マネージドルール全体を止めないようにします。
API でカスタムルールを登録する(Rulesets API)
以前の WAF で使われていた Firewall Rules API と Filters API は、2025年6月15日でサポートが終了しました。現在のカスタムルールは Rulesets API で、http_request_firewall_custom フェーズのエントリーポイントのルールセットに登録します。/firewall/waf/packages や /rate_limits も以前の WAF・レート制限の API で、現在のマネージドルール・レート制限ルールは Rulesets API で扱います。
ZONE_ID="ゾーンID"
CLOUDFLARE_API_TOKEN="WAF を編集できる権限の API トークン"
# 1. カスタムルールのエントリーポイントのルールセットを取得する(id を控える)
curl "https://api.cloudflare.com/client/v4/zones/$ZONE_ID/rulesets/phases/http_request_firewall_custom/entrypoint" \
--header "Authorization: Bearer $CLOUDFLARE_API_TOKEN"
# 2. 取得したルールセットにルールを1つ追加する
RULESET_ID="手順1で控えた id"
curl "https://api.cloudflare.com/client/v4/zones/$ZONE_ID/rulesets/$RULESET_ID/rules" \
--request POST \
--header "Authorization: Bearer $CLOUDFLARE_API_TOKEN" \
--json '{
"description": "Block xmlrpc.php",
"expression": "(http.request.uri.path eq \"/xmlrpc.php\")",
"action": "block"
}'
手順1で 404 Not Found が返る場合は、まだカスタムルールが1つも無く、エントリーポイントのルールセットがありません。その場合は、ダッシュボードで最初のルールを作るか、Rulesets API の「ルールセットの作成」でエントリーポイントを作ってから追加します。
オリジンで訪問者の IP アドレスを正しく扱う
Cloudflare を通すと、オリジンサーバーに接続してくるのは Cloudflare のサーバーなので、PHP の $_SERVER['REMOTE_ADDR'] は Cloudflare の IP アドレスになります。元の訪問者の IP アドレスは CF-Connecting-IP ヘッダーで届きます。
ただし、このヘッダーを無条件に信じて REMOTE_ADDR を書き換えてはいけません。オリジンの IP アドレスが知られていれば、Cloudflare を通さずに直接アクセスし、好きな値の CF-Connecting-IP を付けて送れます。ログイン制限やメンテナンスモードの IP 許可がこの値を使っていると、なりすましで回避されます。
安全な方法は、Web サーバーの機能で「Cloudflare の IP アドレス範囲から来た接続に限り」ヘッダーの値を使うことです。Cloudflare の IP アドレス範囲は https://www.cloudflare.com/ips-v4 と https://www.cloudflare.com/ips-v6 で公開されており、公式ドキュメントでも定期的な更新が必要とされています。
Nginx(ngx_http_realip_module)の場合、範囲の一覧から設定ファイルを作り、http ブロックで読み込みます。
# Cloudflare の IP アドレス範囲から Nginx の設定を作る
{
curl -s https://www.cloudflare.com/ips-v4
echo
curl -s https://www.cloudflare.com/ips-v6
} | grep -v '^$' | sed 's/.*/set_real_ip_from &;/' | sudo tee /etc/nginx/conf.d/cloudflare-realip.inc
echo 'real_ip_header CF-Connecting-IP;' | sudo tee -a /etc/nginx/conf.d/cloudflare-realip.inc
# /etc/nginx/nginx.conf の http ブロック内
include /etc/nginx/conf.d/cloudflare-realip.inc;
nginx -t で設定を確認してから再読み込みします。Apache 2.4 では mod_remoteip を有効にし、RemoteIPHeader CF-Connecting-IP と、Cloudflare の範囲ごとの RemoteIPTrustedProxy を設定します。どちらの場合も、PHP には置き換え後の正しい REMOTE_ADDR が渡るので、WordPress 側のコードでヘッダーを読む必要はありません。
PHP でどうしても扱う場合は、REMOTE_ADDR が Cloudflare の範囲に入っていることを確かめてからヘッダーの値を使います。IPv6 の範囲も判定に含め、範囲の一覧は定期的に更新してください。
さらに、オリジンサーバーのファイアウォールで HTTP・HTTPS の受け付けを Cloudflare の IP アドレス範囲に限ると、Cloudflare を迂回した直接のアクセスそのものを防げます。
動作の確認と運用
- ルールを有効にしたら、ログアウトした状態で
/xmlrpc.phpや/wp-login.phpを開き、ブロックやチャレンジが出ることを確認します。 - 管理画面での記事の保存、プラグインの更新、問い合わせフォームの送信など、普段の操作が止まっていないかを確かめます。
- ダッシュボードのセキュリティイベントで、どのルールがどのリクエストを止めたかを確認できます。正規の操作が止まっていれば、条件を見直します。
- 「I'm Under Attack!」モードは、すべての訪問者に確認をかけるため、攻撃を受けている最中に一時的に使う機能です。普段はレート制限とカスタムルールで対応します。
まとめ
- WAF が働くのは Cloudflare を経由するリクエストだけ。
cf-rayヘッダーで確認する。 - Free プランでもカスタムルール5つとレート制限ルール1つが使える。WordPress 向けのルールを含む Cloudflare Managed Ruleset は Pro 以上。
xmlrpc.phpのブロック、wp-login.phpへのチャレンジ、/wp-admin/の IP 制限(admin-ajax.phpは除外)から始める。- API は Rulesets API を使う。Firewall Rules API は2025年6月15日でサポート終了。
- オリジンでは
CF-Connecting-IPを無条件に信じず、Web サーバーの realip / remoteip の設定で Cloudflare からの接続に限って IP アドレスを置き換える。
関連記事: