FlawOpen

flawopen.com/リファレンス/JWT と HttpOnly クッキー

localStorage の JWT と HttpOnly クッキー:どちらが安全か

認証ガイド
手短に言うと

多くのWebアプリでは、サーバー管理のセッションを HttpOnly Cookie で受け渡す方式が堅実な出発点です。JavaScriptからCookieを読めないため、トークンの直接窃取を抑えられますが、XSS自体は無効化されません。同一オリジンで動く注入コードは、認証済みリクエストを送り、ページから参照できるデータを読む可能性があります。

セキュリティ上のトレードオフ

保存 / 送信XSSのリスクCSRFへの影響失効
localStorage bearer token同一オリジンのJavaScriptから読め、XSSで窃取またはユーザーとして操作される可能性があります。クロスサイトリクエストに自動添付されませんが、XSSやクライアントサイドCSRFは残ります。失効を確認しなければ、自立型JWTは期限まで有効な場合があります。
HttpOnly cookieJavaScriptから値を読めませんが、XSSで認証済みリクエストを送ることは可能です。Cookie規則に従って自動送信されます。SameSiteはCSRF対策の一層にすぎません。不透明なセッションはサーバーで無効化できます。JWT Cookieには別途失効方針が必要です。

推奨アーキテクチャ

トークン形式・保存場所・セッション状態を分けて考える

JWTはトークン形式です。localStorageとCookieはブラウザーでの保存・送信方法で、JWTはどちらにも保存できます。Cookie内の不透明なセッション識別子は通常サーバー側の状態を参照します。「JWTかCookieか」は同列の選択肢の比較ではありません。

方式ごとに変わる点

ブラウザーは localStorage の値をクロスサイトリクエストに自動添付しませんが、同一オリジンのXSSはBearerトークンを読んだり、アプリを通じて操作したりできます。Cookieは規則に従い自動送信されます。HttpOnlyはJavaScriptから値を隠しますが、注入コードがログイン済みページを利用するのは防げません。SameSite=LaxはCSRF対策の一層であり、完全な保証ではありません。安全なメソッドによるトップレベル遷移やsame-siteリクエストも考慮し、GETで状態を変更せず、検証済みトークンやOrigin検証など適切な対策を使います。

失効は保存先ではなく、サーバー状態とトークン検証に依存します。サーバー側セッションは記録を削除して無効化できます。失効状態を確認しない場合、自立型JWTは期限まで受理される可能性があります。短い有効期間はその時間を縮めますが、なくしません。

実務上の出発点

出典・参考資料

関連項目 クロスサイトリクエストフォージェリ(CSRF、CWE-352):仕組みと防ぎ方 — flawopen.com Next.js Server Actions CSRF:Origin と安全な設定 SameSite=Strict は CSRF トークンの代わりになりますか? GET に CSRF トークンは必要?