Cookie のセキュリティフラグ完全ガイド|Secure / HttpOnly / SameSite / __Host-
Web アプリケーションのセッション管理で最もよく使われる Cookie ですが、正しく設定しないと <strong>セッションハイジャック</strong> (session hijacking)、<strong>CSRF</strong> (cross-site request forgery)、<strong>XSS</strong> 経由のトークン窃取といった攻撃を招きます。本記事では Cookie に付けるべき 4 つの主要フラグ (<code>Secure</code> / <code>HttpOnly</code> / <code>SameSite</code> / <code>__Host-</code> プレフィックス) の意味と、実装時の落とし穴を整理します。
Cookie の Set-Cookie ヘッダ構造
サーバがブラウザに Cookie をセットするとき、HTTP レスポンスに以下のようなヘッダを返します。
Set-Cookie: session_id=abc123; Path=/; Domain=example.com; Expires=Wed, 22 Apr 2026 10:00:00 GMT; Secure; HttpOnly; SameSite=Lax
セミコロンで区切られた複数の属性がありますが、大きく分けて次の 2 種類があります。
- <strong>スコープ属性</strong>: Path / Domain / Expires / Max-Age — Cookie がいつどこに送られるかを決める
- <strong>セキュリティ属性</strong>: Secure / HttpOnly / SameSite — 送信/アクセスを制限する
Secure — HTTPS でのみ送信
<code>Secure</code> 属性が付いた Cookie は、ブラウザは <strong>HTTPS 接続のときだけ</strong> サーバに送信します。付けないと、被害者が <code>http://</code> でサイトにアクセスした瞬間に Cookie が平文で流れ、中間者攻撃 (Man-in-the-Middle) でセッション ID を盗まれる可能性があります。
<strong>鉄則:</strong> 認証系の Cookie には必ず付ける。ローカル開発は localhost のため HTTPS でなくても Secure Cookie が送られますが、本番の HTTPS を前提にすれば問題ありません。
HttpOnly — JavaScript からアクセス不可
<code>HttpOnly</code> を付けると <code>document.cookie</code> で読み取れなくなります。これにより、XSS 攻撃で挿入された JavaScript が Cookie を窃取できなくなります。
XSS は依然として起こりうる脆弱性なので、セッション Cookie には必須と考えてください。JavaScript 側で Cookie の値を読む必要がある場合 (例: CSRF トークン) は、<strong>読み取り専用の別 Cookie を作る</strong> か、<strong><meta> タグ経由</strong> で値を渡すのがセオリーです。
SameSite — クロスサイトリクエストでの送信制御
SameSite 属性は CSRF 対策の中核です。値は以下の 3 つ:
| 値 | 挙動 | CSRF 防御 |
|---|---|---|
Strict | クロスサイトリクエストに一切送らない (外部リンクから来たときも) | 最強 |
| <code>Lax</code> (デフォルト) | トップレベル GET ナビゲーションでのみ送る (リンククリック OK、POST フォームは NG) | 強い |
None | すべてのクロスサイトリクエストで送信 (Secure 必須) | なし |
2020 年以降のモダンブラウザは SameSite 未指定を <code>Lax</code> として扱うため、明示しなくても最低限の CSRF 保護は得られますが、意図を明確にするために明示する方が良いです。
SSO 連携や iframe 埋め込みで <code>SameSite=None</code> を使う場合は、<strong>必ず Secure も付ける</strong> のが現代ブラウザの要求仕様です。Secure が無い SameSite=None Cookie はブラウザに拒否されます。
__Host- / __Secure- プレフィックス
Cookie 名が <code>__Host-</code> で始まる場合、ブラウザは次の 3 条件を強制します。
- <code>Secure</code> フラグ必須
- <code>Domain</code> 属性を付けてはならない (=リクエストを送った正確なホストのみ)
- <code>Path=/</code> でなければならない
これらは「他のサブドメインから上書きできない」「Host ヘッダ詐称で勝手に Cookie を置けない」という強力な保証を与えます。セッション Cookie には <code>__Host-session</code> のようにプレフィックスを付けるのが最も堅牢です。
もう一方の <code>__Secure-</code> プレフィックスは Secure フラグ必須のみを強制します (Domain / Path の制約なし)。
4096 バイト制限
Cookie の value は RFC 6265 で <strong>合計 4096 バイト</strong> と推奨されています。大きな JSON や配列を Cookie に詰めると越えて、ブラウザに黙って切られることがあります。大きなデータはサーバサイドセッションに置いて、Cookie にはセッション ID だけ入れるのが定石です。
実装例: 認証セッション Cookie
正しく設定された認証 Cookie は以下のような形です。
Set-Cookie: __Host-session=eyJ0eXAi...; Path=/; Max-Age=3600; Secure; HttpOnly; SameSite=Lax
- <code>__Host-</code>: サブドメイン汚染・ホスト偽装を防ぐ
- <code>Path=/</code>: サイト全体でアクセス可能
- <code>Max-Age=3600</code>: 1 時間で期限切れ
- <code>Secure</code>: HTTPS でのみ送信
- <code>HttpOnly</code>: JavaScript からアクセス不可
- <code>SameSite=Lax</code>: クロスサイト POST では送らない (CSRF 保護)
PHP (Laravel) の例
// config/session.php
return [
'secure' => true, // Secure フラグ
'http_only' => true, // HttpOnly フラグ
'same_site' => 'lax', // SameSite=Lax
'path' => '/',
'cookie' => '__Host-session',
];
Node.js (Express) の例
const session = require('express-session');
app.use(session({
name: '__Host-session',
secret: process.env.SESSION_SECRET,
cookie: {
secure: true,
httpOnly: true,
sameSite: 'lax',
path: '/',
maxAge: 3600 * 1000,
},
}));
既存サイトの Cookie 設定をチェックする方法
自分のサイトや他社サイトの Cookie が正しく設定されているかは、<a href="/ja/check/cookies/">DevLab の Cookie 検査ツール</a> で一瞬で確認できます。URL を入れるだけで、返ってきた Set-Cookie ヘッダすべてを解析し、次のような診断を表示します。
- 各 Cookie の Secure / HttpOnly / SameSite の有無
- SameSite=None なのに Secure が無いなどの違反
- __Host- プレフィックスの整合性
- 4096 バイト超過の警告
- 全体サマリー (Secure 率 / HttpOnly 率 / SameSite 分布)
まとめ
Cookie のセキュリティフラグは「なんとなく付けておく」ではなく、攻撃シナリオと対応を理解した上で設定するのが重要です。最低限、本番環境の認証セッション Cookie には <strong>Secure + HttpOnly + SameSite + __Host- プレフィックス + 短い Max-Age</strong> を付けましょう。既存サイトの設定見直しには <a href="/ja/check/cookies/">Cookie 検査ツール</a> の利用を推奨します。