Cookie 属性ガイド:SameSite・Partitioned・HttpOnly・Secure・Domain・Path・Priority の使い分け
Set-Cookie ヘッダの属性は 7 種類以上あり、認証・CSRF 対策・トラッキング規制対応にすべてが絡みます。「SameSite=Lax でいい」「HttpOnly を付けておけば安全」と単発で覚えがちですが、現代では Partitioned の登場や 3rd-party Cookie 廃止トレンド で組合せ判断が増えています。本記事では各属性の役割と、典型的な用途別の推奨組合せを整理します。
属性一覧
Set-Cookie: sessionId=abc123; Domain=example.com; Path=/; Max-Age=3600;
Secure; HttpOnly; SameSite=Lax; Priority=High; Partitioned | 属性 | 役割 | デフォルト |
|---|---|---|
Domain | 送信先ドメイン範囲 | リクエストのオリジン |
Path | 送信先パス範囲 | リクエストのパス |
Expires / Max-Age | 有効期限 | セッション(タブ閉じで消える) |
Secure | HTTPS のみ送信 | なし(HTTP でも送る) |
HttpOnly | JS から読めない | なし(document.cookie で読める) |
SameSite | クロスサイト送信を制御 | Lax(モダンブラウザ) |
Partitioned | パーティション分離(CHIPS) | なし |
Priority | エビクション優先度 | Medium |
SameSite:CSRF と トラッキングの境界
最も重要な属性。クロスサイトリクエストでの送信挙動を制御。
| 値 | クロスサイト GET(リンク) | クロスサイト POST(フォーム) | iframe 内 |
|---|---|---|---|
Strict | ✗ | ✗ | ✗ |
Lax | ✓ | ✗ | ✗ |
None | ✓ | ✓ | ✓(要 Secure) |
SameSite=Lax(現代のデフォルト)
Chrome 80(2020)以降、SameSite を指定しないと暗黙で Lax 扱いになります。
- 同一サイト:常に送信
- クロスサイトのトップレベル GET(
<a href>クリックで遷移など):送信する - クロスサイトの POST、iframe 読込、画像読込:送信しない
CSRF 対策の主要ライン。「フォーム POST が他サイトから来る」攻撃を防ぐ。
SameSite=Strict
クロスサイトでは一切送信しない。トップレベル遷移であっても他サイトから来たら送らない。
「外部サイトのリンクをクリックしてアクセスしたユーザーは、ログイン状態が一旦切れる」という挙動になります。これを避けるにはログインクッキーを 2 つ持つ設計(短期 Strict + 長期 Lax)が定番。
SameSite=None(要 Secure)
すべてのクロスサイトコンテキストで送信。従来の 3rd-party Cookie 挙動。
ブラウザは SameSite=None だが Secure がない Cookie を拒否(Chrome 80+)。HTTPS が前提。
Partitioned(CHIPS):3rd-party Cookie の置き換え
Set-Cookie: id=abc; Secure; SameSite=None; Partitioned CHIPS(Cookies Having Independent Partitioned State) は、埋め込み元サイトごとに別パーティションでクッキーを持たせる機能。
動機
3rd-party Cookie の用途のうち、正当なもの(埋め込み iframe チャットの状態保持、CMS の埋め込みプレビュー認証など)は残したい。一方、クロスサイトトラッキング(同じ Cookie 値で複数サイトのユーザー追跡)は防ぎたい。
Partitioned は「クッキーを使えるが、埋め込み元サイトごとに別ストア」という解:
chat.example.comの iframe をsiteA.comに埋め込む →siteA.com用パーティションにクッキー保存- 同じ iframe を
siteB.comに埋め込む →siteB.com用の別パーティション - 結果、
chat.example.com側からは「siteA に来たユーザー」と「siteB に来たユーザー」を同一視できない
使い時
- 自社の embeddable widget(チャット、コメント、決済 iframe)
- 3rd-party Cookie の代替が要るが、サイト横断トラッキングは目的でないケース
逆にトラッキングが目的の Cookie は、Partitioned ではユースケースが成立せず、別の仕組み(First-Party Set, Privacy Sandbox API)に移行する必要があります。
HttpOnly と Secure
HttpOnly
JavaScript からアクセスできないクッキー:
Set-Cookie: sessionId=abc; HttpOnly document.cookieで取得・設定できない- HTTP リクエストには通常通り送信される
- XSS でクッキーを盗まれるのを防ぐ最大の防衛線
セッション ID・認証トークンには必ず HttpOnly を付ける。
Secure
HTTPS でのみ送信:
Set-Cookie: sessionId=abc; Secure - HTTP リクエストには送らない
- 中間者がクッキーを抜き取るのを防ぐ
SameSite=None使用時は必須
開発環境(HTTP の localhost)と本番(HTTPS)で挙動を変えたい場合:
const secure = process.env.NODE_ENV === 'production';
res.cookie('sessionId', value, { secure, httpOnly: true }); Domain と Path
Domain
Set-Cookie: id=abc; Domain=example.com このクッキーは example.com および すべてのサブドメイン(api.example.com、www.example.com など)に送信される。
省略すると、Set-Cookie を返したサーバ自身のホストにのみ送信(サブドメインを含まない)。サブドメイン間で共有したいときは明示的に親ドメインを指定。
Path
Set-Cookie: id=abc; Path=/admin /admin 以下のパスでだけ送信。/admin/users には送信、/dashboard には送信しない。
実用上は Path=/ が多い。Path で絞ることでクッキーが多くなるサイトのヘッダサイズ削減に使う場合がある。
Expires と Max-Age
Set-Cookie: id=abc; Max-Age=3600
Set-Cookie: id=abc; Expires=Thu, 01 Dec 2026 16:00:00 GMT | 属性 | 単位 | 解釈基準 |
|---|---|---|
Max-Age | 秒 | 受信時刻からの相対 |
Expires | UTC 日時 | クライアントの時計 |
両方ある場合は Max-Age が優先。クライアント時計のずれを避けたいので Max-Age 推奨。
Max-Age=0 または過去の Expires はクッキー削除の指示。同じ name / Domain / Path で送信し直す必要があります。
Priority(Chrome 拡張)
Set-Cookie: id=abc; Priority=High ブラウザがクッキー数の上限に達したとき、どれから消すかを制御。Low / Medium(既定) / High。Chrome 系のみで実装、Firefox / Safari は無視。
通常は気にしなくてよく、認証用クッキーが頻繁に揮発する場合の応急対応に使う程度。
認証クッキーの推奨組合せ
Set-Cookie: sessionId=abc;
Path=/;
Max-Age=3600;
Secure;
HttpOnly;
SameSite=Lax Path=/:サイト全体で利用Max-Age=3600:1 時間(必要に応じてリフレッシュ)Secure:HTTPS のみHttpOnly:XSS 耐性SameSite=Lax:CSRF 耐性
Domain は明示しない:サブドメイン共有が必要なときだけ追加(共有しない方が攻撃面が小さい)。
CSRF 対策の現代的アプローチ
SameSite=Lax だけでは完全な CSRF 対策にならないケースがあります:
- POST 以外の変更系メソッド(PUT / DELETE):
Laxでもクロスサイトでは送られないので OK - GET で副作用がある古い API:
Laxで送られてしまう(GET をクロスサイトで投げれば認証が通る) - iframe 内アプリケーション:
Laxでは送られないので問題ない
加えて、Double Submit Cookie パターン(クッキーの値と同じ値を別ヘッダ・別フォーム値で送らせて検証)を組み合わせると、Cookie が漏れない限り CSRF を防げます:
// Cookie に CSRF token をセット
Set-Cookie: csrfToken=xyz; Secure; SameSite=Lax
// クライアントは Cookie を読んで(HttpOnly でない CSRF 用 Cookie は別物)
// 同じ値を X-CSRF-Token ヘッダに付けて送信
fetch('/api/transfer', {
headers: { 'X-CSRF-Token': getCsrfToken() }
}); ブラウザ間の差
| 機能 | Chrome | Firefox | Safari |
|---|---|---|---|
| SameSite=Lax デフォルト | ✓ | ✓ | ✓ |
Partitioned (CHIPS) | ✓ (118+) | ✓ (131+) | ✗ |
Priority | ✓ | ✗ | ✗ |
| 3rd-party Cookie 廃止 | 計画変更(保留) | デフォルト無効 | デフォルト無効(ITP) |
Safari の ITP(Intelligent Tracking Prevention)は最も厳しく、Partitioned も未対応。Safari でユーザーが失われる前提で、3rd-party Cookie に依存する設計を避けるのが現代的。
まとめ
Cookie 属性は 「誰に送るか(Domain / Path / SameSite)」「どう守るか(Secure / HttpOnly)」「いつ消すか(Max-Age / Expires)」「分離するか(Partitioned)」 の 4 軸で整理できます。認証用クッキーは Secure + HttpOnly + SameSite=Lax を最小ラインに、3rd-party 用途では SameSite=None + Secure + Partitioned を組み合わせるのが 2026 年の標準形です。Safari 等で Partitioned 未対応の場合は機能が縮退する前提を持つこと。