クッキートークン完全ガイド:認証設計とCSRF/XSS対策の実践

クッキートークンとは何か — 概要

「クッキートークン(cookie token)」という用語は厳密に標準化された単語ではありませんが、一般的には「トークン(認証用アクセストークンやセッショントークン)をブラウザのクッキーに格納してやり取りする仕組み」を指します。Web認証の世界では、サーバーが発行するセッションIDやJWT(JSON Web Token)などをクッキーに入れて、以降のリクエストで自動的に送信させるのが典型的なパターンです。

なぜクッキーにトークンを入れるのか

  • 自動送信:ブラウザは対象ドメインへのHTTPリクエスト時に自動で該当クッキーを付与するため、クライアント側スクリプトでヘッダーを設定する手間が不要になる。

  • httpOnly属性:JavaScriptからの読み取りを防ぐhttpOnlyフラグを付けられるため、XSS(クロスサイトスクリプティング)による盗難リスクを下げられる。

  • 標準プロトコルとの親和性:従来のサーバーサイドセッション(セッションIDをクッキーで管理する)と同様の扱いができ、既存のミドルウェアやライブラリとの互換性が高い。

代表的な使い方のパターン

  • サーバーサイドセッション:サーバーがセッションIDを発行し、それをクッキー(例:SESSIONID)に保存。サーバー側で状態を保持し、リクエストごとに照合する。

  • JWTをクッキーに保存:ステートレス認証としてJWTをレスポンスで発行し、クッキーに入れて以降の認証に使用する。サーバー側の状態管理を減らせるが、安全管理が重要。

  • アクセストークン/リフレッシュトークンの分離:短命のアクセストークンはメモリに保持、長命のリフレッシュトークンは安全なhttpOnlyクッキーに保存してリフレッシュエンドポイントで新しいアクセストークンを発行するパターン。

重要なCookie属性(セキュリティ観点)

  • Secure:HTTPS通信時にのみ送信される。必須にすることで中間者攻撃によるトークン漏洩を減らす。

  • HttpOnly:JavaScriptからアクセスできない。XSSによる直接的な盗難を防ぐが、XSS自体は別途対策が必要。

  • SameSite(Lax / Strict / None):クロスサイトリクエストでクッキーが送信されるかを制御。CSRF対策やクロスサイトの振る舞いを整理するのに重要。SameSite=Noneを使う場合はSecureが必須。

  • Path / Domain:クッキーが送信される対象URIやドメインを制限できる。最小化原則で最小範囲に限定する。

  • Expires / Max-Age:有効期限。セキュリティ上、長期の永続クッキーは避けるべき。

セキュリティ上のトレードオフ:CSRFとXSS

クッキーにトークンを置くと、JavaScriptからは読み取れないようにできるためXSSによる直接漏洩リスクは低くなります。しかし、クッキーは自動送信されるため、攻撃者によるCSRF(Cross-Site Request Forgery)の恩恵を受けやすくなります。したがって、クッキートークンを使う場合はCSRF対策が不可欠です。

代表的対策:

  • SameSite属性の適切な利用(Lax/Strict)

  • サーバー側でCSRFトークン(Synchronizer Token Pattern)を用いる、またはダブルサブミットCookieパターンを採用する

  • CORSとAccess-Control-Allow-Credentialsを適切に設定し、信頼できるオリジンのみを許可する

設計上のベストプラクティス

  • 最小権限・短寿命:アクセストークンを短命にし、必要最低限のスコープに限定する。

  • リフレッシュトークンの安全な保管:長寿命トークンはhttpOnlyかつSecureなクッキーに入れ、トークン回転(rotation)や一回限りのワンタイム化でリプレイを防ぐ。

  • セッション固定化対策:認証後にセッションIDを更新する(新しいクッキーを発行)

  • トークンの署名と暗号化:JWTなどは署名(HMACやRSA)で改ざん検知。必要なら暗号化(JWE)も検討。

  • 監査とログアウト:サーバー側でセッション管理(revocation)を可能にし、強制ログアウトやブラックリスト化を実装する。

  • 最小ドメイン戦略:サブドメイン間で不要なクッキー共有を避けるため、domain属性を厳密に設定する。

実装にまつわる具体的な注意点

・ブラウザの挙動差異:クッキーのサイズ上限(多くのブラウザで約4096バイト)や、ドメインごとの最大クッキー数には差があるため大きなトークンは避ける。
・Third-party cookieの制限:広告ブロッキングやブラウザ方針によりサードパーティのクッキーはブロックされることが多い。認証に第三者ドメインを用いる場合はCORSやSameSiteの影響を検討する。
・SPA(シングルページアプリ)との整合性:SPAでAuthorizationヘッダーを使う設計ならローカルストレージやメモリにトークンを保持する選択肢もあるが、XSSリスクを考慮する。

実例:Set-Cookieヘッダの例

Set-Cookie: refresh_token=...; HttpOnly; Secure; SameSite=Strict; Path=/auth; Max-Age=1209600

この例ではリフレッシュトークンをhttpOnlyかつSecure、SameSite=Strictで保護し、/auth以下のパスでのみ送信されるように制限しています。

トークンベース認証(Authorizationヘッダ)との比較

  • Authorization: Bearer トークンをヘッダで送る場合、CSRFの影響を受けないが、クライアントサイドでトークンを保持する方法(localStorageなど)がXSSに弱い。

  • クッキー格納はXSSに強いがCSRF対策が必要、ヘッダ送信はCSRFに強いがXSSに弱い、というトレードオフがある。

  • 実運用では「短命アクセストークンをメモリで保持」「長命リフレッシュトークンをhttpOnlyクッキーで保持」というハイブリッドがよく採用される。

運用上のポイントと監査

  • 異常検出:同一トークンで不自然なIP/UAからのアクセスがあれば無効化するロジックを入れる。

  • ローテーションと失効:リフレッシュによるトークンローテーションやサーバー側ブラックリストを組み合わせる。

  • 鍵管理:JWT署名鍵や暗号鍵は適切に管理(KMSやHSMの活用)し、定期的にローテーションする。

まとめ(実践的な推奨)

クッキートークンはブラウザの自動送信やhttpOnly保護を活かして安全に認証状態を維持できる一方、CSRFやブラウザポリシーの影響を受けるため、次の点を守ることが重要です。

  • HTTPS + Secure + httpOnly を必ず有効化する。

  • SameSiteを適切に設定し、必要ならCSRFトークンを併用する。

  • トークンは最小権限・短寿命にし、必要に応じてリフレッシュトークンと回転を使う。

  • サーバー側で失効(revocation)や異常検知を行い、運用でのリスク管理を徹底する。

参考文献