Web開発 2026年5月10日

Cloudflare Rate Limiting

Cloudflareエッジで「同じ識別子(IP / Header / Cookie / Body フィールド等)から一定期間に何リクエスト来たか」をカウントし、閾値を超えたものをBlock / Challenge / Logするレートベース制御である。WAF配下の「Rate limiting rules」として統合され、Enterpriseでは複雑な特徴量や複雑度スコアに基づくAdvanced Rate Limitingまで一気通貫で書ける。

Rate Limiting

一行サマリ

Cloudflareエッジで「同じ識別子(IP / Header / Cookie / Body フィールド等)から一定期間に何リクエスト来たか」をカウントし、閾値を超えたものをBlock / Challenge / Logするレートベース制御である。WAF配下の「Rate limiting rules」として統合され、Enterpriseでは複雑な特徴量や複雑度スコアに基づくAdvanced Rate Limitingまで一気通貫で書ける。

解決する課題(Why)

WAFの署名ベース防御は「1リクエスト単体が悪性かどうか」しか見ない。そのためログイン総当たり、商品在庫の買い占め、価格スクレイピング、APIキー流出後の暴走呼び出しといった「個別リクエストは正常だが、頻度が異常」な攻撃を捉えられない。Originのアプリ側でカウンタを実装すると、(1) インスタンス間の状態共有(Redis等)、(2) WAF・LBより手前で止められない、(3) Botネットワークによる分散リクエストで識別子設計を間違えやすい、という運用負債を抱える。Cloudflare Rate Limitingはこれをエッジ側で完結させ、以下を解決する。

  • ログインPOSTやワンタイムトークン検証エンドポイントへの総当たりを、ユーザー名(リクエストボディ)単位で抑止。
  • 在庫・予約・チケット販売の買い占めBotを、Cookie / セッションID単位で抑止。
  • 公開API(無料プラン)における暴走呼び出しを、APIキー(Header)単位で抑止。
  • スクレイピングを、JA3/JA4フィンガープリントやASN単位でしきい値運用。
  • Originに到達する前にBlock / Managed Challengeで返すことで、バックエンドの計算資源・DB接続を保護。

主要機能(What)

Rate Limiting Rules(WAF統合)

2023年の刷新で従来の「Legacy Rate Limiting」はWAF配下の rate limiting rules として統合された。WAF Custom Rules / Managed Rulesと同じRules言語(http.request.uri.path, http.request.method, ip.src, cf.bot_management.score 等)でマッチ条件を書き、そこに「Period内に何回マッチしたら何をするか」を重ねる構造になっている。

  • Expression:マッチ対象を絞り込むRules言語式。http.request.uri.path eq "/api/login" and http.request.method eq "POST" のように、レート制限を効かせたいエンドポイントだけを切り出す。
  • Characteristics(カウント単位):誰/何ごとにカウントするか。IP / IP with NAT / Header / Cookie / Body / JA3-JA4 / ASN / Country / Path / Custom など。
  • Period:カウントの時間窓(秒)。Free 10秒、Pro 最大1分、Business / Enterprise 最大10分(最大65,535秒まで対応するプランあり)。
  • Requests per period:閾値。
  • Mitigation timeout(Duration):閾値到達後、どれだけの間アクションを継続するか。Pro 最大1時間、Business / Enterprise 最大24時間。
  • Action:Block / Managed Challenge / JS Challenge / Interactive Challenge / Log。EnterpriseではBlock時に「Throttle requests above rate」(超過分のみブロック、閾値以下は通す)が選べる。

Advanced Rate Limiting(Business以上 / 多くはEnterprise)

標準のIP単位カウントでは捉えられないユースケースを、複合特徴量とペイロードベースで吸収する上位機能群。

  • Complex characteristics:複数のSelectorを組み合わせ「同一IP + 同一User-Agent + 同一Cookie値」のような複合キーでカウント。Botネットの分散攻撃で「IPは違うがUser-Agentが同じ」「Cookieは違うがJA4が同じ」といった揺らぎを潰せる。
  • Payload-basedhttp.request.body.form["username"] のようにリクエストボディ内のフィールドをカウント単位にできる。ログインAPIで「同じusernameに対する試行回数」を直接抑制でき、IP単位より攻撃意図に近い指標になる。
  • Complexity score:1リクエストの「重さ」(コスト)を score として加算し、純粋な回数ではなく総コストで閾値を切るモデル。重いGraphQLクエリやレポート生成APIでの暴走対策に向く。
  • Throttle action:閾値超過分のみをBlock / Challengeし、閾値以下のリクエストはそのまま通す(純粋な「整流」)。

Counting Characteristics(プラン別対応)

カウント単位として何を選べるかはプランで明確に分かれる。

プラン利用可能な Characteristics
FreeIP のみ
ProIP
BusinessIP / IP with NAT
Enterprise(Advanced)IP / IP with NAT / Header / Cookie / ASN / Country / Path / JA3-JA4 Fingerprint / JSON field / Body / Form input / Custom expression

「IP with NAT」はCloudflareが推定する「同一NAT配下を1ユーザーとみなす」拡張で、モバイルキャリアNATや企業プロキシで誤ブロックを抑える。

Mitigation Timeout(Duration)

閾値到達後、どれくらい制裁を続けるか。短すぎれば攻撃側が即座にリトライするだけになるし、長すぎれば誤検知が業務を止める。一般的な設計指針は次の通り。

  • ログインBrute-force:Period 60s / Threshold 5〜10 / Timeout 10〜30分(人間のリトライ時間に合わせる)。
  • スクレイピング:Period 60s / Threshold 100〜300 / Timeout 1〜24時間(ターゲットコンテンツの重要度次第)。
  • API濫用:Period 60s / Threshold = プランごとのRPS×60 / Timeout 10分〜1時間(請求と整合する制裁時間)。

Workers Rate Limiting API(自前実装の選択肢)

WAFのRate Limiting Rulesは「ゾーン全体に対するエッジ手前の機械的制御」だが、Workers Rate Limiting APIは「Worker内のロジック条件込みでカウントしたい」場合の補完である。

  • env.MY_RATE_LIMITER.limit({ key }) のシンプルなAPIで、内部的にDurable Objectsベースのカウンタが走る。
  • 認証後のユーザーID単位、ワークフローのステップ単位など、WAF Expressionでは表現しづらい「アプリ文脈で正規化したキー」でレート制限できる。
  • KV / Durable Objectsを直接叩いて自前カウンタを書くこともできるが、それは整合性・コスト・実装複雑度を引き受ける覚悟が要る。Rate Limiting APIは「DOで自前実装する一歩手前」を引き受ける位置づけである。

Legacy Rate Limiting(deprecated)からの移行

2017年から提供されていた旧Rate Limiting(ダッシュボード上で「Tools → Rate Limiting」にあった独立機能)は、現在は新しい「WAF配下のRate limiting rules」に統合されている。

  • 旧ルールは引き続き動作するが、新規作成は新形式で行う前提。
  • 旧ルールは「URLパターン + Method + Threshold」しか持たないため、Expressionによる柔軟な絞り込みやEnterprise Advanced機能が使えない。
  • 移行はCloudflareダッシュボードの誘導またはAPI(POST /zones/{id}/rulesets/.../rulesphase = http_ratelimit)で行う。Terraform管理下なら cloudflare_ruleset リソースに phase = "http_ratelimit" で書き直す。

アーキテクト視点:いつ選ぶか

Bot Management / API Shield との役割分担

3者は「速度・形・素性」のどこで切るかで棲み分ける。

  • Rate Limiting:速度(頻度)で切る。識別子と閾値・期間というシンプルなモデル。Bot判定ができない(しない)リクエストにも効く。
  • Bot Management:素性(人間 / 良性Bot / 悪性Bot)で切る。Bot Score、JA4、機械学習による行動分析。「人間っぽいかどうか」の判定そのもの。
  • API Shield:形(API契約)で切る。OpenAPIスキーマからの逸脱、Schema Validation、Sequence Mitigation、JWT検証。APIエンドポイントを「正しい形のリクエストか」で守る。

実運用では [Bot Management で明確な悪性Botを落とす] → [API Shieldでスキーマ違反を落とす] → [Rate Limitingで人間/Bot問わず頻度異常を抑える] のように直列配置する。Rate Limiting単独では「分散Bot」「人間っぽいBot」を取り逃がしやすく、Bot Management単独では「正規ユーザーの暴走」「APIキー漏洩後の悪用」を取り逃がしやすい。

適しているシーン

  • ログインAPI / OTP送信API / パスワードリセットAPIなど、明確に「同一識別子からの連続試行」が攻撃シグナルになるエンドポイント。
  • 公開APIの無料プランRPS制限の実装基盤(課金プラン別のしきい値運用)。
  • 在庫・予約・チケットなど買い占めBot対策(Cookie / セッション単位)。
  • スクレイピング対策の第1段(JA3/JA4 / ASN単位でPeriod長め)。

適していないシーン

  • そもそもCloudflare経由していないトラフィック(Origin直アクセス可能なIP)にはRate Limitingは効かない。Origin IP秘匿が前提。
  • Worker内のロジック条件・認証後ユーザーID単位の制御は、Workers Rate Limiting APIまたはアプリ側実装の方が適切。
  • 短期スパイクではなく長期傾向(1日単位の総量配分)はQuota管理の世界で、Apigee Quotaや自前のメータリングが向く。

競合・代替

観点Cloudflare Rate LimitingAWS WAF Rate-basedKong Rate LimitingApigee Quota / Spike ArrestAkamai Rate ControlsImperva ABP
配置エッジ(Cloudflareネットワーク)エッジ(CloudFront / ALB / API GW)API Gateway内API Management内エッジ(Akamai)エッジ(Imperva)
カウント単位IP / Header / Cookie / Body / JA3-JA4 / ASN / Country 他(Enterprise)IP / Header / Forwarded IP / カスタムキーConsumer / Credential / IP / Service / HeaderAPI key / Developer / App / ProductIP / Geo / カスタムIP / セッション / フィンガープリント
ペイロード単位カウントあり(Form input / JSON field / Body)※Enterprise限定的(ヘッダ・クエリ中心)あり(Body parser plugin)あり(API Productに紐づく)ありあり
Throttle(超過分のみ)ありあり(Block / Count)ありSpike Arrestで実装ありあり
Bot対策との統合Bot Managementと密結合AWS WAF Bot Controlは別ルール別Plugin別商品Bot Manager別商品同一プラットフォーム強み
強みエッジ統合・JA4 / Body単位までエッジで完結AWSスタック完結・IaC成熟OSS基盤・自前運用OK・拡張性API管理基盤としての設計力大規模配信基盤・成熟度Bot対策と一体運用
弱みFree / ProでIP単位以外不可カウント単位の柔軟性は中位自前運用のオーバーヘッドエッジではなくAPIゲートウェイ位置高コスト・調達ハードル高コスト

CloudflareのRate Limitingは「エッジで止められる」「JA4 / Body / Cookieまでエッジで効く」「Bot Management / API Shield / WAFと同じプレーンで書ける」点に集約される。Originがマルチクラウドだったり、API Gatewayレイヤを別ベンダーで揃えていてもエッジ手前で1段絞れるのが最大の差別化要因である。

料金

  • Free:Rate Limiting Rules 1ルール(一部公開情報では「Previously Free」枠相当)。Period最大10秒、IP単位のみ。検証用途。
  • Pro:5ルール程度。Period最大1分、Mitigation Timeout最大1時間、IP単位のみ。
  • Business:15ルール程度。IP / IP with NAT。Period・Timeoutともに上限拡張。
  • Enterprise:100ルール超 + Advanced Rate Limiting(Header / Cookie / Body / JA4 / ASN / Country / Custom expression、Complexity score、Throttle action)。Period最大10分(プラン詳細によっては65,535秒まで)、Timeout最大24時間。

実装上は「Free / Proは『IPベースの最低限の防衛線』、Business以上から『業務要件に沿ったRate Limiting設計』が現実解」と割り切るのが妥当である。WAFやBot Managementとセットで Enterprise Advanced を引くケースが多い。

CLI / API 例

Ruleset API(curl)でレート制限ルールを追加

http_ratelimit phaseのrulesetに追加する形になる。

ZONE_ID="..."
TOKEN="..."

# 1) http_ratelimit phaseのentry point rulesetを取得(無ければ作成)
curl -s -X GET \
  "https://api.cloudflare.com/client/v4/zones/${ZONE_ID}/rulesets/phases/http_ratelimit/entrypoint" \
  -H "Authorization: Bearer ${TOKEN}"

# 2) ルールを追加:/api/login への POST に対し、IP単位で60秒5回を超えたら10分Block
curl -s -X POST \
  "https://api.cloudflare.com/client/v4/zones/${ZONE_ID}/rulesets/phases/http_ratelimit/entrypoint/rules" \
  -H "Authorization: Bearer ${TOKEN}" \
  -H "Content-Type: application/json" \
  --data '{
    "description": "Login brute-force protection",
    "expression": "(http.request.uri.path eq \"/api/login\" and http.request.method eq \"POST\")",
    "action": "block",
    "ratelimit": {
      "characteristics": ["ip.src", "cf.colo.id"],
      "period": 60,
      "requests_per_period": 5,
      "mitigation_timeout": 600
    }
  }'

Terraform(cloudflare provider v5)

resource "cloudflare_ruleset" "rate_limit_login" {
  zone_id     = var.zone_id
  name        = "Rate limiting rules"
  description = "Edge rate limiting"
  kind        = "zone"
  phase       = "http_ratelimit"

  rules = [
    {
      description = "Login brute-force: 5 req/60s per IP -> block 10min"
      expression  = "(http.request.uri.path eq \"/api/login\" and http.request.method eq \"POST\")"
      action      = "block"
      ratelimit = {
        characteristics     = ["ip.src", "cf.colo.id"]
        period              = 60
        requests_per_period = 5
        mitigation_timeout  = 600
      }
    },
    {
      description = "API key abuse: 1000 req/60s per X-Api-Key -> managed_challenge 1h"
      expression  = "(starts_with(http.request.uri.path, \"/api/\"))"
      action      = "managed_challenge"
      ratelimit = {
        characteristics     = ["http.request.headers[\"x-api-key\"]", "cf.colo.id"]
        period              = 60
        requests_per_period = 1000
        mitigation_timeout  = 3600
      }
    },
    {
      description = "Login attempts per username (Advanced Rate Limiting / Enterprise)"
      expression  = "(http.request.uri.path eq \"/api/login\" and http.request.method eq \"POST\")"
      action      = "block"
      ratelimit = {
        characteristics     = ["http.request.body.form[\"username\"]", "cf.colo.id"]
        period              = 60
        requests_per_period = 10
        mitigation_timeout  = 1800
      }
    },
  ]
}

Workers Rate Limiting API

// wrangler.jsonc
{
  "name": "api-worker",
  "main": "src/index.ts",
  "compatibility_date": "2025-01-01",
  "ratelimits": [
    { "name": "API_LIMITER", "namespace_id": "1001", "simple": { "limit": 100, "period": 60 } }
  ]
}
export default {
  async fetch(req: Request, env: Env): Promise<Response> {
    const userId = await authenticate(req); // 認証後のユーザーID
    const { success } = await env.API_LIMITER.limit({ key: userId });
    if (!success) return new Response("rate limited", { status: 429 });
    return handle(req);
  },
};

制限・注意点

  • カウンタ更新の遅延:Cloudflareは「リクエスト検知からカウンタ反映まで数秒の遅延がある」と明記している。閾値直後の数秒間は超過リクエストがOriginに届く前提で設計する(Origin側にも保険を置く)。
  • Period上限はプラン依存:Free 10秒、Pro 1分、Business / Enterprise 10分〜(プラン詳細により最大65,535秒)。Period長を前提にした設計(例:1時間レート)はBusiness以上。
  • Counting Characteristics数とルール数の上限:プランごとに利用可能な特徴量の種類数とルール数が決まる。Header / Cookie / Body単位が必要なら原則Enterprise。
  • cf.colo.id の扱い:CloudflareはAnycastで複数PoPに分散するため、特徴量に cf.colo.id を加えて「PoPごとカウント」とする運用が公式サンプルでも採用されている。グローバルに厳密な集約カウントが要るケースには向かない(その用途はWorkers Rate Limiting APIや自前DOで実装)。
  • OriginIP直叩き対策:Cloudflareを通らなければ意味がない。Authenticated Origin Pulls / Cloudflare Tunnel / Origin IPホワイトリストで直アクセスを塞ぐ前提が必要。
  • Bot Managementとの順序:同一フェーズで動作するため、ルールの優先順位(Custom Rules → Rate Limiting Rules → Managed Rules)を意識して設計する。Bot Management未契約の環境でRate Limitingだけに頼ると、分散Botに対しては効果が薄い。
  • Legacy Rate Limitingの扱い:旧ルールは新形式と並存できるが、Advanced機能・新Expression言語が使えないため、移行を前提に棚卸しする。

参考リンク


参照日: 2026-05-04