クッキートークン完全ガイド:認証設計と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)や異常検知を行い、運用でのリスク管理を徹底する。
参考文献
- MDN: Set-Cookie(日本語)
- RFC 6265: HTTP State Management Mechanism
- RFC 7519: JSON Web Token (JWT)
- OWASP Session Management Cheat Sheet
- OWASP CSRF Prevention Cheat Sheet
- web.dev: SameSite cookies explained


