Appearance
公開スケジュールAPI レート制限(Cloudflare)
目的
公開スケジュールAPIの濫用(連打・大量作成/削除)を抑止する。
対象
- パス: /api/v1/public/candidates//schedules
- メソッド: POST, DELETE
アプリ側レート制限(有効)
Cloudflare Free では method や host 条件が使えず WAF の Rate Limiting が想定通り動かないため、 アプリ側(Hono ミドルウェア)で IP ベースのレート制限を実装している。
しきい値
- 20 / 1 minute
- 100 / 1 day
仕組み
- インメモリ Map で IP ごとにカウント
- どちらかが上限超過で 429
Retry-Afterを返す- 上限超過時は
SECURITY_EVENTログを出力する(PUBLIC_SCHEDULE_RATE_LIMITED)
緊急遮断(アプリ側)
公開スケジュールAPIの異常時に挙動を切り替えるための環境変数を用意する (Cloud Run ではリビジョン更新が必要)。
PUBLIC_SCHEDULE_MUTATIONS_DISABLED=truePOST/DELETE /api/v1/public/candidates/:token/schedules*を 503 で停止
PUBLIC_TOKEN_BLOCKLIST=<token1>,<token2>,...- 指定トークンの
/api/v1/public/candidates/:token*を 403 で遮断
- 指定トークンの
いずれも発火時に SECURITY_EVENT ログを出力する。
Cloudflare レート制限(Free では不十分)
Free プランでは method / host 条件が使えず、公開APIだけに限定できないため採用しない。
検証
UI上の失敗通知と Slack 連携まで含めたE2E確認は以下を参照:
docs/security/mypage-slack-notification-e2e.md
1. curl 連打(POST)
以下のリクエストを 21 回以上送る(400 でも可。レート制限の発火が目的)。
curl -s -o /dev/null -w "%{http_code}\n"
-X POST "https://buson.notari.co.jp/api/v1/public/candidates/<public_token>/schedules"
-H "Content-Type: application/json"
-d '{"start_time":"2026-02-09T10:00:00","end_time":"2026-02-09T11:00:00"}'
21回目以降で 429 を確認する。
2. Cloudflare Events
アプリ側のため Cloudflare Events は対象外。必要ならアプリログで確認する。