仕組みから学ぶ Web
応用読了目安 14#レート制限#429#トークンバケット#ログイン#分散システム

レート制限 — 誰を、どの単位で、どこで止めるか

ログインに IP ごとの制限をかけたら、同じ会社の社員がまとめて締め出され、数千の IP に散らばった攻撃は素通りした。制限の強さより先に、何を1人と数えるかを決める。

この記事の進み方

What — 何を「1人」と数えるか

レート制限は、ある単位ごとに、一定時間あたりのリクエスト数に上限を設け、超えたら断る仕組みです。

上限の数字より先に決めるべきなのは、何を単位に数えるかです。単位を間違えると、どんな数字にしても、止めたいものは止まらず、止めたくないものが止まります。

単位数えやすさ困る場面
IP アドレスログイン前でも数えられる1つの IP の後ろに大勢がいる(会社、携帯回線)。攻撃は IP を散らせる
ログインした利用者正確ログイン前の API には使えない
API キー契約単位で公平にできるキーが漏れれば、他人の枠を使われる
対象のアカウントログインの総当たりに効く攻撃者が他人のアカウントをわざと締め出せる
サービス全体自分たちを守れる誰が原因かに関係なく、全員が断られる

冒頭の事故は、「利用者を区別したい」のに「IP」で数えていたことから来ています。

429 Too Many Requests
上限を超えたことを伝えるステータスコード。待てば通る、という意味を含む。
Retry-After
何秒後に再試行してよいかを伝えるヘッダー。
トークンバケット
一定の速さで補充されるトークンを1回ごとに1つ使う方式。短い集中を許しつつ、平均の速さを抑える。
クレデンシャルスタッフィング
他で流出した ID とパスワードの組を、別のサービスで大量に試す攻撃。

数え方でも、通る量が変わる

同じ「毎分100回」でも、どう数えるかで実際に通る量が変わります。

Compare数え方

毎分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秒間で、何回が通りますか?

まず選ぶ(解答例は a〜d の記号で説明します)

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 キーで、実際に毎分何回まで通りますか?

まず選ぶ(解答例は a〜d の記号で説明します)

演習 — まず自分で判断する

解説を読む前に、まず自分で判断してみてください。ここで一度詰まっておくと、 次の節の判断軸が「なるほど」ではなく「そう来たか」に変わります。

演習 — 設計判断を問う

ログイン API の制限を、どう設計し直しますか?

与えられた条件
  • 法人向けのサービスで、同じ会社の社員が同じ出口の IP から使うことが多い
  • 他で流出したパスワード一覧を使った試行が、数千の IP から少しずつ来ている
  • 特定の人を狙った総当たりも、過去に1度あった
  • 利用者の多くは始業時刻に一斉にログインする
  • ログインの処理は、パスワードの照合に意図的に時間をかけている(1回あたり数百ミリ秒)
この軸で考える
  • · IP・アカウント・サービス全体の、どの単位で何を止めるか
  • · 攻撃者が制限そのものを悪用できないか
  • · 正しい利用者が巻き込まれたとき、何が起きるか
まず選ぶ(解答例は a〜d の記号で説明します)

演習 — 説明できるか

「うちの会社の社員だけ、朝ログインできない」という問い合わせを受けたサポート担当者に、何が起きていたかを説明してください

与えられた条件
  • 相手は IP アドレスという言葉は知っているが、会社のネットワークの仕組みには詳しくない
  • 開発側で制限の設計を直すまで、数日かかる
  • 問い合わせてきた会社に、どう伝えるかを知りたがっている

読み終わりましたか?

読了にすると、これを前提とする記事がロードマップで開放されます。