レートリミット(rate limiting)は、決めた時間のあいだに、同じ相手から来るリクエストの回数を制限する仕組みです。上限を超えたリクエストは、HTTP の状態コード 429 Too Many Requests(リクエストが多すぎる)で断ります。API(アプリやサービスのあいだで、データや機能をやり取りする窓口)やログインを作るときは、この制限が無いと、短い時間に大量のリクエストを送られて、サービスが止まったり、外のサービスへの支払いが増えたりすることがあります。
2026年10月には、JPCERT/CC が注意喚起 JPCERT-AT-2026-0030 で、ログイン・パスワードリセット・SMS 送信・検索処理などに、個別にレート制限や利用回数制限を入れるよう書いています。個人情報保護委員会の WARNING も、API の悪用の事例の原因に「アクセス回数制限(レートリミット)がなかった」ことを挙げています。この 2 つの文書は、認証と認可の違いとは?とJPCERT/CC の注意喚起(2026年10月)を読み解くで詳しく書いています。
この記事は、API やログインのある Web アプリを作り始めた人に向けて、自分の API とログインを守る側の話を書いたものです。レートリミットとは何か、429 と Retry-After、ログインの失敗の数え方、Cloudflare の無料プランでできること、数え方とヘッダーの決まりの状況を説明します。使う側で 429 が出たときの話は、最後に 1 節だけ書きました。書いてあることは、OWASP・NIST・IETF・Cloudflare の文書を、2026年10月21日に開いて確かめたものです。JPCERT/CC と個人情報保護委員会の文書は、関連記事のために 2026年10月20日に開いたものです。手元の確かめは、macOS 14.4.1・Python 3.12.3・curl 8.4.0 で、自分のパソコンの 127.0.0.1 の中だけで流しました。Cloudflare のサービスそのものは、手元では流していません。
OWASP の Cheat Sheet(開発者向けの短い手引き)や Cloudflare の無料プランの範囲は、書き換わることがあります。「2026年10月時点」は、その日に読んだ内容です。作るときは、最新の文書を開き直してください。
- レートリミットが何を守るか。OWASP は、回数だけでなく、大きさ・件数・時間・支出も制限するよう書いていること
- 429 と Retry-After の意味と、手元のサーバーで 200 → 429 → 待って 200 を確かめた結果
- ログインの失敗を、IP とアカウントのどちらで数えるか(OWASP と、手元の例の違い)。締め出しを他人への攻撃に使わせない注意
- Cloudflare の無料プランでできること・できないこと(2026年10月21日に開いた公式の表)と、Turnstile のサーバー側の確かめ
- 数え方(固定窓・スライディング窓・トークンバケット)と RateLimit ヘッダーが、まだ標準ではないこと
レートリミットとは?何を制限するの?
OWASP(ウェブの安全に取り組む団体)の Denial of Service Cheat Sheet は、レートリミットを「サーバーや部品との間の通信の速さを制御すること」と説明しています。インフラ(サーバーやネットワークの側)でもアプリの側でも入れられ、数える相手は、問題のある IP・IP のブロックリスト・地域などで決められる、と書いています。DoS(Denial of Service)は、資源を使い切らせて、ほかの人が使えなくする攻撃のことです。
OWASP API Security Top 10 の 2023 年版(今の版です)には、レートリミットに近い項目として API4:2023 Unrestricted Resource Consumption(資源の消費に制限が無いこと) があります。API に応えるには、帯域・CPU・メモリ・ストレージが要ります。メール・SMS・電話・生体認証の確認のように、外のサービスに 1 回ごとにお金を払う資源もあります。悪用されると、資源が尽きてサービスが止まるだけでなく、CPU やクラウドのストレージなど、運用の費用が増えることもあります。OWASP は、単純なリクエストで悪用でき、1 台のパソコンからでも同時にたくさん送れる、制限していない API はよくある、とも書いています。
ただし、API4 は「回数」だけの項目ではありません。 OWASP は、次の制限が 1 つでも無いか、合っていない(低すぎる・高すぎる)と、API が弱いと書いています。
- 実行の時間切れ
- 使えるメモリ
- ファイル記述子の数・プロセスの数
- アップロードの大きさ
- 1 回のリクエストでする操作の数(GraphQL の batching など)
- 1 回で返す件数
- 外のサービスへの支出の上限
回数の制限(レートリミット)は、このうちの 1 つです。2019 年版では、同じ番号の項目が「Lack of Resources & Rate Limiting」という名前でした。
OWASP が挙げる 3 つの例
OWASP は、API4 の例を 3 つ挙げています。どれも OWASP が「Example Attack Scenarios(攻撃の例)」として挙げたもので、実際の事故として書かれてはいません。
- SMS の費用。 パスワードを忘れたときに、SMS でコードを送る API があります。外の SMS の会社は 1 回あたり $0.05 かかります。攻撃者がスクリプトで最初の API を何万回も呼ぶと、裏で何万通もの SMS が送られ、数分で数千ドルを失います
- 「回数」と「中の操作の回数」は別。 「短い時間に何度も呼べない」という昔ながらのレートリミットを入れていても、GraphQL の 1 回のリクエストに同じ操作をたくさん詰めると、操作の回数は制限されていないので、サーバーのメモリが尽きます。OWASP は、リクエストの回数の制限だけでは足りない例として挙げています
- 攻撃でなくても起きる。 大きなファイルをダウンロードさせる API で、キャッシュは 15GB までしか持たないのに、ファイルが 18GB に増えました。費用の通知も上限も無かったので、月の請求が平均 US$13 から US$8k に増えました。利用者がふつうに取りに来ただけでも、費用は増えます
OWASP の防ぎ方
OWASP は、防ぎ方として、決まった時間の中でクライアントが API とやり取りできる回数を制限すること(rate limiting)を挙げています。レートリミットは業務の必要に合わせて調整し、入口によってはもっと厳しくします。1 つのクライアント・利用者が 1 つの操作をする回数や頻度も制限します(例: OTP〔ワンタイムパスワード〕の確認、パスワードの再設定の申し込み)。そのほか、すべての入力に最大の大きさを決めること、返す件数を決めるパラメーターをサーバー側で確かめること、外のサービスへの支出の上限を決める(できなければ請求の通知を設定する)ことも挙げています。
OWASP は、具体的な回数(何回まで)は書いていません。 何回にするかは、自分のサービスの使われ方で決めることになります。
なお、JPCERT/CC が挙げる「ログイン、パスワードリセット、SMS送信、検索処理」は、OWASP の例の SMS や、防ぎ方の OTP・パスワードの再設定と重なります(JPCERT/CC が OWASP から取った、とは書かれていません)。
429 と Retry-After とは?
429 Too Many Requests は、RFC 6585(2012年4月。Proposed Standard)で決まった状態コードです。RFC は「決まった時間の中で、利用者が送ったリクエストが多すぎる(rate limiting)」ことを示す、と書いています。OWASP の REST Security Cheat Sheet も、状態コードの表で 429 を「DoS 攻撃が見つかったかもしれないとき、またはレートリミットで断ったとき」に使うものとし、API キーの節では「速すぎるリクエストには 429 を返す」と書いています。
RFC 6585 が 429 の応答について決めていることは、次のとおりです。
- 事情を説明する中身を入れるべき(SHOULD)。RFC の例は、「ログインした利用者ごとに 1 時間に 50 回まで」という HTML と、
Retry-After: 3600です - 次のリクエストまでどれだけ待つかを示す Retry-After ヘッダーを付けてもよい(MAY)。必須ではありません
- 429 の応答は、キャッシュに保存してはいけない(MUST NOT)
Retry-After は、RFC 9110(2022年6月。Internet Standard)の 10.2.3 節に定義があります。次のリクエストまで、利用者のソフトがどれだけ待つべきかを示すヘッダーで、値は日時(HTTP-date)か、受け取ってから待つ秒数(0 以上の整数)です。Retry-After: 120 なら、2 分待ちます。
似た場面で出てくる 503 との違いは、次のとおりです。
| 状態コード | 意味 | 決めている文書 |
|---|---|---|
| 429 Too Many Requests | 決まった時間の中で、その利用者が送ったリクエストが多すぎる | RFC 6585 |
| 503 Service Unavailable | サーバーが、一時的な過負荷や保守で、リクエストに応えられない | RFC 9110 |
503 にも Retry-After を付けてよい(MAY)ことになっています。503 で付けたときは「どれだけ使えないと見込まれるか」の意味になります。RFC 9110 は、過負荷のとき 503 を使わなければならないわけではない(接続を断るだけのサーバーもある)とも書いています。なお、RFC 9110 の本文には 429 は出てきません。429 を決めているのは RFC 6585 です。
RFC 6585 が決めていないこと
RFC 6585 は、利用者をどう見分けるか・リクエストをどう数えるかを、決めていません。 数え方は、資源ごと・サーバー全体・複数のサーバーにまたがってでもよく、見分け方は、認証の資格情報でもクッキーでもよい、と書いています。「IP アドレスごとに数える」とは、書いていません。何を単位に、どう数えるかは、作る側が決めます。
手元で確かめる:3 回まで通して、4 回目は 429
429 と Retry-After を、手元のサーバーで確かめます。試すのは、自分で作った手元のサーバーだけです。 他人のサービスに、大量のリクエストを送ってはいけません。
環境は、macOS 14.4.1(arm64)・Python 3.12.3・curl 8.4.0 です。サーバーは、Python の標準ライブラリの http.server だけで書き、127.0.0.1:8765(自分のパソコンの中だけ)で待ち受けました。流し終わったら止めています。外には何も送っていません。次のコードは手元の確かめ用で、本番のサーバーにする形ではありません。
流したサーバー
IP アドレスごとに、60 秒のあいだに 3 回までしか通さないサーバーです。
import math
import time
from collections import defaultdict, deque
from http.server import BaseHTTPRequestHandler, HTTPServer
LIMIT = 3 # 1 分あたりに通す回数(N)
WINDOW = 60 # 数える長さ(秒)
hits = defaultdict(deque) # IP ごとの「通したリクエストの時刻」
class Handler(BaseHTTPRequestHandler):
def do_GET(self):
ip = self.client_address[0]
now = time.monotonic()
q = hits[ip]
while q and now - q[0] >= WINDOW: # 60 秒より前の分は捨てる
q.popleft()
if len(q) >= LIMIT:
wait = math.ceil(WINDOW - (now - q[0])) # いちばん古い 1 回が窓から出るまで
body = f"Too Many Requests: {LIMIT} requests per {WINDOW} seconds\n".encode()
self.send_response(429)
self.send_header("Retry-After", str(wait))
self.send_header("Content-Type", "text/plain; charset=utf-8")
self.send_header("Content-Length", str(len(body)))
self.end_headers()
self.wfile.write(body)
return
q.append(now)
body = f"ok ({len(q)}/{LIMIT})\n".encode()
self.send_response(200)
self.send_header("Content-Type", "text/plain; charset=utf-8")
self.send_header("Content-Length", str(len(body)))
self.end_headers()
self.wfile.write(body)
def log_message(self, fmt, *args):
pass # 出力を絞る
HTTPServer(("127.0.0.1", 8765), Handler).serve_forever()
数え方は、次のとおりです。
self.client_address[0]は、TCP でつないできた相手の IP です。手元では 127.0.0.1 の 1 つだけです。プロキシ(Cloudflare など)の後ろにアプリを置いたとき、アプリに見える IP がどうなるかは、確かめていません。 プロキシの IP になる場合もありえます。このコードを、本番の書き方として勧めるものではありません- 通したリクエストの時刻を IP ごとに持ち、直近 60 秒に 3 回あれば断ります
Retry-Afterは、いちばん古い 1 回が 60 秒の窓から出るまでの秒数(切り上げ)です- 断ったリクエストは、数に入れていません
curl で 5 回送る
サーバーを立ち上げ、待ち受けを確かめてから、curl を続けて 5 回送りました。-i は、応答のヘッダーも表示するオプションです。
$ curl -s -i http://127.0.0.1:8765/ # 1 回目
HTTP/1.0 200 OK
Server: BaseHTTP/0.6 Python/3.12.3
Date: Wed, 21 Oct 2026 10:40:52 GMT
Content-Type: text/plain; charset=utf-8
Content-Length: 9
ok (1/3)
$ curl -s -i http://127.0.0.1:8765/ # 2 回目
HTTP/1.0 200 OK
Server: BaseHTTP/0.6 Python/3.12.3
Date: Wed, 21 Oct 2026 10:40:52 GMT
Content-Type: text/plain; charset=utf-8
Content-Length: 9
ok (2/3)
$ curl -s -i http://127.0.0.1:8765/ # 3 回目
HTTP/1.0 200 OK
Server: BaseHTTP/0.6 Python/3.12.3
Date: Wed, 21 Oct 2026 10:40:52 GMT
Content-Type: text/plain; charset=utf-8
Content-Length: 9
ok (3/3)
$ curl -s -i http://127.0.0.1:8765/ # 4 回目
HTTP/1.0 429 Too Many Requests
Server: BaseHTTP/0.6 Python/3.12.3
Date: Wed, 21 Oct 2026 10:40:52 GMT
Retry-After: 60
Content-Type: text/plain; charset=utf-8
Content-Length: 45
Too Many Requests: 3 requests per 60 seconds
$ curl -s -i http://127.0.0.1:8765/ # 5 回目
HTTP/1.0 429 Too Many Requests
Server: BaseHTTP/0.6 Python/3.12.3
Date: Wed, 21 Oct 2026 10:40:52 GMT
Retry-After: 60
Content-Type: text/plain; charset=utf-8
Content-Length: 45
Too Many Requests: 3 requests per 60 seconds
1〜3 回目は 200 OK(本文は ok (1/3) から ok (3/3))、4・5 回目は 429 Too Many Requests と Retry-After: 60 でした。そのあと、Retry-After の 60 秒(待つ秒数は、もう 1 回送って取り出しました)を待ってから送ると、また 200 OK になりました。
# Retry-After: 60 の秒数だけ待ったあと
$ curl -s -i http://127.0.0.1:8765/
HTTP/1.0 200 OK
Server: BaseHTTP/0.6 Python/3.12.3
Date: Wed, 21 Oct 2026 10:41:53 GMT
Content-Type: text/plain; charset=utf-8
Content-Length: 9
ok (1/3)
最初の 3 回は同じ秒に通していたので、60 秒後に 3 回分がまとめて窓から出て、また ok (1/3) から数え直しになりました(Date は 10:40:52 から 10:41:53 です)。
応答の先頭の HTTP/1.0 と Server: BaseHTTP/0.6 Python/3.12.3 は、http.server が付けたものです。理由句の Too Many Requests も Python が付けました。コードに書いたのは send_response(429) だけです。
ログインの失敗はどう数える?IP かアカウントか
ログインの入口は、回数の制限がとくに大事な場所です。パスワードを何度も試される攻撃に、直接さらされるからです。OWASP の Authentication Cheat Sheet は、自動で行われる攻撃を、次の 3 つの型に分けています。
| 型 | 中身 |
|---|---|
| 総当たり(Brute Force) | 1 つのアカウントに、辞書などから取ったたくさんのパスワードを試す |
| クレデンシャルスタッフィング(Credential Stuffing) | よそのサイトから漏れた、ユーザー名とパスワードの組を試す |
| パスワードスプレー(Password Spraying) | 1 つの弱いパスワードを、たくさんのアカウントに試す |
OWASP は、これらの守りはどれも完全ではないが、重ねて使うと、それなりの守りになると書いています。この節は、OWASP が「主に総当たりを防ぐ」として書いている内容が中心です。スタッフィングとスプレーは、OWASP が別の Cheat Sheet に分けていて、この記事では扱いません。パスワードの保存の側の話は、パスワードの正しい受け取り方と保存のしかたにあります。
数える単位:アカウントに結びつける(OWASP)
OWASP が挙げるいちばん一般的な守りは、アカウントの締め出し(account lockout)です。一定の回数ログインに失敗したら、しばらくのあいだ、それ以上のログインの試みを受け付けません。
そのとき、OWASP は次のように書いています。
失敗の回数は、送り元の IP アドレスではなく、アカウントそのものに結びつけて数えるべきです。たくさんの別の IP アドレスから試されるのを防ぐためです。
(OWASP の Authentication Cheat Sheet の文を訳したものです。)
決めることは、OWASP によれば 3 つです。
- 締め出すまでの失敗の数(lockout threshold)
- その数を数える時間の長さ(observation window)
- 締め出す長さ(lockout duration)
決まった長さ(たとえば 10 分)の代わりに、ごく短い時間(たとえば 1 秒)から始めて、失敗のたびに倍にする「指数的な締め出し」を使うアプリもある、とも書いています。
IP ごとに数えるやり方との関係
一方で、IP アドレスごとに数える例もあります。OWASP の Denial of Service Cheat Sheet は、レートリミットを IP などで決められると書き、この記事の手元のサーバー、Cloudflare の無料プラン、Cloudflare のログインの手本(数えるのは 401・403 の失敗だけ)も、IP ごとです。RFC 6585 は見分け方を決めていません(例は、認証の資格情報とクッキーです)。
どれが正しい、という話ではなく、守るものが違います。 この記事では、次のように分けて考えます。これは記事の整理で、出典の言い方そのままではありません。
- API 全体の使いすぎ(費用・負荷)。IP や、ログイン後の利用者ごとなど、相手ごとに数える
- ログインの失敗。OWASP の言うとおり、アカウントに結びつけて数える
なお、ログインの失敗をアカウントごとに数えるコードは、手元では流していません。 手元のサーバーが数えるのは IP ごとの回数だけです。アカウントごとの数え方が、スタッフィングやスプレーにどこまで効くかも、確かめられていないので書きません。
締め出しを、他人への攻撃に使わせない
アカウントごとに数えて締め出すと、別の問題が出ます。他人のアカウントに、わざと間違ったパスワードを何度も送れば、その人を締め出せてしまうからです。OWASP は、締め出しの仕組みを作るときは、他人のアカウントを締め出す DoS に使われないように気をつけるよう書いています。1 つの手として、アカウントが締め出されていても、「パスワードを忘れたとき」の手順ではログインできるようにすることを挙げています。
NIST の「100 回」は上限です
NIST SP 800-63B-4(米国の NIST が出した指針。米国の政府の情報システム向けです)は、試行の回数を制限する仕組みを入れること(SHALL)を決めています。認証の手段ごとに別の決まりが無ければ、1 つのアカウント・1 つの認証の手段で、続けて失敗できるのは 100 回まで(SHALL)です。
この 100 は上限で、もっと少なくしてよい(MAY)ので、「100 回にする」という意味ではありません。100 にした理由は、当たる見込みと、上限を超えたときの復旧の手間の釣り合いです。OWASP、NIST、Cloudflare の手本で出てくる数字は、数えているものも使い方も違うので、数字だけを並べて比べないでください。NIST は、締め出しを減らす工夫の 1 つに「認証を試す前に、ボットを見分けて抑える確認を済ませてもらう」ことを挙げています。NIST の試行回数と締め出しを減らす工夫は、パスワードの正しい受け取り方と保存のしかたにもまとめています。
CAPTCHA・多要素認証・ログ
- CAPTCHA(人かどうかを見分ける確認)。OWASP は、自動のログインの試みを防ぐ助けになるが、自動で解けたり、解く業者に回されたりする弱さがあるので、「防ぐもの」ではなく、攻撃に時間と費用をかけさせる重ねの守りと見るよう書いています。最初のログインから求めるより、何回か失敗したあとにだけ求めるほうが、使いやすいかもしれない、とも書いています
- 多要素認証(パスワード以外の確認も使うこと)。OWASP は、総当たりを含む、パスワードへの攻撃の多くに対して、とびぬけていちばんの守りだと書いています
- ログ。OWASP は、認証の失敗・パスワードの失敗・アカウントの締め出しを、すべて記録して見直すよう書いています
認証と認可の違いは、認証と認可の違いとは?で説明しています。
Cloudflare で止めるには?無料プランでできること
Cloudflare(サイトの前に置く、DNS・CDN・セキュリティのサービス)を使っているなら、アプリの手前で回数を制限できます。Cloudflare の考え方は、Cloudflare とは?無料プランでできることで説明しています。この節は、Cloudflare の公式の文書(2026年10月21日に開いたもの)の範囲で書きます。プランの範囲は、変わることがあります。
Rate limiting rules の仕組み
Cloudflare の Rate limiting rules は、式に当たるリクエストに回数の上限を決め、上限に達したときの動き(action)を決める機能です。公式の文書は、使い道として、ログインの入口を総当たりから守ること、1 つのクライアントが決まった時間に呼べる API の回数を絞ることを挙げています。
ルールで決めるのは、式(どのリクエストを数えるか)・動き(action)・数える単位(characteristics。Cloudflare が回数を数えるときの見分け方)・数える長さ(Period。秒)・その長さで何回まで(Requests per period)・上限に達したあと止め続ける長さ(Duration)です。既定では、止める長さのあいだは、その間のリクエストの回数にかかわらず、動きを続けます。
動きは、block(止める)・Non-Interactive Challenge・Managed Challenge・Interactive Challenge(人かどうかの確認)・log(記録だけ)から選びます。block のときの状態コードは、400〜499 から選べて、既定は 429 です。Cloudflare が返す 429 に Retry-After が付くかどうかは、開いた文書に書かれていませんでした。Cloudflare のサイトでは流していないので、確かめていません。
無料プランの範囲(2026年10月21日に開いた公式の表)
| Free | Pro | Business | |
|---|---|---|---|
| 式に使える項目 | Path・Verified Bot | Host・URI・Path・Full URI・Query・Verified Bot | Free と Pro の項目に加えて、Method・Source IP・User Agent |
| 数える単位 | IP | IP | IP、IP with NAT support |
| 数え方を別の式にする(例: 応答が 401・403 のときだけ数える) | できない | できない | できる |
| 数える長さ | 10 秒だけ | 1 分まで | 10 分まで |
| 止める長さ | 10 秒だけ | 1 時間まで | 1 日まで |
| ルールの数 | 1 | 2 | 5 |
(Enterprise の 2 列は省きました。)
この表から、無料プランについて、次のことが言えます。
- 数える単位は IP だけです。アカウントごとには数えられません
- 式に使える項目に Method(GET・POST など)が無いので、「
/loginへの POST だけ」というルールは書けません。Path で選ぶことになります(同じ Path への GET も数に入る、と読めます。手元では確かめていません) - 数え方を別の式にできないので、「ログインに失敗したときだけ数える」こともできません
- 数える長さも止める長さも 10 秒だけ、ルールは 1 つです
Cloudflare の公式の手本(credential stuffing からログインを守る)は、/login への POST で、応答が 401・403 のものだけを IP ごとに数えます。1 分に 4 回で Managed Challenge、10 分に 10 回で Managed Challenge、1 時間に 20 回で 1 日 Block、と罰を段々重くする 3 つのルールです。この手本は、Business プラン以上が要ります。 「無料の Cloudflare で、ログインの失敗を 1 分に 4 回まで」とは、公式の表からは書けません。
IP ごとに数えるときの注意
Business 以上の「IP with NAT support」の説明に、注意が書かれています。NAT(1 つの IP アドレスを、たくさんの機器や人で共有する仕組み)の向こうの人たちは、同じ IP に見えます。この機能はクッキー(_cfuvid)で見分けますが、クッキーを消す人やプライベートブラウズの人は 1 つの数にまとめられ、混んだ NAT では誤って止めることがある、と書いています。ログインや支払いの入口では、Path やヘッダーの値などと組み合わせるよう勧めています。
また、Cloudflare は、Rate limiting rules は正確な回数だけを通すためのものではないと書いています。リクエストを見つけてから数を更新するまで数秒の遅れがあり、その間に、上限を超えた分がオリジンサーバー(あなたのアプリのサーバー)に届くことがあります。数はデータセンターごとに持っていて(同じ地域のデータセンターどうしは共有)、ネットワーク全体で 1 つの数は持ちません。この記事は、ここから、「Cloudflare の制限は入口の 1 つの層で、上限ぴったりで止まる前提にはしない」と読みます。これは記事の読み方で、Cloudflare がそう書いているわけではありません。
Turnstile:ログインの前に、人かどうかを確かめる
Turnstile は、Cloudflare の「CAPTCHA の代わり」です。Cloudflare を通さないサイトにも埋め込めて、訪問者に CAPTCHA を見せずに動きます。操作の要らない JavaScript の小さな確認(計算のパズルなど)で、人か自動のものかを見分けます。部品(widget)の型は、Managed(推奨。危なさに応じてチェックボックスを出すか決める)・Non-interactive・Invisible の 3 つです。NIST の「ボットを見分ける確認」や、OWASP の「何回か失敗したあとにだけ CAPTCHA」を実現する手段の 1 つになりえます。これは記事の読み方で、Cloudflare・NIST・OWASP がそう書いているわけではありません(NIST は Turnstile の名前を挙げていません)。
無料プランの範囲は、2026年10月21日に開いた公式の表では、次のとおりです。
- 料金は無料。部品は 20 個まで(アカウントごと)。部品の型はすべて使える
- 確認の回数は無制限(Cloudflare の表の言い方)。部品 1 つにつきホスト名 10 個まで。分析は 7 日まで遡れる
- Cloudflare の表示は消せない。ほかの Cloudflare のサービスが無くても、単独で使える
そして、サーバー側での確かめ(Siteverify API)が必須です。Cloudflare の文書は、「ページに置く部品だけでは、フォームは守られない」と書いています。理由は次の 3 つです。
- トークン(確認を通った証になる文字列)は、偽れる。確認を解かずに、攻撃者が好きな文字列をフォームに送れる
- トークンは、作られてから 300 秒(5 分)で切れる
- トークンは、1 回しか確かめられない。同じトークンを 2 回送ると、
timeout-or-duplicateのエラーで拒まれる
サーバーからは https://challenges.cloudflare.com/turnstile/v0/siteverify に POST して確かめます。Turnstile は手元では流していません(サイトの鍵と秘密の鍵が要るため)。コードの書き方は、Cloudflare の文書を見てください。なお、Cloudflare は、Turnstile は利用者の入力(フォームに書いた中身など)を読まず、保存も送りもしない、と書いています(Cloudflare の自己申告です)。
数え方とヘッダー:標準で決まっていないこと
数え方(固定窓・スライディング窓・トークンバケット)に標準の定義は無い
「何回までか」をどう数えるかには、いくつかのやり方があります。ただし、数え方は、標準で決まっていません。 RFC 6585 は数え方を決めておらず(前に書いたとおりです)、あとで書く RateLimit ヘッダーの草案も、特定の数え方を求めていません。草案に「sliding window」の語は出てきます(サーバーが残りと窓の値を途中で変えてよい例など)が、定義は書かれていません。
以下は、一般的な説明です。HTTP の標準や、どれかの製品の仕様を決めたものではありません。どの方式が良いとも、書きません。
- 固定窓。 期間(たとえば 1 分)の頭で数を 0 に戻し、期間の中で数える、いちばん素朴なやり方です。Cloudflare の 2017 年のブログは、数が一定の間隔で戻されるので、急な波(スパイク)が制限をすり抜けてしまう、あまり正確ではないやり方だと説明しています
- 全部のリクエストの時刻を持つやり方。 正確に数えられますが、メモリと処理が重くなります。この記事の手元のサーバーは、このやり方です
- スライディング窓。 窓を少しずつずらしながら数えるやり方、という一般的な説明です。Cloudflare のブログは、前の期間の数で補う近似を紹介しています(前の期間が 42 回、今の期間が 15 秒の時点で 18 回なら、
42 × (60 − 15) / 60 + 18 = 49.5回、という式です) - トークンバケット。 決まった速さでトークンが増えて、バケット(入れ物)の大きさまで貯まります。リクエスト 1 つにつきトークンを 1 つ使い、トークンが無いときは断る、という一般的な説明です。「トークンバケット」の語が出る RFC の 1 つに RFC 2697(1999年9月。Informational)がありますが、ネットワーク機器のパケットの計測の話で、HTTP の API の定義ではありません
上の Cloudflare のブログ(2017年6月)は、文書(仕様)ではなくブログで、いまは使えない前の版の Rate Limiting を作ったときの記事です。いまの Rate limiting rules が同じ数え方だとは、いまの文書には書かれていません。いまの文書が書くのは、「ルールの数える単位の値の組ごとに、別の数を持つ」「数はデータセンターごと」までです。
RateLimit ヘッダーは、まだ標準ではありません
「あと何回使えるか」を、レスポンスのヘッダーで伝える書式が、IETF(インターネットの技術の標準を作る団体)の httpapi WG で検討されています。2026年10月時点で、これは RFC(標準)ではなく、Internet-Draft(作業中の草案) です。
- 草案の名前は draft-ietf-httpapi-ratelimit-headers。2026年10月21日に開いた時点の最新は -11(2026年5月23日。2026年11月24日に期限が切れます)
- 草案自身が、Internet-Draft は最長 6 か月の作業中の文書で、いつ書き換え・置き換えられてもよく、「作業中」として以外に引くのはふさわしくない、と書いています
- -10 には、HTTP の分野の早めの査読で、「Not ready」の評価が付いています(査読の中身は、開いていません)
つまり、「標準のヘッダー」ではありません。名前も書式も、変わるかもしれません。
草案が決めようとしているのは、2 つのヘッダーです。RateLimit-Policy が、サーバーが決めた割り当ての方針、RateLimit が、いまの方針で残っている割り当てです。草案の例は、次のような形です。
RateLimit-Policy: "permin";q=50;w=60,"perhr";q=1000;w=3600
RateLimit: "default";r=50;t=30
q は割り当て、w は窓の秒数、r は残り、t は残りの秒数です(草案 -11 の例。変わるかもしれません)。草案は、これは認可やアクセス制御のためのものではない、とも書いています。レートリミットは認可の代わりではない、という認証と認可の違いとは?にも書いた注意と同じ向きです。
使う側への決まりとして、RateLimit と Retry-After が両方あるときは、Retry-After が優先する(MUST)と書いてあります。残りが正の数でも、次のリクエストが通る保証ではない(MUST NOT assume)とも書いてあります。これも草案の決まりです。
草案の付録は、いまの Web では X-RateLimit-Limit・X-RateLimit-Remaining・X-RateLimit-Reset のような名前がよく使われていると書き、名前の揺れ(X-Rate-Limit-… など)や、同じ名前でも中身(秒・ミリ秒・UNIX 時刻・日時)が違う実装があるとも書いています。使う API の文書で、名前と意味を確かめてください。
自分の API で、標準として決まっているのは、429 と Retry-After です。RateLimit 系のヘッダーを付けるなら、草案であることを前提にしてください。
429 が出たとき(使う側)はどうする?
ここまでは作る側の話でした。使う側で 429 が出たときの話は、短く書きます。
- 429 は、「決まった時間に送りすぎた」という意味です。
Retry-Afterが付いていたら、その秒数(または日時)が過ぎるまで待ってから、送り直します。RateLimitヘッダーもあるときは、草案でもRetry-Afterが優先です - 503 にも
Retry-Afterが付くことがあります。一時的な過負荷や保守のときです - 草案は、使う側のふるまいとして、上限に近づいたら前もって速さを落とすことも、割り当てを使い切ってから待つことも、どちらでもよいと書いています。決まったふるまいを求めてはいません
- 待ち時間を延ばしながら再試行するやり方は、この記事では一次資料を確かめていないので、書きません。使う API の公式の文書を見てください
- Cloudflare のサイトで止められた訪問者向けには、Cloudflare に「error 1015」の文書があります(中身は、この記事では開いていません)
よくある質問
Cloudflare の無料プランで、ログインの失敗だけを数えられますか?
2026年10月21日に開いた公式の表では、できません。無料プランは、式に Method(POST など)を使えず、数え方を別の式にする(応答が 401・403 のときだけ数える)こともできません。Cloudflare の公式のログインの手本は、Business プラン以上が要ります。
Cloudflare が返す 429 には、Retry-After は付きますか?
確かめられませんでした。Cloudflare の文書は、block のときの状態コードを 400〜499 から選べて、既定は 429 だと書いていますが、Retry-After を付けるかどうかは、開いた文書に書かれていませんでした。公開中の Cloudflare のサイトに、大量のリクエストを送って確かめることはしていません。アプリ側で 429 を返すなら、Retry-After は自分で付けられます。
固定窓・スライディング窓・トークンバケットのどれを使えばよいですか?
どれが良い、とは書けません。HTTP のレートリミットとしての、標準の公式の定義は見つかりませんでした。この記事の手元のサーバーのやり方も、手元で選んだ書き方で、どれかの文書が勧める形ではありません。
- ログイン・パスワードの再設定・OTP の確認・SMS やメールを送る入口に、回数の制限を入れているか(→「レートリミットとは?何を制限するの?」)
- 回数だけでなく、アップロードの大きさ・1 回で返す件数・外のサービスへの支出の上限も決めているか(→「レートリミットとは?何を制限するの?」)
- 上限を超えたリクエストに 429 を返し、待つ秒数を
Retry-Afterで伝えているか(→「429 と Retry-After とは?」) - ログインの失敗の回数を、IP ではなく(IP だけに頼らず)、アカウントに結びつけて数えているか(→「ログインの失敗はどう数える?IP かアカウントか」)
- 締め出しの仕組みが、他人のアカウントを締め出す攻撃に使われないようになっているか(→「ログインの失敗はどう数える?IP かアカウントか」)
- Cloudflare の無料プランでできることを、公式の表で確かめたか。Turnstile を使うなら、サーバー側の確かめ(Siteverify)まで入れているか(→「Cloudflare で止めるには?無料プランでできること」)
- RateLimit ヘッダーを「標準のヘッダー」と思い込んでいないか。使う API の名前と意味を確かめたか(→「数え方とヘッダー:標準で決まっていないこと」)
- 429 が出たら、
Retry-Afterの秒数(または日時)まで待っているか(→「429 が出たとき(使う側)はどうする?」)
まとめ
- レートリミットは、決めた時間のあいだに、同じ相手から来るリクエストの回数を制限する仕組み。上限を超えたら 429(RFC 6585)で断り、
Retry-After(RFC 9110)で待つ時間を伝える。OWASP は回数だけでなく大きさ・件数・時間・支出も制限するよう書いていて、具体的な回数は書いていない - 手元の Python のサーバーでは、IP ごとに 60 秒に 3 回までにすると、4・5 回目が 429 と
Retry-After: 60になり、60 秒待つとまた 200 になった(確かめ用で、本番の形ではない) - ログインの失敗は、OWASP の言うとおりアカウントに結びつけて数える。IP ごとの数え方もあり、守るものが違う。締め出しを他人への攻撃に使わせない手当てが要る。NIST の 100 回は上限で、少なくしてよい(米国の政府向け)
- Cloudflare の無料プランは、2026年10月21日に開いた公式の表では、数える単位が IP だけ、Path だけで選ぶ、10 秒だけ数えるルール 1 つ。ログインの POST の失敗だけを数える手本は Business 以上。Turnstile は、サーバー側の確かめが必須
- 数え方に標準の定義は無く、RateLimit ヘッダーはまだ作業中の草案で、標準ではない(2026年10月時点)
Web 開発で点検することの全体は、Web 開発のセキュリティの基本にまとめています。
参考資料
この記事の内容は、2026年10月21日に開いた文書をもとにしています。OWASP の Cheat Sheet と Cloudflare の文書は、書き換わることがあります。
- OWASP API Security Top 10 2023: API4 Unrestricted Resource Consumption
- OWASP: Denial of Service Cheat Sheet・Authentication Cheat Sheet・REST Security Cheat Sheet
- RFC 6585(429 Too Many Requests)
- RFC 9110: HTTP Semantics(Retry-After・503)
- IETF Internet-Draft: RateLimit header fields for HTTP(作業中の草案)
- RFC 2697(トークンバケットの語が出る、ネットワーク機器のパケットの計測の RFC)
- NIST SP 800-63B-4(3.2.2 Rate Limiting (Throttling))
- Cloudflare: Rate limiting rules・Request rate calculation・Rate limiting parameters・Rate limiting best practices
- Cloudflare: Turnstile・Turnstile Plans・Validate the token
- Cloudflare ブログ(2017年6月): How we built rate limiting capable of scaling to millions of domains
※この記事は、公式の資料をもとに AI(Claude)で下書きし、2026年10月21日時点の公式の資料と照らして確かめてから公開しています。誤りに気づいたらお問い合わせからお知らせください。



