Cookie の仕組みとセキュリティ属性(SameSite・__Host-)
Cookie のスコープと SameSite・__Host- を原理から押さえれば、CSRF やセッション横取りの設計ミスを未然に潰せる。属性一つの差が信頼境界を左右する理由がわかる。
- 1.Cookie のスコープはオリジンではなく「ドメイン+パス」で決まり、ポートやスキームは(原則)区別しない。ここがオリジン分離と最初にズレる。
- 2.SameSite は別サイト発リクエストへの自動付与を制御する。Lax が既定、Strict は遷移でも付かず、None は Secure 必須。CSRF 緩和の中核。
- 3.__Secure- は Secure 必須、__Host- はさらに Domain 不可・Path=/ 必須で、サブドメインからの Cookie tossing をブラウザ側で封じる。
Cookie のスコープはオリジンではなく「ドメイン+パス」
まず外せない大前提は、Cookie のスコープが Web セキュリティの基本単位であるオリジン(スキーム+ホスト+ポート)と一致しないことです。サーバーは Set-Cookie ヘッダで Cookie を発行し、ブラウザは次回以降のリクエストに Cookie ヘッダで自動的に同梱します。このとき「どのリクエストに付けるか」を決めるのが Domain と Path という二つのスコープ属性です。
Set-Cookie: sid=abc123; Domain=example.com; Path=/; Secure; HttpOnly
ここで重要な非対称が二つあります。
- ポートを区別しない:
example.com:443で発行した Cookie はexample.com:8080にも送られる。オリジンならポート違いは別扱いだが、Cookie は無視する。 - スキームをほぼ区別しない:
Secure属性が無ければ HTTP/HTTPS の両方に付く。Secureを付けて初めて HTTPS 限定になる。
つまり Cookie の信頼境界は「ドメイン」という、オリジンより粗い単位で引かれます。この粗さがサブドメイン間の信頼問題(後述の Cookie tossing)の根になります。
Domain を省略すると、その Cookie は発行したホスト自身にのみ送られます(host-only cookie)。Domain=example.com と明示すると、example.com とすべてのサブドメイン(api.example.com、www.example.com …)に広がります。直感に反して「Domain を書く=範囲を絞る」ではなく「広げる」操作である点に注意。逆に Domain を自分より上位の登録ドメイン(例 .com や他社ドメイン)に設定することはブラウザが拒否します。
Path はパスのプレフィックス一致でスコープを絞りますが、これはセキュリティ境界として信頼してはいけません。同一ドメイン内では同一オリジンのスクリプトがどのパスにもアクセスでき、document.cookie 経由で別パスの動作に干渉しうるためです。Path はあくまで送信量の最適化や名前空間の整理用と考えます。
SameSite:別サイト発リクエストへの自動付与を制御する
Cookie が「別サイトから来たリクエストにも自動で付く」性質こそ CSRF の根本原因でした。これをブラウザ側で制御するのが SameSite 属性です。判定基準はリクエストの送信元サイトと宛先サイトが同じ site かどうかで、ここでいう site は厳密なオリジンではなく「eTLD+1」(example.co.jp のような登録可能ドメイン)単位である点に注意します。
| 値 | 別サイト発リクエストへの付与 | 代表的な用途と注意 |
|---|---|---|
| Strict | 一切付けない(トップレベル遷移でも付かない) | 最も堅い。ただし外部リンクから来た初回は未ログイン表示になる |
| Lax | GET のトップレベル遷移(リンク・アドレスバー)にのみ付く | 現代ブラウザの既定。POST・iframe・fetch・img には付かず CSRF を大きく抑える |
| None | 常に付ける | クロスサイト埋め込みに必須。Secure 属性が無いとブラウザに拒否される |
Lax の肝は「安全(safe)かつトップレベル遷移のときだけ付ける」点です。リンククリックでの遷移には付くので利便性を保ちつつ、POST フォーム送信・<img>・fetch・<iframe> といったサイレントに発火しうる経路には付かない。CSRF の自動送信フォーム攻撃がここで止まります。
Lax でも GET で状態を変える実装(/delete?id=1 のような副作用付き GET)はトップレベル遷移で付与されるため攻撃が通ります。また同一サイト内(信頼できないサブドメインや、同居する別アプリ)からの攻撃は SameSite では防げません。SameSite は保険であり、本命は依然として CSRF トークンや Origin 検証です。設計の詳細は CSRF を参照。
SameSite=None を選ぶ場合は Secure が必須で、これが無い None は最近のブラウザではCookie 自体が破棄されます。クロスサイトで Cookie を使う以上、平文での流出を許さないという整合的な制約です。
__Secure- と __Host- プレフィックス:属性を“偽装できなくする”
Secure や SameSite を付けても、サブドメインや中間者が同名の Cookie を上書きして属性を骨抜きにする攻撃が残ります。これを防ぐため、Cookie 名に特定のプレフィックスを付けると、ブラウザが受理時に属性条件を強制チェックする仕組みが Cookie Prefixes です。条件を満たさない Set-Cookie はブラウザが受け取りを拒否します。
| プレフィックス | ブラウザが強制する条件 | 守られる性質 |
|---|---|---|
| __Secure- | Secure 必須/HTTPS 由来であること | 平文経路からの設定・上書きを排除 |
| __Host- | Secure 必須・Path=/ 必須・Domain 指定不可(host-only) | 上に加え、サブドメインからの注入を完全に封じる |
__Host- が決定的なのは Domain を付けられない(host-only に固定される) ことです。これにより Cookie は「発行したホスト自身」にだけ束縛され、api.example.com のような兄弟・子サブドメインがこの Cookie を設定・上書きする経路が原理的に消えます。セッション ID やトークンは __Host- を強く推奨します。
# OK: host-only に固定され、サブドメインから触れない
Set-Cookie: __Host-sid=abc123; Secure; Path=/; HttpOnly; SameSite=Lax
# 拒否される: __Host- なのに Domain を指定している
Set-Cookie: __Host-sid=abc123; Secure; Path=/; Domain=example.com
__Host- / __Secure- の強制条件に HttpOnly は入っていません。HttpOnly は JavaScript の document.cookie からの読み取りを禁じ、XSS によるセッション窃取の被害を抑える別軸の属性です。プレフィックスは「設定・上書き」を、HttpOnly は「読み取り」を守る——役割が異なるので、認証 Cookie には両方を併せて付けます。
Cookie tossing:サブドメインという信頼境界の穴
Cookie のスコープが「ドメイン単位」であることの帰結が Cookie tossing(Cookie 注入) です。攻撃者が evil.example.com のようなサブドメインを支配できた場合(共有ホスティング、放置されたサブドメインの乗っ取り=サブドメインテイクオーバー、XSS など)、そこから親ドメインに向けた Cookie を仕込めます。
# evil.example.com が、親ドメイン全体に効く Cookie を設定する
Set-Cookie: sid=attacker-value; Domain=example.com; Path=/
問題は、ブラウザが同名 Cookie を送るときどのドメイン/パスで設定されたかを Cookie ヘッダで区別しないことです。サーバーには Cookie: sid=... としか届かず、正規の host-only Cookie と注入された Domain Cookie が衝突したときどちらが届くかが曖昧になります。攻撃者はこれを使ってセッション固定(victim を攻撃者のセッションに誘導)や、より具体的な Path を持つ Cookie で正規値を覆い隠すことを狙います。
ここが信頼境界の核心です。app.example.com と evil.example.com は SameSite 的には同一サイト(eTLD+1 が同じ)なので、SameSite=Strict でも互いのリクエストには Cookie が付きます。一方で同一オリジンではないため、本来は分離されるべき。つまり SameSite は「外部サイト」は防いでも「兄弟サブドメイン」は守りません。サブドメインを一つでも信頼できない状況を作ると、ドメイン全体の Cookie が汚染されうる——これが Cookie tossing の本質です。
防御の要点を原理に沿って整理します。
__Host-を使う: host-only に固定され、サブドメインからの Domain Cookie 注入をブラウザが拒否する。最も効く一手。__Host-で Path=/ に固定: より深い Path を使った「覆い隠し」攻撃の余地を消す。- サーバー側で値を検証: セッション ID は署名・サーバー保存と突き合わせ、注入された未知の値を弾く(セッション固定対策)。
- サブドメインを信頼境界として管理: 使わない DNS レコードは消し(テイクオーバー防止)、別アプリを安易に同一登録ドメイン配下へ同居させない。
実務でのまとめ
認証・セッション系 Cookie の既定形は次のとおりです。__Host- プレフィックス、Secure、HttpOnly、SameSite=Lax(クロスサイト要件があるときだけ熟慮の上で None)を基本とし、CSRF トークンを別途重ねます。
Set-Cookie: __Host-session=...; Secure; HttpOnly; Path=/; SameSite=Lax
整理すると、SameSite は「外部サイト」、__Host- は「サブドメイン」、HttpOnly は「XSS による読み取り」、Secure は「平文経路」を、それぞれ別の角度から塞ぐ多層防御です。どれか一つで完結はしません。クリックジャッキングのようなフレーム経由の悪用や、ヘッダによる防御の全体像は クリックジャッキング と セキュリティヘッダ も合わせて押さえると、Web の信頼境界が立体的に見えてきます。
セキュリティ Article
Cookie の仕組みとセキュリティ属性(SameSite・__Host-)を実務で読む
TL;DRは入口です。実際に選ぶ・使う段階では、何を解決するか、何と比較するか、導入後にどこで詰まるかまで見る必要があります。
解決すること
セキュリティ
比較で見る軸
難易度: advanced / カテゴリ: セキュリティ / タグ数: 5
導入後に効く点
SameSite は別サイト発リクエストへの自動付与を制御する。Lax が既定、Strict は遷移でも付かず、None は Secure 必須。CSRF 緩和の中核。
先に潰すリスク
用語だけ覚えても、設計・実装・運用でどこに効くかを確認しないと判断を誤る。
- 難易度
- advanced
- カテゴリ
- セキュリティ
- タグ数
- 5
判断チェックリスト
- 自社の用途が「セキュリティ / Cookie」に近いか確認する。
- 強みである「Cookie のスコープはオリジンではなく「ドメイン+パス」で決まり、ポートやスキームは(原則)区別しない。ここがオリジン分離と最初にズレる。」が本当に評価軸になるか確認する。
- 注意点の「用語だけ覚えても、設計・実装・運用でどこに効くかを確認しないと判断を誤る。」を運用で吸収できるか確認する。
- 公開値や仕様値は、対象プラン・対象機種・対象リージョンまで確認する。
- 既存システム、ID、ネットワーク、監視、バックアップとの接続方法を先に洗い出す。
- 小さく試してから、本番移行、権限設計、障害時手順、コスト監視を決める。