API のヘッダーとアクセス数制限

OWASP Secure Headers Project・RFC 6648・IETF RateLimit Header Fields を 取得して書いたもの。この2つの主題は推奨が動いたため、原典に当たり直してある。

エンドポイント・レスポンス・ステータスコードの設計は API 設計 にある。

ヘッダー

この節は 2026-08-31 に OWASP Secure Headers Project を取得して更新した。 元のノートにあった推奨のうち2つが、現在では非推奨になっていたため。

目的ヘッダ
HTTPS の強制Strict-Transport-Security: max-age=63072000; includeSubDomains
読み込み先の制限Content-Security-Policy: script-src 'self'
MIME 推測の禁止X-Content-Type-Options: nosniff
クリックジャッキング対策X-Frame-Options: deny
リファラの制御Referrer-Policy: no-referrer
クロスドメインポリシーの制限X-Permitted-Cross-Domain-Policies: none
ログアウト時のデータ削除Clear-Site-Data: "cache","cookies","storage"
キャッシュによる露出の防止Cache-Control: no-store, max-age=0
DNS 先読みの停止X-DNS-Prefetch-Control: off
ブラウジング文脈の隔離Cross-Origin-Opener-Policy: same-origin
資源の保護Cross-Origin-Resource-Policy: same-origin
埋め込みの制限Cross-Origin-Embedder-Policy: require-corp

Content-Security-Policy は、読み込んだ HTML 内の IMG・SCRIPT・LINK 要素などについて、 どこからの読み込みを許可するかを指定するヘッダ。

Permissions-Policy(旧 Feature-Policy)はまだ策定中。

-Report-Only 系があるものは、遮断せずに違反だけ報告させて試せる。 Content-Security-Policy-Report-Only など。

独自ヘッダに X- を付けない

新しく作るヘッダに X- を付けない(RFC 6648)。

新しいパラメータを作る者は、名前に X- やそれに類する接頭辞を付けるべきではない。

理由が実際に起きたことに基づいている。 実験的なパラメータは、そのうち事実上の標準になる。 後から標準化されると同じものに2つの名前が並び、 古い実装が元の名前を使い続けるので、新しい実装は両方を支え続けることになる。

上の X-RateLimit-* から RateLimit への移行が、まさにこの形。

受け取る側の規則もある。 X- が付いているかどうかだけで、標準か非標準かを判断してはならない。

既にある X- ヘッダを使うな、という話ではない。 RFC は既存の非標準パラメータについては何も推奨していない。 だから X-Content-Type-OptionsX-Frame-Options は、そのまま使う。

使ってはいけないもの

元のノートに載っていた推奨が、現在では反転している。

ヘッダ現状
X-XSS-Protection非推奨。有効にすると、かえってクライアント側に問題を持ち込みうる。 0 にして無効化し、CSP で守る
Public-Key-Pins(HPKP)非推奨。下記
Expect-CTほぼ役目を終えた。2018年5月以降の証明書は既定で SCT に対応している
Feature-PolicyPermissions-Policy に置き換わった
PragmaHTTP/1.0 の遺物。Cache-Control を使う

X-XSS-Protection: 1; mode=block は、長く「XSS 対策」として書かれてきた。 現在はそう扱わない。古い資料をそのまま写すと、この種の反転を取り込む。

SSL 証明書が偽造されていないかのチェック

証明書の内容のハッシュ値と有効期限を記録しておき、以降のアクセスでそのハッシュ値を使って 証明書が正しいものか判別する仕組み。

Public-Key-Pins: max-age=2592000;
          pin-sha256="E9CZ9INDbd+2eRQozYqqbQ2yXLVKB9+xcprMF+44U1g=";
          pin-sha256="LPJNul+wow4m6DsqxbninhsWHlwfp0JecwQzYpOLmCQ="

この方式は使わない。 主要ブラウザが対応をやめている。

やめた理由が仕組みそのものにある。 鍵を失ったり、誤った値を固定したりすると、自分のドメインに自分で到達できなくなる (HPKP Suicide)。攻撃者に固定値を仕込まれる形の脅迫も想定された。 間違えたときに自力で回復できない設計だった。

記録として残すが、新規に採用するものではない。

属性効果
Secureそのクッキーは HTTPS の通信のときだけサーバーに送り返される
HttpOnlyそのクッキーは HTTP の通信でのみ使われ、JavaScript からアクセスできない。XSS でセッション情報が読み出されるのを防げる

SameSite__Host- プレフィックスを含めた全体は セッション管理にある。

アクセス数制限

この節は 2026-08-31 に IETF の RateLimit Header Fields を取得して更新した。 X-RateLimit-* の3本組は標準化の過程で2本に置き換わっている。

標準化されたヘッダ

2つある。役割が違う。

ヘッダ何を伝えるか変化
RateLimit-Policyどういう制限方針か(静的・準静的)応答をまたいで一定であるべき
RateLimitいまの残量(動的)リクエストごとに変わりうる
RateLimit-Policy: "burst";q=100;w=60,"daily";q=1000;w=86400
RateLimit: "default";r=50;t=30

RateLimit-Policy の項目は q(割り当て量)が必須で、 qu(単位。既定は requests)、w(窓の秒数)、pk(分割キー)が任意。 RateLimitr(残量)が必須で、t(リセットまでの秒数)と pk が任意。

残量が正でも、次が通る保証にはならない。 仕様がそう明言している。

なぜ置き換わったか

古い3本組は名前が同じでも意味が揃っていなかった。

X-RateLimit-Reset が、ある実装では窓が切れるまでの秒数、 別の実装ではミリ秒UNIX 時刻日時を指していた。 同じ名前で違うものを返すので、クライアントが一律に解釈できない。

これは結合の度合いでいう意味の連鎖そのもので、 「複数の要素が、ある値の意味について合意していること」が成立していなかった。

状態コードとの関係

HTTP/1.1 429 Too Many Requests
Retry-After: 3600

429 は例示であって必須ではない。 403 を使う実装もある。 サーバーは状態コードによらず RateLimit を返してよい。

両方返す場合、クライアント側では Retry-After が優先される。 サーバー側は、RateLimittRetry-After同じ時点を指すようにする。

実装

利用者やアプリケーションごとのアクセス回数を数えておく必要があり、 通常は Redis などの KVS に記録する。

同じ問題への別の入口が分散システムにある。 レートリミットは、過負荷を受け止める手段の1つ。

関連