「デバイスを跨いでもログイン状態を維持したい」という要件があるとき、セッション情報(JWT やセッション ID)をどこに保存するのがベストなのか。 localStorage、sessionStorage、Cookie... それぞれの選択肢にはメリットとデメリットがありますが、セキュリティと運用性を考えると、実は「正解」は絞られてきます。
4 つの代表的な選択肢を比較しながら、なぜその方法が推奨されるのかを深掘りします。
比較する 4 つの選択肢
A) localStorage に保存された JWT
- 永続性:◯(ブラウザを閉じても保持される)
- リスク:XSS(クロスサイトスクリプティング)に極めて弱い
- 結論:JavaScript から中身が丸見えなので、悪意のあるスクリプトが実行された瞬間にトークンを盗まれます。セキュリティを重視するなら推奨されません。
B) httpOnly クッキーに保存された JWT
- 永続性:◯(Cookie の有効期限内なら保持される)
- リスク:JavaScript からアクセスできない(httpOnly)ため、XSS 耐性がある。
- 課題:
- JWT はサーバー側で状態を持たないため、「特定のデバイスだけ強制ログアウトさせる」といった制御が難しい。
- トークンの失効管理(ブラックリスト管理)を始めると、ステートレスという JWT の利点が薄れてしまう。
C) httpOnly クッキーに保存された「セッション ID」(最適解)
- 永続性:◯
- セキュリティ:◯(httpOnly により XSS 耐性があり、Secure 属性で HTTPS 通信のみに限定可能)
- 運用の柔軟性:◎ 最も柔軟
- 実体はサーバー側の Redis や DB にあるため、サーバー側でセッションを自由に無効化できる。
- 「ログイン中のデバイス一覧」を表示したり、パスワード変更時にすべてのセッションを破棄したりする処理が容易。
D) sessionStorage に保存された JWT
- 永続性:✕(タブを閉じると消える)
- 要件への適合:今回の「デバイス間で永続させたい」という要件には全く適合しません。
なぜ「httpOnly クッキー + セッション ID」が選ばれるのか
現代のウェブ開発において、特にセキュリティと高度なユーザー管理が必要な場合、**選択肢 C(httpOnly クッキー + サーバー管理のセッション ID)**が最もバランスが良いとされています。
- XSS 対策:httpOnly 属性により、万が一スクリプトが混入してもセッション ID は盗まれません。
- サーバー側での制御権:JWT のような「一度発行したら止められない」というリスクがなく、サーバー側でいつでもアクセス権を取り消せます。
- デバイス管理:ユーザーが複数のデバイスでログインしている場合、それぞれのセッションを個別に管理(表示・削除)できるのは、サーバー側で状態を持っている強みです。
まとめ
「スケーラビリティのために JWT を localStorage に」という誘惑は多いですが、セキュリティ事故のリスクや、後から「特定のユーザーを強制ログアウトさせたい」となった時の困り具合を考えると、Cookie とサーバーサイドセッションの組み合わせが、今でも最も堅実で安全な選択肢と言えます。