レート制限 — 誰を、どの単位で、どこで止めるか
ログインに IP ごとの制限をかけたら、同じ会社の社員がまとめて締め出され、数千の IP に散らばった攻撃は素通りした。制限の強さより先に、何を1人と数えるかを決める。
この記事の進み方
What — 何を「1人」と数えるか
レート制限は、ある単位ごとに、一定時間あたりのリクエスト数に上限を設け、超えたら断る仕組みです。
上限の数字より先に決めるべきなのは、何を単位に数えるかです。単位を間違えると、どんな数字にしても、止めたいものは止まらず、止めたくないものが止まります。
| 単位 | 数えやすさ | 困る場面 |
|---|---|---|
| IP アドレス | ログイン前でも数えられる | 1つの IP の後ろに大勢がいる(会社、携帯回線)。攻撃は IP を散らせる |
| ログインした利用者 | 正確 | ログイン前の API には使えない |
| API キー | 契約単位で公平にできる | キーが漏れれば、他人の枠を使われる |
| 対象のアカウント | ログインの総当たりに効く | 攻撃者が他人のアカウントをわざと締め出せる |
| サービス全体 | 自分たちを守れる | 誰が原因かに関係なく、全員が断られる |
冒頭の事故は、「利用者を区別したい」のに「IP」で数えていたことから来ています。
- 429 Too Many Requests
- 上限を超えたことを伝えるステータスコード。待てば通る、という意味を含む。
- Retry-After
- 何秒後に再試行してよいかを伝えるヘッダー。
- トークンバケット
- 一定の速さで補充されるトークンを1回ごとに1つ使う方式。短い集中を許しつつ、平均の速さを抑える。
- クレデンシャルスタッフィング
- 他で流出した ID とパスワードの組を、別のサービスで大量に試す攻撃。
数え方でも、通る量が変わる
同じ「毎分100回」でも、どう数えるかで実際に通る量が変わります。
毎分0秒で数え直す
12:00:00〜12:00:59 で 100 回 → 12:01:00 に 0 へ戻る- 作りやすさ
- 最も簡単
- 記憶する量
- 単位ごとに数値1つ
- 区切り目
- **前後1秒で最大2倍通る**
- 向いている場面
- 多少の集中は構わない、大まかな制限
- –12:00:59 に100回、12:01:00 に100回で、2秒間に200回通る
- –区切りの直後に一斉にリクエストが来る、という偏りも生みやすい
- –日単位の上限(クォータ)なら、この粗さで困らないことが多い
上限の数字が同じでも、区切り目の扱いで、短い時間に通る量が倍になることがある。守りたいのが「1分あたりの平均」なのか「瞬間の集中」なのかで選ぶ。
「毎分100回まで」を、毎分0秒で数え直す方式で制限しています。12:00:59 に100回、12:01:00 に100回のリクエストが届きました。この2秒間で、何回が通りますか?
Why — なぜ単位を1つに決められないのか
レート制限には、目的が少なくとも3つあり、それぞれ適切な単位が違います。
- 自分たちのサービスを守る — 誰が送ってきたかに関係なく、処理しきれない量を断る。単位はサービス全体や API ごと
- 利用者どうしを公平にする — 1人の使いすぎで他の人が遅くならないようにする。単位は利用者や API キー
- 悪用を止める — 総当たりや大量取得を止める。単位は狙われているもの(ログインならアカウント)と、送ってくる元(IP)の両方
冒頭の制限は「悪用を止める」ために入れたのに、単位が IP だけでした。IP は送ってくる元の目安にはなりますが、1つの IP の後ろに何百人もいることも、1人の攻撃者が数千の IP を使うこともあります。
ログインでは「締め出し」が武器になる
ログインの総当たりを防ぐために、アカウントごとに失敗5回でロックするのはよくある対策です。これは総当たりには効きますが、別の攻撃を可能にします。
攻撃者は、他人のアカウントにわざと5回間違えたパスワードを送るだけで、その人をログインできなくできます。メールアドレスの一覧さえあれば、全員を締め出せます。
アカウントごとの上限は、ロックではなく遅延にするほうが安全です。失敗が続くほど次の試行までの待ち時間を伸ばし、正しいパスワードでの成功で解除する。追加の確認(メールでの確認コードなど)を求める手もあります。
台数ぶん、上限が増える
API のサーバーが複数台あるとき、回数を各サーバーのメモリで数えると、上限は台数ぶん増えます。ロードバランサがリクエストを振り分けるので、それぞれのサーバーは全体の一部しか見ていないからです。
上限: 毎分100回、サーバー5台、各サーバーのメモリで数える
→ 各サーバーが「100回まで」を許すので、全体では最大 500回
複数台で正確に数えるには、回数を共有の置き場所(キャッシュ用の高速なストア)で数えるか、全台の手前(ゲートウェイ、CDN)で数えます。
API サーバーが5台あり、各サーバーのメモリ上で「API キーごとに毎分100回まで」を数えています。ロードバランサは均等に振り分けます。1つの API キーで、実際に毎分何回まで通りますか?
演習 — まず自分で判断する
解説を読む前に、まず自分で判断してみてください。ここで一度詰まっておくと、 次の節の判断軸が「なるほど」ではなく「そう来たか」に変わります。
ログイン API の制限を、どう設計し直しますか?
- 法人向けのサービスで、同じ会社の社員が同じ出口の IP から使うことが多い
- 他で流出したパスワード一覧を使った試行が、数千の IP から少しずつ来ている
- 特定の人を狙った総当たりも、過去に1度あった
- 利用者の多くは始業時刻に一斉にログインする
- ログインの処理は、パスワードの照合に意図的に時間をかけている(1回あたり数百ミリ秒)
- · IP・アカウント・サービス全体の、どの単位で何を止めるか
- · 攻撃者が制限そのものを悪用できないか
- · 正しい利用者が巻き込まれたとき、何が起きるか
「うちの会社の社員だけ、朝ログインできない」という問い合わせを受けたサポート担当者に、何が起きていたかを説明してください
- 相手は IP アドレスという言葉は知っているが、会社のネットワークの仕組みには詳しくない
- 開発側で制限の設計を直すまで、数日かかる
- 問い合わせてきた会社に、どう伝えるかを知りたがっている
読み終わりましたか?
読了にすると、これを前提とする記事がロードマップで開放されます。