RFC 6265: Cookie
Cookieの仕様をRFC 6265で精読し、Domainが範囲を広げる指定である理由、Pathやポートが安全境界にならない事情、SameSiteが6265に無い経緯までを押さえ、セッション設計の誤解を解ける。
- RFC 6265は、1994年にNetscapeが実装したCookieを17年越しに文書化した規格。理想の設計を示した先行のRFC 2109/2965は市場に無視され、ブラウザが既にやっていた現実を追認した珍しい仕様である。
- サーバーはCookieごとにSet-Cookieを送り、ブラウザは名前と値だけをCookieヘッダで返す。Domain省略時は当該ホスト限定、指定時はサブドメインにも広がる。ポートは無視され、Pathも安全な隔離境界ではない。
- SameSiteはRFC 6265に存在しない。__Host-接頭辞や400日の寿命上限とともに改訂版6265bis(ドラフト)にあり、Chromeは2020年にLax既定を出荷済み——実装が規格の公開を10年近く追い越したままだ。
このRFCが決めたこと
横にスクロール
RFC 6265(2011年4月、Adam Barth)は、ステートレスなHTTPの上に状態を載せるCookieの仕組みを定めた文書だ。ただし他のRFCと決定的に違う点がある。この文書はCookieを設計していない。1994年にNetscape Navigatorが実装し、以来ブラウザが互換性のために積み上げてきた挙動を、後から観察して書き起こしたものだ。
整った設計の試みが無かったわけではない。RFC 2109(1997年)とRFC 2965(2000年)は、Set-Cookie2とCookie2という新しいヘッダを用意し、曖昧さの少ない状態管理を定義していた。だが市場はこれを実装せず、Webは古いNetscape方式を使い続けた。RFC 6265はこの現実を受け入れ、RFC 2965を廃止してSet-Cookie2/Cookie2を非推奨とし、既に2965に廃止されていたRFC 2109についてはHistoricへの移行を求めた。標準化が実装を導くのではなく、実装が標準化を屈服させた事例だと言える。
この出自は仕様の随所に痕跡を残している。日付の解析規則は「規格上正しい形式」ではなくブラウザが実際に受け付ける形を追認した寛容なアルゴリズムだし、セキュリティ考慮事項の8節は、Cookieが何を守れないかを異例の率直さで列挙している。
6265を読むときの構えは他のRFCと逆になる。「なぜこう設計したのか」を探しても答えは無い。「1994年の実装がこうだったから」が答えである場面が多い。仕様の不合理は、たいてい互換性の化石だ。
要点の精読
Set-CookieとCookieは対称ではない
サーバーはレスポンスでCookieを1つずつ、それぞれ独立したSet-Cookieヘッダに載せて送る。
HTTP/1.1 200 OK
Content-Type: text/html
Set-Cookie: sid=abc123; Domain=example.com; Path=/; Secure; HttpOnly
Set-Cookie: theme=dark; Max-Age=31536000; Path=/
複数のCookieを1本のヘッダにまとめてはならない。Expiresの日付が「Sun, 06 Nov 1994 08:49:37 GMT」のようにカンマを含むため、カンマ区切りのリストとして畳むと壊れるからだ。結果としてSet-Cookieは、同名ヘッダをカンマで結合できるというHTTPの一般規則から外れる代表的な例外になっている(この結合規則そのものはRFC 9110: HTTPセマンティクスが定めており、9110自身がSet-Cookieを例外として名指ししている)。
そしてブラウザが返すリクエストは、こうなる。
GET /account HTTP/1.1
Host: shop.example.com
Cookie: sid=abc123; theme=dark
ここが最初の落とし穴だ。戻ってくるのは名前と値だけで、属性は一切戻らない。 サーバーは自分が付けたDomainもPathもSecureも受け取れない。つまりサーバーから見ると、そのsidがexample.com向けに設定したものなのか、攻撃者が別の経路で仕込んだものなのかを、Cookieヘッダだけでは区別できない。属性は送信するかどうかをブラウザが判断するための材料であって、サーバーへの申告ではない。
さらに、同じ名前のCookieがDomainやPathの違いで複数存在しうる。その場合ブラウザは両方を送る。
Cookie: sid=attacker; sid=abc123
RFC 6265の5.4節は、パスの長いCookieを先に並べることを推奨しているが、あくまでSHOULDであり、サーバー側にはどちらがどの範囲のCookieなのか判定する手段が無い。多くのフレームワークは素朴に最初の値を採用するため、この曖昧さがそのまま攻撃面になる。
Domainは範囲を狭める指定ではなく、広げる指定
Domain属性の直感は、ほぼ全員が最初に間違える。
- Domainを省略すると、host-only-flagが立ち、そのホストと完全一致する場合にのみ送られる。これが最も狭い。
- Domainを指定すると、host-only-flagが下り、指定ドメインとその全サブドメインに送られる。こちらが広い。
Domain=example.com は「example.comに限定する」ではなく「example.comとwww、shop、blog、そして誰かが立てた任意のサブドメイン全部に配る」を意味する。範囲を絞りたくて書いた一行が、実際には範囲を最大化している。
先頭のドットは意味を持たない。5.2.3節は、属性値の先頭が「.」なら取り除くと定めており、Domain=.example.com と Domain=example.com は完全に同じ挙動になる。RFC 2109ではドットの有無が意味を持ったが、6265はブラウザの実態に合わせてこれを捨てた。古い記事がドットに意味を持たせて説明していたら、それは2109時代の知識だ。
無制限に広げられるわけではなく、2つの歯止めがある。1つは、Domainがリクエスト元ホストにdomain-matchしなければCookieが破棄されること。shop.example.comは Domain=example.com を設定できるが、Domain=other.com は設定できない。もう1つがpublic suffixの拒否で、誰かが Domain=com や Domain=co.jp を指定して全世界にCookieを配ることを防ぐ。
public suffixの判定に使われるPublic Suffix Listは、RFCではない。Mozillaが管理するpublicsuffix.orgの一枚のテキストファイルであり、6265はこれを規範的に定義せず、5.3節の注記で事実上参照するにとどまる。「どこまでが組織の境界か」というWebの基礎的な線引きが、標準化過程の外にあるコミュニティ管理のリストに委ねられている。しかも同じ5.3節は、public suffixの拒否を「ユーザーエージェントがそう設定されているなら」という条件付きで書いている。
Path、ポート、スキームは境界にならない
Cookieの分離能力について、RFC 6265は8.5節「Weak Confidentiality」で自らの限界を認めている。
| 分離の軸 | RFC 6265での扱い | 帰結 |
|---|---|---|
| ホスト | Domainでサブドメインごと共有される | サブドメイン1つの侵害が全体へ波及する |
| ポート | 完全に無視される(8.5節) | 同一ホストの別ポートのアプリと共有される |
| スキーム | 隔離しないと明記(8.5節) | httpとhttpsが同じCookie空間を使う |
| パス | 送信のフィルタにすぎない(8.5節) | 同一ホストの別パスからJSで読み出せる |
| Secure属性 | 機密性のみを守る(8.6節) | 非セキュアな出自からの上書きを防げない |
Pathについて8.5節は「一部のユーザーエージェントは非HTTPのAPIでCookieを公開しており、異なるパスから受け取ったリソースを隔離しないため、あるパスのCookieに別のパスからアクセスできることがある」という趣旨を述べている。ブラウザの同一生成元ポリシーはパスを見ないので、/a/ のページは /b/ 用のCookieを、iframeとdocument.cookieを経由して読める。Pathが決めるのは「どのリクエストに載せるか」だけで、「誰が読めるか」ではない。認可の境界としては使えない。
ポートについては「あるポートで動くサービスから読めるCookieは、同じサーバーの別のポートで動くサービスからも読める」と明言されている。localhost:3000とlocalhost:8080が開発中にCookieを踏み合うのは、実装のバグではなく仕様どおりの挙動だ。
そして8.6節「Weak Integrity」が最も重要な告白をしている。Secure属性について、この節は「能動的なネットワーク攻撃者からCookieを守るのに有用に見えるが、Secure属性が守るのはCookieの機密性だけである」と述べる。Secureが保証するのはHTTPS以外で送信されないことだけで、HTTPの経路からSecure Cookieを上書きされないことは保証しない。同じホストの平文HTTPページや中間者は、Secure付きのセッションCookieを好きな値に差し替えられた。同じ節は、foo.example.comが Domain=example.com のCookieを設定してbar.example.comのCookieを上書きできることも指摘している。これがcookie tossingやshadowingと呼ばれる、兄弟サブドメインを踏み台にした攻撃の根拠だ。
この整合性の穴は6265本体では塞がれず、後年のdraft-ietf-httpbis-cookie-alone(「Secure Cookieを放っておけ」)が担当した。Chrome 52とFirefox 52が2016年に実装し、非セキュアな出自からのSecure Cookie設定・上書きを禁止している。この規則は現在6265bisの保存モデルに取り込まれているが、6265だけを読んでいると、いまだに存在しない防御を期待することになる(TLS側の前提はRFC 8446: TLS 1.3を参照)。
有効期限、HttpOnly、そして上限値
寿命を決める属性は2つあり、優先順位がはっきり決まっている。4.1.2.2節は「CookieがMax-AgeとExpiresの両方を持つ場合、Max-Ageが優先し、有効期限を決定する」と定める。どちらも無ければセッションCookieとなり、永続化されない。Max-Ageが0以下なら即時失効で、これがCookie削除の常套手段だ。
Expiresの解析規則(5.1.1節)は、この仕様の性格をよく表している。厳密な日付形式を要求するのではなく、区切り文字を読み飛ばしながら数字らしきものを拾う寛容なアルゴリズムが延々と書かれている。ブラウザが実際に受理してきた雑多な日付表記を追認するには、こうするしかなかった。
HttpOnlyは4.1.2.6節の属性で、document.cookieのような非HTTPのAPIからCookieを隠す。XSSでセッションCookieを盗み出す典型的な手口を潰せるので効果は大きい。ただし守備範囲を誤解しやすい。
HttpOnlyが防ぐのはスクリプトによるCookieの読み出しであって、Cookieの自動送信ではない。他サイトからのリクエストにもブラウザはCookieを律儀に添付するため、CSRFはHttpOnlyを付けても成立する。盗まれないことと、勝手に使われないことは別問題だ。CSRFを止めるにはトークンか、6265の外にあるSameSiteが要る。
容量の上限は6.1節にある。1Cookieあたり4096バイト以上(名前・値・属性の合計で測る)、1ドメインあたり50個以上、合計3000個以上を、ユーザーエージェントは扱えるべきだとされる。ここは「最低限これだけは対応せよ」という下限の要求であって、ブラウザが強制する上限ではない点に注意したい。実際に送られるSet-Cookieを確かめたいときはHTTPヘッダ解析で手元のレスポンスを覗くのが早い。
6265に無いもの、そして6265bisという長い宿題
ここが本題かもしれない。SameSiteはRFC 6265に一文字も登場しない。
SameSiteは2016年の別の提案(draft-west-first-party-cookies)から生まれ、Chrome 51が同年に実装した。属性を書かなければ従来どおり全てのクロスサイトリクエストにCookieが載る、という既定は長く変わらなかったが、Chromeは2020年2月17日の週からChrome 80でLax既定の展開を開始する。ところが同年4月3日、COVID-19下でのサービス安定性を理由に展開が巻き戻され、7月に再開されて年内に定着した。あわせて SameSite=None にはSecureが必須という規則も入っている。
この一連の変更を収容する先が改訂版のdraft-ietf-httpbis-rfc6265bisだ。draft-00は2016年10月10日(Adam BarthとMike West)に出ている。現在までに入った主な内容は次のとおり。
- SameSite属性(Strict / Lax / None)。属性が無い場合の既定の強制モードはLax相当だが、互換のための「Lax-allowing-unsafe」という緩和モードが任意で認められている。
__Secure-と__Host-の名前接頭辞。__Secure-はSecure必須。__Host-はSecure必須かつPath=/かつDomain属性を持たないことを要求する。前述した「サーバーは属性を受け取れない」問題への、名前に制約を埋め込むという実用的な回答だ。- Secure Cookieを非セキュアな出自から上書きすることの禁止(cookie-alone由来)。
- 明確なサイズ上限。名前と値の合計は4096オクテット、1つの属性値は1024オクテットを超えたら破棄する。6265の6.1節が「対応すべき下限」を書いていたのに対し、こちらは規範的な上限になっている。
- 有効期限の上限。ExpiresやMax-Ageが上限より長い寿命を指定した場合は上限まで切り詰めなければならず、その上限は400日(34560000秒)を超えるべきでないとされる。
そして状態が、この記事の主題を象徴している。2026年7月時点で最新版はdraft-22(2025年12月1日)で、IESGの承認を経てRFC Editor Queueに入った段階にあり、まだRFCとして発行されていない。文書の表紙には今も「Obsoletes: 6265 (if approved)」と条件付きで書かれたままだ。2016年10月に始まった改訂は10年近く公開に至らず、その間にブラウザは仕様を実装し、既定を変え、Webの挙動を確定させてしまった。1994年の実装を2011年に追認した文書が、2016年の実装を2026年になっても追認しきれていない。
6265bisの発行状態は動いている最中だ。RFC Editor Queueにある文書は、通常そのまま発行される見込みが高いが、RFC番号が付くまで確定ではない。実装の可否を判断するときは、規格の発行状態ではなく、対象ブラウザの実際の挙動を基準にするのが安全だ。
なお、6265bisに入っていないものもある。CHIPSとして知られる Partitioned 属性は6265bisの本文には無く、別の仕様として扱われている。またCookieをスキームやポートに束縛する仕組み(source schemeやsource portをCookieごとに保存する方式)も、draft-22の保存モデルには入っていない。同節が列挙するCookieの保存フィールドは、name、value、expiry-time、domain、path、creation-time、last-access-time、persistent-flag、host-only-flag、secure-only-flag、http-only-flag、same-site-flagであり、スキームもポートも含まれない。スキームを考慮するsame-site判定(schemeful same-site)は6265bisが外部のsame-site定義を参照する形で成立しており、6265bis自身が定義しているわけではない。ポートを無視するという1994年からの性質は、いまも生きている。
サードパーティCookieの行方も、単純な廃止物語にはならなかった。SafariとFirefoxは既定でサードパーティCookieを遮断しているが、Googleは2025年4月22日、Chromeでサードパーティを廃止せず、専用の選択プロンプトも導入しないと表明した。さらに2025年10月17日にはPrivacy Sandboxの多くの技術を退役させ、CHIPS、FedCM、Private State Tokensなど少数に絞る方針を示している。2026年7月時点のChromeにサードパーティCookieは残っている。代替手段としては、自動送信されないぶんCSRFに強いBearerトークン(RFC 6749: OAuth 2.0)や、JSから読めるためXSSに弱いlocalStorageがあるが、どれもCookieを一方的に置き換える性質のものではない。
つまずきやすい点
まずDomainの方向を逆に覚えないこと。範囲を絞りたいならDomain属性を書かないのが正解で、書いた瞬間に全サブドメインへ広がる。狭めたつもりの一行が最大の露出を作る。
次に、Lax既定を前提に設計しないこと。これはChromium系の挙動であって、6265が定めた既定でも全ブラウザ共通の挙動でもない。6265bis上も、属性が無い場合はLax相当としつつ緩和モードを認めている。クロスサイトの送信可否に依存するなら、SameSiteを明示的に書くしかない。
セッションCookieがブラウザを閉じても消えるとは限らない。永続化しないという仕様上の意図に対し、多くのブラウザはセッション復元機能を持っており、再起動後もセッションCookieが生き残ることがある。ログアウトの実装をブラウザの終了に期待してはいけない。
HttpOnlyをCSRF対策と数えないこと。Secureを整合性の保証と数えないことも同様だ。6265は8.6節で「Secureが守るのは機密性だけ」と自ら書いている。
最後に、同名Cookieの曖昧さを侮らないこと。サーバーは属性を受け取れないため、どのDomainやPathから来た値なのかを判定できない。ここに効く実務上の答えが __Host- 接頭辞で、名前そのものに「host-onlyかつSecureかつPath=/」という制約を焼き込むことで、サーバーが名前を見ただけで出自を絞り込めるようにしている。Cookieの設計としては後付けの応急処置だが、6265の非対称性が抱えた欠陥に対する現実的な回答になっている。セキュリティ全般の整理はセキュリティから辿れる。
まとめ
RFC 6265は、1994年のNetscapeの実装を2011年に追認した文書であり、理想の設計ではなく現実の記録だ。だからこそ、Domainが範囲を広げること、Path・ポート・スキームが境界にならないこと、Secureが機密性しか守らないことといった不合理が、仕様自身の口から率直に語られている。押さえるべきは、属性はサーバーへ戻らないという非対称性、Domainの向き、そしてSameSiteや __Host- が6265の外側にあるという構図だ。6265bisは2026年7月時点でRFC Editor Queueに留まり、実装が規格を10年先行し続けている。この「規格より実装が先にある」状態こそ、Cookieというレイヤーの本質を最もよく表している。他のRFC解説はRFC精読から辿れる。
RFC精読の記事ガイド
RFC 6265: Cookieを実務で読む
TL;DRは入口です。実際に選ぶ・使う段階では、何を解決するか、何と比較するか、導入後にどこで詰まるかまで見る必要があります。
解決すること
RFC
比較で見る軸
難易度: advanced / カテゴリ: RFC精読 / タグ数: 5
導入後に効く点
サーバーはCookieごとにSet-Cookieを送り、ブラウザは名前と値だけをCookieヘッダで返す。Domain省略時は当該ホスト限定、指定時はサブドメインにも広がる。ポートは無視され、Pathも安全な隔離境界ではない。
先に潰すリスク
用語だけ覚えても、設計・実装・運用でどこに効くかを確認しないと判断を誤る。
- 難易度
- advanced
- カテゴリ
- RFC精読
- タグ数
- 5
判断チェックリスト
- 自社の用途が「RFC / Cookie」に近いか確認する。
- 強みである「RFC 6265は、1994年にNetscapeが実装したCookieを17年越しに文書化した規格。理想の設計を示した先行のRFC 2109/2965は市場に無視され、ブラウザが既にやっていた現実を追認した珍しい仕様である。」が本当に評価軸になるか確認する。
- 注意点の「用語だけ覚えても、設計・実装・運用でどこに効くかを確認しないと判断を誤る。」を運用で吸収できるか確認する。
- 公開値や仕様値は、対象プラン・対象機種・対象リージョンまで確認する。
- 既存システム、ID、ネットワーク、監視、バックアップとの接続方法を先に洗い出す。
- 小さく試してから、本番移行、権限設計、障害時手順、コスト監視を決める。