3つのオプションが防ぐもの
| オプション | 防ぐ攻撃 | 防がないもの |
|---|---|---|
httpOnly | XSS によるトークン窃取 | CSRF・盗聴 |
sameSite | CSRF(クロスサイトリクエスト偽造) | XSS・盗聴 |
secure | 通信経路での盗聴(中間者攻撃) | XSS・CSRF |
3つは異なる攻撃ベクタに対応しており、役割が重複しません。1つだけでは防げないリスクがあるため、認証 Cookie には原則として3つすべてを設定します。
各オプションの役割
httpOnly
JavaScript から Cookie を読み書きできなくします。document.cookie でアクセスできないため、XSS 攻撃でスクリプトを注入されても Cookie の値が盗まれません。
cookieStore.set("session", token, {
httpOnly: true, // JS からアクセス不可
});
注意点: httpOnly: true にすると、フロントエンドから認証状態を document.cookie で確認できなくなります。認証状態の確認が必要な場合は、別途 /api/me などの API エンドポイントか、フラグ専用の非 httpOnly Cookie を併用します。
sameSite
クロスサイトリクエスト時に Cookie を送るかどうかを制御します。CSRF 攻撃(別サイトからフォーム送信などでセッションを悪用する手法)への対策になります。
| 値 | 挙動 |
|---|---|
Strict | 同一サイトのリクエストにのみ送信 |
Lax | 同一サイト+トップレベルナビゲーション(GET)に送信 |
None | すべてのクロスサイトリクエストに送信(secure: true が必須) |
cookieStore.set("session", token, {
sameSite: "lax", // 通常の認証 Cookie は Lax が現実的
});
Strict vs Lax の選び分け: Strict は最もセキュアですが、外部サイトからのリンクでページを開いたときにセッションが送られないため、ログイン状態がリセットされたように見えることがあります。認証 Cookie には Lax を使うことが多いです。
secure
HTTPS 接続時のみ Cookie を送信します。HTTP 通信では Cookie が送られないため、通信経路での盗聴を防ぎます。
cookieStore.set("session", token, {
secure: process.env.NODE_ENV === "production", // 本番のみ有効
});
一緒に使う理由
// 認証 Cookie の典型セット
cookieStore.set("session_id", token, {
httpOnly: true, // XSS 対策
sameSite: "lax", // CSRF 対策
secure: process.env.NODE_ENV === "production", // 盗聴対策(本番のみ)
path: "/",
maxAge: 60 * 60 * 24 * 7, // 7日
});
3つを組み合わせることで「盗めない・偽造できない・盗聴されない」Cookie になります。
開発環境で混乱しやすい点
secure: true と localhost
secure: true は HTTPS 接続のみ Cookie を送信します。ローカル開発(HTTP)では Cookie が送られなくなるため、一般的に NODE_ENV === "production" の条件で切り替えます。Chrome は localhost を例外扱いしますが、Safari などでは挙動が異なります。
SameSite=None と secure の依存関係
sameSite: "none" を設定する場合は secure: true が必須です。ブラウザは Secure フラグのない SameSite=None Cookie を無視します。クロスオリジン環境(フロントエンドと API が別ドメイン)では HTTPS 環境での確認が必要です。
// ❌ secure なしの SameSite=None はブラウザが無視する
{ sameSite: "none" }
// ✅ SameSite=None には secure: true が必須
{ sameSite: "none", secure: true }
httpOnly とフロントエンドの認証状態確認
httpOnly: true の Cookie はクライアント JS から読めないため、React などのフロントエンドで document.cookie を使った認証チェックができません。認証状態を UI に反映したい場合は API エンドポイント(例: GET /api/me)で確認するパターンを使います。
関連サンプルの見どころ
- nextjs-cookie-session: 認証 Cookie の発行・削除の基本実装(3点セットの使用例)
- nextjs-cookies-server: Server Component / Server Actions / Route Handler での Cookie 操作
- nextjs-auth-redirect: Cookie を確認してリダイレクトするパターン