Cookies vs localStorage vs sessionStorage:クライアントストレージの選択
Webアプリケーションを構築する際、ユーザーのテーマ設定、ショッピングカート、認証トークンなど、クライアント側にデータを保存する必要がよくあります。主な選択肢はCookies、localStorage、sessionStorageの3つです。それぞれ異なる特性を持ち、異なるシナリオに適しています。間違った選択をすると、セキュリティ脆弱性、パフォーマンス問題、またはユーザーエクスペリエンスの低下を招く可能性があります。
この記事では、違いを分解し、実用的なガイダンスを提供し、次のプロジェクトでどのストレージメカニズムを使用すべきかを判断するのに役立ちます。
簡単な比較
詳細に入る前に、3つのストレージタイプの概要を以下に示します:
| 機能 | Cookies | localStorage | sessionStorage |
|---|---|---|---|
| 容量 | ドメインあたり約4KB | オリジンあたり約5-10MB | オリジンあたり約5-10MB |
| 永続性 | 設定可能な有効期限 | 明示的にクリアするまで | タブ/ウィンドウを閉じるまで |
| サーバーに送信 | すべてのHTTPリクエストで自動的に | いいえ | いいえ |
| JavaScriptからアクセス可能 | はい(HttpOnlyでない場合) | はい | はい |
| スコープ | ドメインとパス | オリジン(プロトコル + ドメイン + ポート) | オリジン + タブ/ウィンドウ |
| XSSに対して脆弱 | はい(HttpOnlyでない場合) | はい | はい |
| CSRFに対して脆弱 | はい(認証に使用する場合) | いいえ | いいえ |
Cookies:元祖クライアントストレージ
CookiesはWebの初期から存在しています。これらは小さなデータ片(最大約4KB)で、ブラウザが保存し、同じドメインへのすべてのHTTPリクエストで自動的にサーバーに送信します。
Cookiesを使用する場合
- 認証セッション:サーバーが各リクエストを検証するために必要なセッションIDやトークンを保存します。
HttpOnly、Secure、SameSiteフラグを使用してXSSとCSRFのリスクを軽減します。 - サーバーサイドパーソナライゼーション:サーバーがページをレンダリングする前にユーザー設定(言語、テーマなど)を知る必要がある場合。
- トラッキングと分析:Cookiesはセッションを超えて持続し、設定すればサブドメイン間で共有できます。
セキュリティ考慮事項
Cookiesは自動的に送信されるため、追加の保護なしに認証に使用するとCSRFに対して脆弱になります。常にSameSite属性(LaxまたはStrict)を設定し、CSRFトークンの使用を検討してください。機密データにはHttpOnlyを使用してJavaScriptからのアクセスを防ぎ、XSSの影響を減らします。
HTTPレスポンスで安全なCookieを設定する例:
Set-Cookie: sessionId=abc123; HttpOnly; Secure; SameSite=Lax; Path=/; Max-Age=3600
localStorage:永続的なキー値ストレージ
localStorageは、ブラウザを閉じても持続するシンプルなキー値ストアを提供します。データはオリジンごと(プロトコル + ドメイン + ポート)に保存され、サーバーに自動的に送信されません。ページリロードやブラウザ再起動後も存続すべき非機密データの保存に最適です。
localStorageを使用する場合
- ユーザー設定:テーマ(ダーク/ライト)、フォントサイズ、言語、レイアウト設定。
- キャッシュ:APIレスポンスや静的データを保存してネットワークリクエストを減らし、オフライン体験を向上させます。
- クライアントサイド状態:ショッピングカートの内容、下書きフォームデータ、機能フラグ。
セキュリティ考慮事項
localStorageはJavaScriptからアクセス可能なため、XSS脆弱性があると保存されたすべてのデータが露出する可能性があります。堅牢なXSS保護がない限り、パスワード、個人識別番号、認証トークンなどの機密情報を保存しないでください。トークンを保存する必要がある場合は、代わりにHttpOnly Cookieアプローチの使用を検討してください。
localStorageの使用例:
// ユーザー設定を保存
localStorage.setItem('theme', 'dark');
// 設定を取得
const theme = localStorage.getItem('theme');
// アイテムを削除
localStorage.removeItem('theme');
sessionStorage:タブごとのストレージ
sessionStorageはlocalStorageに似ていますが、寿命が短くなっています。タブまたはウィンドウを閉じるとデータがクリアされます。単一のタブにスコープされるため、同じオリジンでもタブやウィンドウ間でデータが共有されません。
sessionStorageを使用する場合
- マルチステップフォーム:ユーザーがステップを進むにつれてフォームデータを一時的に保存し、完了後に永続化しないようにします。
- 単一タブの状態:一時的な認証状態やワンタイムトークンなど、タブ間で漏洩すべきでないデータ。
- 機密操作:ユーザーがタブを閉じたときにデータを自動的にクリアし、露出を減らしたい場合。
セキュリティ考慮事項
localStorageと同様に、sessionStorageはXSSに対して脆弱です。ただし、限られた寿命とタブごとのスコープにより、攻撃者の機会の窓は減少します。それでも、高度に機密性の高いデータの保存は避けてください。
sessionStorageの使用例:
// フォームデータを保存
sessionStorage.setItem('formStep1', JSON.stringify({name: 'John'}));
// フォームデータを取得
const step1 = JSON.parse(sessionStorage.getItem('formStep1'));
選択方法:意思決定ガイド
以下の順序付きリストを使用して意思決定を導いてください:
- サーバーはすべてのリクエストでデータを読み取る必要がありますか?はいの場合、Cookiesを使用します。例:セッションID。
- データはブラウザセッションを超えて持続する必要がありますか?はいの場合、localStorageを使用します。例:ユーザー設定。
- データは単一のタブに限定すべきですか?はいの場合、sessionStorageを使用します。例:マルチステップフォームデータ。
- データは機密ですか?localStorageやsessionStorageに保存しないでください。トークンにはHttpOnly Cookiesを使用し、パスワードは絶対に保存しないでください。
- データは大きいですか?Cookiesは約4KBに制限されています。localStorageとsessionStorageははるかに多くの容量を提供します。
セキュリティのベストプラクティス
- 常に入力を検証およびサニタイズすることで、クライアントサイドストレージを侵害する可能性のあるXSSを防ぎます。
- 認証トークンにはHttpOnly、Secure、SameSite Cookiesを使用することで、XSSとCSRFを軽減します。
- 機密データの保存を避ける:localStorageやsessionStorageに保存しないでください。保存する必要がある場合は、暗号化し、短い有効期限を使用してください。
- Content Security Policy (CSP)を実装することで、XSSリスクを減らします。
- 古いデータを定期的にクリアすることで、ストレージ制限に達するのを避け、露出を減らします。
FAQ
認証トークンにlocalStorageを使用できますか?
localStorageはJavaScriptからアクセス可能なため、トークンがXSSに対して脆弱になるのでお勧めしません。SecureとSameSiteフラグを備えたHttpOnly Cookiesを優先してください。
タブを複製するとsessionStorageはどうなりますか?
タブを複製すると、新しいタブは複製の瞬間に元のタブからsessionStorageのコピーを取得します。その後、それらは独立しています。
Cookiesはすべてのリクエストでサーバーに送信されますか?
はい、現在のドメインのCookiesはすべてのHTTPリクエストに自動的に含まれます。あまり多くのデータを保存するとパフォーマンスに影響する可能性があります。控えめに使用してください。
保存するJSONデータをすばやくフォーマットまたは検証する必要がありますか?クライアントストレージに保存する前にJSONペイロードを美化してデバッグするには、JSON Formatterをお試しください。