TOOLS BOX/ガイド/Cookie セキュリティオプション 3点セット
Concept

Cookie セキュリティオプション 3点セット

httpOnly / sameSite / secure の役割差と組み合わせ理由を整理するガイド。それぞれが防ぐ攻撃と開発環境での注意点を比較する。

cookiehttpOnlysameSitesecurexsscsrfhttpssecurity

どういう場面で使うか

  • ·認証 Cookie(セッショントークン)を発行するとき: 3つすべてを設定する
  • ·開発環境で動作確認するとき: secure を false にして http-only と same-site のみ有効にする
  • ·SameSite=None を使うとき(クロスオリジン Cookie): secure: true が必須

注意点 / Pitfalls

  • ·SameSite=None を設定する場合は secure: true が必須。ブラウザが Secure なしの SameSite=None を無視する
  • ·httpOnly: true にするとクライアント JS から Cookie が読めなくなる(意図した動作だが認識が必要)
  • ·secure: true のまま HTTP でデプロイすると Cookie が送信されずログインできない

補足

3つは異なる攻撃ベクタに対応するため、役割が重複しない。認証 Cookie には原則として3つすべてを設定する。

3つのオプションが防ぐもの

オプション防ぐ攻撃防がないもの
httpOnlyXSS によるトークン窃取CSRF・盗聴
sameSiteCSRF(クロスサイトリクエスト偽造)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=Nonesecure の依存関係

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 を確認してリダイレクトするパターン

関連ドキュメント

関連サンプル

同じテーマや技術スタックを使った実装例