ブラウザアプリケーションにおけるローカルストレージ活用術
1. はじめに:クライアントサイドストレージとローカルストレージ
1.1. クライアントサイドストレージの概観
現代のウェブアプリケーションにおいて、クライアントサイドストレージは不可欠な技術要素となっています。ユーザーエクスペリエンスの向上、オフライン機能の実現、サーバー負荷の軽減など、その役割は多岐にわたります 1。主要なブラウザストレージメカニズムとしては、クッキー(Cookies)、ウェブストレージ(LocalStorage、SessionStorage)、IndexedDBが挙げられ、さらに新しいAPIとしてCache APIやオリジンプライベートファイルシステム(OPFS)も登場しています 1。
これらの技術の進化は、ウェブアプリケーションが単純な情報表示から、より複雑で高度な機能を提供する「ローカルファーストアプリケーション」へと向かう潮流を反映しています 2。このようなアプリケーションでは、クライアント側でのデータ操作が重要となり、各ストレージオプションの特性を深く理解する必要性が高まっています。ローカルストレージは、この広範なエコシステムの中で基本的な位置を占めますが、常に最新の要求に応える最先端の解決策とは限りません。この点を認識することが、適切な技術選定の第一歩となります。
1.2. ローカルストレージの定義:目的と基本的な特徴
ローカルストレージ(LocalStorage)は、Web Storage APIの一部として定義されるクライアントサイドストレージ技術です 3。その主な目的は、ウェブアプリケーションがキーと値のペア形式でデータをクライアント側(ユーザーのブラウザ)に永続的に保存する仕組みを提供することにあります。これにより、ブラウザセッションを跨いでもデータが保持されます 3。
ローカルストレージの基本的な特徴は以下の通りです。
- 永続性: データは、ユーザーまたはアプリケーションによって明示的に削除されるまで保持されます 3。
- クライアントサイド限定: データはクッキーとは異なり、HTTPリクエストの度に自動的にサーバーへ送信されることはありません 3。
- シンプルさ: setItem、getItem、removeItem、clearといった直感的なAPIを通じて容易に操作できます 3。
セッションストレージ(SessionStorage)がセッション終了時にデータが消去されるのに対し、ローカルストレージは永続性を持ちます。また、クッキーと比較すると、より大きな容量を持ち、サーバーへの自動送信がない点で異なります 3。
ローカルストレージの「半永久的」なデータの保持 3 は、重要な差別化要因です。プログラムされた有効期限は存在しませんが、ユーザーによるブラウザキャッシュのクリア 6 や、プライベートブラウジングモードでの最後のタブを閉じた際のデータ消去 4 など、データが失われる可能性も存在します。この「半永久性」は、データの信頼性戦略を検討する上で考慮すべき点です。「有効期限なし」4 という特性は条件付きであり、開発者はローカルストレージを絶対的な永続ストアとして扱うべきではありません。この微妙なニュアンスは、ローカルストレージに保存するデータの種類、特に重要なデータの扱いに影響を与えます。
2. ローカルストレージ:詳細な技術仕様
2.1. データモデル:キーバリューペアと文字列ベースのストレージ
ローカルストレージは、データをキーと値のペアとして保存します。ここで重要なのは、キーと値の双方が常にUTF-16文字列形式で格納されるという点です 4。この仕様は、数値、真偽値、オブジェクト、配列といった文字列以外のデータ型を保存する際に、開発者に追加の処理を要求します。具体的には、保存前にこれらのデータを文字列にシリアライズ(例えばJSON.stringify()を使用)し、取得後にデシリアライズ(例えばJSON.parse()を使用)する必要があります 10。また、整数キーは自動的に文字列に変換されて扱われます 4。
この文字列のみという制約は、シリアライズ・デシリアライズのオーバーヘッドを生じさせ、正しく処理されない場合にはエラーの原因ともなり得ます 12。これは、複雑なオブジェクトを直接保存できるIndexedDBのような他のストレージ技術との大きな違いです 2。文字列のみという性質(原因)がシリアライズの必要性(結果)を生み、それがパフォーマンスのオーバーヘッドや実装の複雑性(波及効果)につながるため、大量の複雑なオブジェクトを扱うアプリケーションでは、ローカルストレージの効率が低下する可能性があります。
2.2. ストレージ容量:制限とブラウザ間の差異
ローカルストレージが提供するデータ保存容量は、一般的にオリジンあたり約5MBから10MBとされています 1。より具体的には、MDNのドキュメントによると、Web Storage(ローカルストレージとセッションストレージの合計)の最大容量は10MiBで、そのうちローカルストレージにはオリジンあたり最大5MiBが割り当てられています 1。ブラウザごとの具体的な上限値としては、ChromeやEdgeでは5MB、Firefoxでは10MB、Safariでは4~5MBといった報告があります 2。
この容量制限を超えてデータを保存しようとすると、ブラウザはQuotaExceededErrorという例外を発生させます。開発者はこのエラーをtry…catchブロックを用いて適切に処理する必要があります 1。
クッキーの約4KBという容量と比較すれば格段に大きいものの、5MBという上限はデータ量の多いアプリケーションにとっては依然として制約となり得ます。ブラウザ間の容量差は比較的小さいものの、開発時には最も一般的な下限値を基準にするか、あるいは容量超過エラーに対する堅牢なエラーハンドリングを実装することが求められます。この容量制限は、ローカルストレージに実質的に保存可能なデータの種類と量に直接的な影響を与えます。例えば、多数の画像をBase64エンコードされた文字列としてキャッシュしたり、大規模なユーザー生成コンテンツをクライアント側に保存したりするようなアプリケーションは、すぐにこの制限に直面し、IndexedDBやサーバーサイドストレージといった代替手段を検討する必要が出てくるでしょう。
2.3. データの永続性と寿命
ローカルストレージのデータには、APIレベルでの明確な有効期限は設定されていません。データはブラウザセッションを跨いで、つまりブラウザを閉じて再度開いた後も保持されます 3。
しかし、データが消去されるケースも存在します。
- JavaScriptによる明示的な削除(localStorage.removeItem()またはlocalStorage.clear())4。
- ユーザーによるブラウザのデータ/キャッシュ/クッキーのクリア操作 4。
- プライベートブラウジングモードやシークレットモードでは、最後のプライベートタブが閉じられた際にデータがクリアされます 4。
また、ブラウザはストレージ全体の圧迫(ディスク容量の逼迫など)が生じた場合に、Least Recently Used (LRU) ポリシーに基づいてデータを削除することがあります 1。ローカルストレージ自体がそのクォータに達する前にLRUの対象となることは一般的ではありませんが、IndexedDBなど他のAPIで「ベストエフォート」ストレージが使用されている場合、オリジン全体のブラウザストレージが影響を受ける可能性はあります。
「永続的」という言葉は、ある程度の修飾が必要です。APIの観点からは永続的(クッキーのようなsetMaxAgeは存在しない)ですが、ユーザーの操作やブラウザのポリシーによってデータが失われる可能性は否定できません。この点は、ローカルストレージを唯一の信頼できる情報源として重要なデータを扱う場合の信頼性に影響します。「有効期限なし」4 という記述は、ユーザーによるキャッシュクリア 4 やプライベートブラウジングでのデータ消去 4 といったシナリオを考慮すると、条件付きであることがわかります。Chromeチームの調査によれば、ユーザー操作やクォータ問題以外でブラウザによってデータが削除されることは「非常に稀」であるとされていますが 1、「有効期限なし」が決して「無期限に安全」を意味するわけではないことを理解しておく必要があります。このため、データの損失が致命的な場合(例:「未保存の下書きはブラウザに保存されています。ブラウザデータを消去すると削除されます」といった通知)は、その旨をユーザーに伝えるなどの配慮が求められます。
2.4. APIの同期性:ブロッキングの性質とパフォーマンスへの影響
ローカルストレージのAPI操作(setItem、getItemなど)は同期的です 5。これは、これらの操作が完了するまでJavaScriptのメインスレッドがブロックされることを意味します 5。
この同期的な性質は、特に大量のデータを扱ったり、頻繁な操作を行ったりする場合に、パフォーマンスの低下を引き起こす可能性があります。結果として、ユーザーインターフェースが応答しなくなる、いわゆる「ジャンク」が発生することがあります 12。ある資料では、「ローカルストレージを使用する複雑なアプリケーションは速度が低下し、使い物にならなくなる」と指摘されています 14。また別の資料では、「ローカルストレージは非同期ではないブロッキングAPIとして動作し、メインスレッドをブロックする可能性があり、アプリケーションのパフォーマンス低下につながる」と述べられています 12。
この同期的な性質は、特にシングルページアプリケーション(SPA)など、現代のウェブ開発においてローカルストレージが抱える最も重大な技術的制約の一つと言えるでしょう。スムーズで応答性の高いユーザーインターフェースという目標と直接的に矛盾するためです。このため、パフォーマンスが重視されるタスクや、複雑なアプリケーションで頻繁にアクセス・変更されるデータの保存には不向きです。同期API(原因)がメインスレッドのブロッキング(中間的影響)を引き起こし、最終的にUIのジャンク、パフォーマンス低下、アプリケーションの無応答(最終的影響)につながるという因果関係を理解することが重要です。アプリケーションが多数の読み書きや大きなアイテムの保存を予期する場合には、これらの特定のタスクに対してローカルストレージの使用を避け、IndexedDBのような非同期の代替手段を優先すべきです 12。
2.5. スコープ:オリジンバウンドとその意味
ローカルストレージは、ドキュメントのオリジン(スキーム、ホスト名、ポート番号の組み合わせ)によってスコープが決定されます 4。これは、例えばhttp://example.comによって保存されたデータは、https://example.comやhttp://sub.example.comからアクセスできるデータとは分離されることを意味します 4。
さらに、データはブラウザベンダーによっても区分されます。例えば、Chromeのローカルストレージに保存されたデータはFirefoxからは読み取れません 15。iframeに関しては、iframe自身のオリジンのローカルストレージにアクセスできます。親ドキュメントやクロスオリジンのiframeのローカルストレージへのアクセスは、同一オリジンポリシーによって制限されます。ただし、サードパーティのiframeがアクセスを要求するためにStorage Access API 16 を利用できるケースもあります。
オリジンバウンドという性質は、異なるサイト間でのデータ漏洩を防ぐための基本的なセキュリティ機能です。しかし、サブドメイン間やプロトコル変更時にデータを共有したい正当なシナリオにおいては、これが障害となり、より複雑な解決策が必要になることもあります。このスコープ設定は、クライアントサイドストレージにおける同一オリジンポリシーの直接的な実装です。セキュリティには有益ですが、サイトがHTTPからHTTPSに移行した場合、ローカルストレージは実質的に「新規」のものとして扱われます。同様に、www.example.comとapp.example.comは別々のローカルストレージを持ちます。このため、複数のサブドメインやプロトコルにまたがり、クライアントサイドの状態を共有する必要があるアプリケーションでは、慎重な計画が不可欠です。
2.6. file: URLおよびプライベートブラウジングでの挙動
file: URL(ローカルファイルシステムから直接ブラウザで開かれたファイル)におけるローカルストレージの挙動は未定義であり、ブラウザによって異なる可能性があります 4。現在のブラウザは各file: URLに対して一意のストレージ領域を割り当てる傾向にありますが、これは保証されていません 4。したがって、開発者はローカルHTMLファイルにおけるローカルストレージの永続的な保存機能に依存すべきではありません。
プライベートブラウジングモード(シークレットモードなど)では、ローカルストレージに作成されたデータは、通常、最後のプライベートタブが閉じられた時点で消去されます 4。一部のブラウザ(例えば、モバイルSafariやモバイルChromeのプライベートモード)では、ストレージ容量が0KBとして扱われ、実質的に無効化されることもあります 15。
file: URLでの信頼性の欠如は、永続的なストレージが要件となる場合に、単純なHTMLファイルとして配布されるオフラインアプリケーションにとってローカルストレージが不適切であることを意味します。また、プライベートモードでの挙動は、ユーザーがこのモードを頻繁に利用する場合、アプリケーションがローカルストレージの長期的な永続性に依存できないことを示唆しています。これらの制約から、ローカルストレージの有用性は主にウェブサーバーから配信されるアプリケーションを標準的なブラウジングコンテキストで使用する場合に限定されると言えます。ローカルでの使用を目的としたツールを開発する場合や、あらゆるブラウジングモードで保証された永続性が必要な場合は、これらの制限を認識しておく必要があります。
3. ローカルストレージの実用的なアプリケーションと一般的なユースケース
3.1. ユーザー設定の保存
ローカルストレージの一般的な活用例として、ユーザーインターフェースのテーマ(ダークモード/ライトモード)、言語設定、フォントサイズ、レイアウトの選択、ユーザーが操作する機能のオン/オフ切り替えといったユーザー設定の保存が挙げられます 4。例えば、ダークモードの設定をローカルストレージに保存しておけば、ユーザーが次回サイトを訪れた際に同じモードで表示できます 18。
このユースケースの利点は、サーバーとの通信なしにユーザーの選択をセッション間で記憶し、一貫したユーザーエクスペリエンスを提供できる点にあります。保存されるデータは通常小さく(例:「”dark_mode”: “true”」のような文字列)、ローカルストレージの容量制限内で十分に扱え、永続性という特性が活かされます。このような設定の読み込み(ページロード時)や書き込み(ユーザーが設定変更時)は頻度が低いため、同期APIであることのパフォーマンスへの影響も比較的小さいと考えられます。
3.2. アプリケーション状態の維持
シングルページアプリケーション(SPA)における現在のビュー、選択されたフィルター、ソート順、UI要素の状態(例:アコーディオンパネルの開閉状態)、フォーム入力中の下書き内容など、アプリケーションの一時的な状態を維持するためにもローカルストレージが利用されます 4。例えば、TinyMCEのようなリッチテキストエディタの内容をローカルストレージに保存する例もあります 11。
これにより、ページのリロード後やアプリケーションへの再訪時に状態を復元し、ユーザビリティを向上させることができます。ただし、これは重要度の低い状態に適しています。ReduxやVuexストアのような複雑な状態管理において、大規模な状態オブジェクトを頻繁にローカルストレージに直接書き出すと、同期的な書き込み処理と文字列化のオーバーヘッドによりパフォーマンス問題を引き起こす可能性があります。そのため、状態の主要な要素を選択的に永続化するアプローチがしばしば推奨されます。ローカルストレージは状態の主要な側面を永続化するために使用できますが、複雑なアプリケーションの主要なリアクティブストアとして機能させるべきではありません。
3.3. 重要度の低いアプリケーションデータのキャッシュ
重要度の低いAPIエンドポイントからのレスポンスや、頻繁には変更されないアイテムのリスト(例:カテゴリ、タグ)などをキャッシュするためにもローカルストレージが利用されることがあります。これにより、比較的静的なデータに対するサーバーへのリクエスト数を減らし、体感的なパフォーマンスを向上させることが期待できます 4。
この用途は、データが小さく、揮発性が低い場合に適しています。しかし、本格的なキャッシュ戦略や、完全なオフライン機能を実現するためのサービスワーカーの代替となるものではありません。5MBという容量制限と文字列のみという性質は、大規模なキャッシングには不向きです。ローカルストレージは単純なキャッシュとして機能しますが、高度なキャッシュ機構(例えばService WorkerのCache API 1)とは異なる位置づけです。
3.4. ローカルストレージが適したシナリオと避けるべきシナリオ
ローカルストレージの利用を検討する際には、その特性を理解し、アプリケーションの要件と照らし合わせることが重要です。
適したシナリオ 11:
- 少量のキーバリューデータの保存。
- ユーザー設定(テーマ、言語など)。
- 単純なアプリケーション状態の永続化。
- 重要度の低い機能のための基本的なオフラインデータ。
- 使いやすさから、テストや迅速なプロトタイピングにも適しています 11。
避けるべきシナリオ 4:
- 機密情報(パスワード、個人識別情報、重要なトークンなど)の保存 8。
- 大規模または複雑なデータ構造の保存(IndexedDBの使用を検討)。
- 頻繁かつ大量の読み書き操作が必要なアプリケーション(パフォーマンス問題の可能性)。
- 複雑なクエリやインデックス作成が必要な場合(IndexedDBの使用を検討)。
- ウェブワーカーからアクセスする必要があるデータ(ローカルストレージはワーカーから利用不可 14)。
ローカルストレージを使用するかの判断は、そのシンプルさと、同期性、容量、文字列のみといった制約とのトレードオフにかかっています。アプリケーションのデータの特性とパフォーマンス要件を明確に理解することが不可欠です。ローカルストレージは「軽量な」タスクに適しており 12、データが「重く」(大規模、複雑、頻繁にアクセスされる)なると、ローカルストレージの使用はアンチパターンとなる可能性があります。
4. ローカルストレージ利用の利点と制限
4.1. 利点
ローカルストレージの採用には、いくつかの明確な利点があります。
- シンプルさと使いやすさ: APIは最小限の構成で、学習と実装が容易です 3。複雑な初期設定も不要です 3。
- クッキーよりも大きな容量: 一般的に約5MBから10MBの容量を持ち、クッキーの約4KBと比較して大幅に大きいです 2。
- クライアントサイドでの操作: データはHTTPリクエストごとに自動的にサーバーへ送信されないため、クッキーと比較してネットワークトラフィックとサーバー負荷を削減できます 3。
- セッションを跨いだ永続性: ブラウザを閉じて再度開いた後もデータが利用可能です 3。
- 幅広いブラウザサポート: ほぼ全ての最新デスクトップおよびモバイルブラウザでサポートされています 3。2018年12月時点で93.87%のカバー率との報告もあります 3。
これらの利点、特にシンプルさ、十分な容量(意図された用途において)、そして永続性の組み合わせは、高度な機能を必要としない多くの一般的なクライアントサイドストレージのニーズにとって、ローカルストレージを魅力的な選択肢にしています。ただし、これらの利点は、ローカルストレージがその適切な範囲内で使用された場合に最も顕著になります。例えば、「クッキーよりも大きな容量」は利点ですが、この容量はIndexedDBと比較すると依然として小さいものです。
4.2. 欠点
一方で、ローカルストレージには無視できないいくつかの欠点も存在します。
- 同期API: メインスレッドをブロックするため、特に大量のデータや頻繁な操作を行う場合にパフォーマンス問題やUIの無応答を引き起こす可能性があります 5。これは現代のインタラクティブなアプリケーションにとって大きな懸念事項です。
- 文字列のみの保存: 文字列しか保存できません。オブジェクトや他のデータ型はシリアライズ/デシリアライズ(例:JSON.stringify/parse)が必要で、これによりオーバーヘッドと複雑性が増します 4。
- 限定的な容量: 約5MBから10MBという容量は、大量のデータを保存する必要があるアプリケーションにとっては不十分な場合があります 1。
- インデックス作成とクエリ機能の欠如: インデックス作成や複雑なクエリの組み込みサポートがありません。特定のデータを取得するには、キーを反復処理したり、全データを取得してJavaScriptでフィルタリングしたりする必要があり、大規模なデータセットに対しては非効率です 12。
- セキュリティ上の懸念: データは同一オリジンで実行される全てのJavaScriptからアクセス可能であるため、XSS(クロスサイトスクリプティング)攻撃に対して脆弱です。機密データの保存には適していません 4。
- Web Workerからのアクセス不可: ローカルストレージAPIはWeb Workerから直接アクセスできません 14。これにより、ストレージ操作をメインスレッドからオフロードする用途での利用が制限されます。
- タブブロッキングの可能性: あるタブでのローカルストレージの重い操作が、CPUリソースの競合により、同一オリジンの他のタブのパフォーマンスに影響を与える可能性があります 12。
これらの欠点の中でも、同期的な性質とセキュリティの脆弱性は特に深刻です。開発者はこれらの点を鋭敏に認識し、緩和策を計画するか、これらの欠点がアプリケーションの要件と矛盾する場合には代替ストレージを選択する必要があります。同期APIとその悪影響に関する指摘 12 は特に重要です。また、セキュリティ面 4 も特定のデータ型にとっては大きな危険信号となります。Web Workerからのアクセス不可 14 は、メインスレッドから処理を移してパフォーマンスを最適化しようとする開発者にとって実用的な制約です。これらの欠点が総合的にローカルストレージの有用性の境界を定義しています。
5. セキュリティ詳細:ローカルストレージのリスクと緩和戦略
5.1. 主要な脅威:クロスサイトスクリプティング(XSS)
クロスサイトスクリプティング(XSS)攻撃は、攻撃者が悪意のあるスクリプトをウェブページに注入し、他のユーザーのブラウザ上で実行させる攻撃手法です 19。ローカルストレージは、同一オリジン上で動作するJavaScriptからwindow.localStorageを介してアクセス可能であるため、そのオリジンにXSS脆弱性が存在する場合、ローカルストレージに保存されたデータが盗難されたり、改ざんされたりする危険性があります 14。ある資料では、「ローカルストレージはあらゆるJavaScriptコードから自由にアクセスできてしまう」「これはセキュリティ上非常に重大な問題だ」と警鐘を鳴らしています 14。
XSS攻撃には、主に反射型XSS、格納型XSS、DOMベースXSSといった種類があります 20。特に格納型XSSは、悪意のあるスクリプトがサーバーに永続的に保存され、ユーザーがその情報を要求するたびに実行されるため、被害が広範囲に及ぶ可能性があります。
JavaScriptによるアクセスの容易さが、XSS脆弱性が存在する場合にローカルストレージを格好の標的にしてしまいます。このため、ローカルストレージに少しでも機密性の高いデータや状態を変更しうるデータを保持する場合は、アプリケーションをXSSから保護することが最重要課題となります。XSS脆弱性によって任意のJavaScript実行が可能になる(原因)と、そのJavaScriptがwindow.localStorageにアクセスできる(メカニズム)ため、ローカルストレージ内のデータが盗まれたり操作されたりする(結果)という因果関係を理解する必要があります。
5.2. データ保存に関するベストプラクティス
ローカルストレージを安全に利用するための最も基本的な原則は、機密情報の保存を避けることです。パスワード、クレジットカード番号、暗号化されていない個人のプライベートデータ、重要なセッショントークンなどを直接ローカルストレージに保存すべきではありません 4。ある資料では、「個人情報:パスワードやクレジットカード番号は絶対に保存しない」と明記されています 18。
潜在的に機密性の高い設定データなどを保存する場合は、それが攻撃者によって読み取られた場合に悪用される可能性がないかを慎重に評価する必要があります。この「機密情報を保存しない」というルールは、ローカルストレージ利用における黄金律と言えます。仮にXSS攻撃によってローカルストレージからデータが漏洩したとしても、その影響を最小限に抑えるべきです。データが非常に機密性の高いものであれば、漏洩時の影響は甚大になります。この原則は、ローカルストレージのXSS脆弱性 14 の直接的な帰結であり、XSS経由で容易にアクセスできる場所に価値のあるものを置かない、というシンプルな論理に基づいています。
5.3. XSSの緩和技術
ローカルストレージの内容を保護する最善の間接的な方法は、XSS攻撃そのものを防ぐことです。主なXSS対策は以下の通りです。
- 入力サニタイズ/出力エンコーディング: 最も重要な対策です。ユーザーから提供された全ての入力を、ページに表示したり、スクリプト実行につながる可能性のある方法で使用したりする前に、適切にサニタイズ(無害化)します。また、出力先のコンテキスト(HTML、HTML属性、JavaScript、CSS、URL)に応じて適切なエンコーディングを施します 22。例えば、HTMLコンテキストではhtmlspecialchars()、JavaScriptコンテキストではjson_encode()といった関数が利用できます 23。OWASPの資料では、異なるコンテキストでのエンコーディングと安全なシンク(データ出力先)の使用が強調されています 22。
- コンテンツセキュリティポリシー(CSP): 強力な多層防御メカニズムです。CSPを使用すると、コンテンツ(スクリプト、スタイル、画像など)の信頼できるソースのホワイトリストを定義でき、意図しないソースからの悪意のあるスクリプトの実行をブラウザが防ぐことで、XSSのリスクを大幅に軽減できます 22。ただし、CSPは主要な防御策としてではなく、多層防御の一環として、各アプリケーションに合わせてカスタマイズして使用することが推奨されます 22。
- 最新のウェブフレームワークの活用: 多くのフレームワークには、XSS対策機能(例:テンプレートエンジンにおける自動出力エンコーディング)が組み込まれています 22。使用しているフレームワークがどのようにXSSを処理し、どのような制限があるかを理解することが重要です。
- HTMLサニタイズライブラリ: ユーザーがHTMLを送信する必要がある場合(例:WYSIWYGエディタ)、堅牢なHTMLサニタイズライブラリ(例:DOMPurify)を使用します 22。
これらの対策は一般的なXSS対策ですが、XSSがローカルストレージ侵害の主要な経路であるため 14、XSSを防ぐこと(原因)がローカルストレージのデータを直接保護する(結果)ことにつながります。特にCSP 22 は、実行可能なスクリプト自体を制限することで、ローカルストレージへのアクセスを保護する強力な障壁として機能します。
5.4. 安全なトークン管理(ローカルストレージをトークン保存に検討する場合)
アクセストークンや機密性の高いリフレッシュトークンなどのトークンをローカルストレージに保存することは、XSSリスクのため一般的に推奨されません 19。
もしローカルストレージをトークン保存に利用せざるを得ない場合の対策としては、以下のようなものが考えられます。
- リフレッシュトークンのローテーション: リフレッシュトークンを使用する場合、使用するたびに古いトークンを無効化し、新しいトークンを発行するローテーションを実装します。これにより、盗まれたトークンの有効期間が限定されます 19。
- 短命なアクセストークン: アクセストークンの有効期限を短く設定します。
- 機密トークンに対するHttpOnlyクッキーの使用: リフレッシュトークンやセッショントークンを保存するためのより安全な代替手段は、HttpOnly属性を持つクッキーを使用することです。これらのクッキーはJavaScriptからアクセスできないため、XSSベースのトークン盗難を緩和できます 19。アプリケーションはその後、これらのクッキーを使用して新しいアクセストークンを要求し、アクセストークンはJavaScriptメモリ内に保持することができます。
- Backend for Frontend (BFF) パターン: SPAの場合、BFFを利用してトークン管理をサーバーサイドで行い、クライアントブラウザからトークン処理を完全に抽象化する方法も推奨されます 19。
トークンがクライアントサイドにあり、JavaScriptからアクセス可能である必要がある場合(例:API呼び出し用のアクセストークン)、それを囲むアプリケーションはXSSに対して極めて堅牢でなければなりません。より機密性の高いリフレッシュトークンなどについては、HttpOnlyクッキーが優れたアプローチです。トークン保存におけるセキュリティ対策には階層があり、BFFパターン > HttpOnlyクッキー > 緩和策を伴うローカルストレージ > 緩和策なしのローカルストレージ(非常に危険)の順で安全性が高いと言えます。
6. ウェブストレージエコシステムにおけるローカルストレージ:比較分析
6.1. ローカルストレージ vs. セッションストレージ
ローカルストレージとセッションストレージの最も大きな違いは、データの寿命です。ローカルストレージのデータは明示的に削除されるまで永続しますが、セッションストレージのデータはページセッションが終了する(タブやウィンドウが閉じられる)と消去されます 3。
スコープに関しては、両者ともオリジンバウンドです。しかし、セッションストレージはタブ固有でもあり、同一オリジンであっても、あるタブのデータは他のタブからはアクセスできません 5。一方、ローカルストレージは同一オリジンの全てのタブ/ウィンドウで共有されます。
容量については、両者とも同程度(通常それぞれ5MB、オリジンあたり合計10MBのWeb Storage制限に寄与)です 1。
主なユースケースは以下の通りです。
- ローカルストレージ: 長期的なユーザー設定、アプリケーション設定。
- セッションストレージ: 単一セッション用の一時データ(フォーム入力値、ログイン前のショッピングカート内容、複数ステッププロセスの現在状態など)3。
どちらを選択するかは、主に必要なデータの寿命と、データをタブごとに分離する必要があるか共有する必要があるかによって決まります。セッションストレージは、タブ内の単一ユーザーワークフローに対して本質的に「プライベート」な性質を持ちます。このタブ固有のスコープ 5 は、例えば複数のタブでアプリケーションの異なるインスタンスを開いた場合に状態が衝突するのを防ぐといったユースケースで重要な違いとなります。
6.2. ローカルストレージ vs. クッキー
ローカルストレージとクッキーの主な違いは以下の通りです。
- データ送信: クッキーはそのドメインへの全てのHTTPリクエストと共に送信され、リクエストのオーバーヘッドを増大させます。ローカルストレージのデータは自動的には送信されません 1。
- 容量: ローカルストレージ(約5MB~10MB)はクッキー(約4KB)よりもはるかに大容量です 2。
- アクセシビリティ: ローカルストレージはクライアントサイド(JavaScript)からのみアクセス可能です。クッキーはサーバーサイドとクライアントサイドの両方からアクセスできます(HttpOnly属性が指定されていない場合)8。
- 有効期限: ローカルストレージには組み込みの有効期限がありません。クッキーはExpires属性やMax-Age属性で有効期限を設定できます 3。
- 主なユースケース:
- ローカルストレージ: クライアントサイドのデータ永続化(設定、アプリ状態)。
- クッキー: セッション管理(セッションID)、トラッキング、サーバーサイドでの状態認識 3。
一般的に、クライアントサイドのデータ保存には、容量が大きくネットワークリクエストに影響を与えないローカルストレージがクッキーよりも好まれます。クッキーはサーバーサイドのセッション管理において依然として不可欠です。HTTPリクエストと共にクッキーが自動送信されるという特性 1 は、純粋なクライアントサイドデータにはクッキーを避けるべき理由となります。この点と容量の差 2 から、ローカルストレージは設計された目的に対してより良い選択肢となります。HttpOnlyクッキーは、クライアントサイドJSの目的においてはローカルストレージとは異なる性質を持つセキュリティ機能です。
6.3. ローカルストレージ vs. IndexedDB
ローカルストレージとIndexedDBは、クライアントサイドストレージの中でも特に機能面で大きな違いがあります。
- データ型と構造: ローカルストレージは文字列(キーバリュー)を保存します。IndexedDBは複雑なJavaScriptオブジェクト、ファイル、Blobを保存でき、オブジェクトストアとインデックスによる構造化データをサポートします 1。
- 容量: IndexedDBははるかに大きなストレージ容量を提供します(数十MBから数百MB、ディスク容量によってはGB単位も可能)1。Chromiumベースのブラウザではディスク容量の最大80%まで使用できるとの報告もあります 2。
- APIの同期性: ローカルストレージは同期的です。IndexedDBは非同期的(ノンブロッキング)で、リクエストとイベントハンドラを使用します 2。
- クエリ: ローカルストレージにはクエリ機能がありません。IndexedDBはインデックスをサポートし、これらのインデックスに基づいてデータをクエリできるため、効率的なデータ取得が可能です 2。
- 複雑性: ローカルストレージAPIは非常にシンプルです。IndexedDB APIはより複雑でイベント駆動型です 11。
- Web Workerからのアクセス: IndexedDBはWeb Workerからアクセス可能です。ローカルストレージはアクセスできません 14。
- ユースケース:
- ローカルストレージ: 単純なキーバリューストレージ、ユーザー設定。
- IndexedDB: 大規模データセット、オフラインアプリケーション、複雑なデータ構造、効率的なクエリやワーカーでのバックグラウンドデータ処理が必要なアプリケーション 2。 ある資料では、「IndexedDBはキーバリューペアだけでなくJSONドキュメントも保存するように設計されている」と述べられています 12。
IndexedDBは、ローカルストレージの制約(同期性、容量、文字列のみ、クエリ不可)が問題となるような、より複雑なクライアントサイドストレージのニーズに対応する、より強力なデータベースライクなソリューションです。その代償としてAPIの複雑性が増します。IndexedDBの非同期性 12 は、ローカルストレージの主要なパフォーマンスボトルネックに対する直接的な解決策です。複雑なオブジェクトを保存できる能力 2 やクエリのサポート 2 は、ローカルストレージの他の主要な制約に対処します。これにより、クライアントサイドのストレージニーズがより高度になった場合に、IndexedDBが「次のステップアップ」として位置づけられます。
6.4. その他の技術(文脈理解のため)
ローカルストレージ以外にも、特定のニーズに応えるクライアントサイドストレージ技術が存在します。
- オリジンプライベートファイルシステム (OPFS): 高パフォーマンスなファイルアクセス、バイナリデータの保存に適しています 1。直接的なファイルシステムライクな操作を提供します。
- WASM-SQLite: WebAssemblyを介してブラウザ内でSQLiteを実行可能にし、永続化にはIndexedDBやOPFSを利用することが多いです。完全なSQL機能を提供します 2。
- Cache API: Service Workerの一部であり、HTTPリクエスト/レスポンスペアを保存し、主にオフラインサポートとパフォーマンス向上のために使用されます 1。
これらのより専門的なAPIの存在は、ローカルストレージが汎用的でシンプルなストレージソリューションであり、より特定的または高度なニーズ(大容量ファイル、SQL、ネットワークキャッシング)には他のツールがより適切であることを示しています。これらの技術の特定の機能(OPFSのファイル操作、WASM-SQLiteのSQL、Cache APIのネットワークレスポンス)は、ローカルストレージの単純なキーバリュー文字列ストレージとは明確に区別され、ローカルストレージの設計範囲をはるかに超えるユースケースに対応します。
表1:クライアントサイドストレージメカニズムの比較分析
| 特徴 | ローカルストレージ (LocalStorage) | セッションストレージ (SessionStorage) | クッキー (Cookies) | IndexedDB |
| データの寿命 | 明示的な削除まで永続 | タブ/ウィンドウが閉じられるまで | 設定された有効期限まで(セッションクッキーはブラウザ終了時) | 明示的な削除まで永続 |
| 容量 | 約5MB~10MB/オリジン | 約5MB/オリジン | 約4KB/ドメイン | 数十MB~数GB以上(ディスク容量に依存) |
| データ形式 | 文字列(キーバリュー) | 文字列(キーバリュー) | 文字列 | 複雑なJSオブジェクト、ファイル、Blobなど |
| サーバーとの連携 | 自動送信なし | 自動送信なし | HTTPリクエスト毎に自動送信 | 自動送信なし |
| APIの同期性 | 同期 | 同期 | (適用外 – 主にHTTPヘッダ経由) | 非同期 |
| クエリ機能 | なし | なし | なし | インデックスを利用した高度なクエリが可能 |
| 主なユースケース | ユーザー設定、アプリ状態の永続化 | 一時的なデータ保存(フォーム入力値など) | セッション管理、トラッキング | 大規模データ、オフラインアプリ、複雑なデータ構造 |
| XSS脆弱性 (JSアクセス) | あり (同一オリジンからのJSでアクセス可能) | あり (同一オリジンからのJSでアクセス可能) | あり (HttpOnly属性なしの場合) | あり (同一オリジンからのJSでアクセス可能、ただし非同期APIのため直接的な同期アクセスとは異なる) |
データソース: 1
この表は、開発者が特定のタスクに最適なストレージメカニズムを選択する際の迅速な意思決定を支援します。
7. 開発者ツールキット:ローカルストレージの操作とデバッグ
7.1. 主要APIメソッドとJavaScriptの例
ローカルストレージの操作は、いくつかの基本的なAPIメソッドを通じて行われます。
- localStorage.setItem(key, value): 指定されたキーと値のペアをローカルストレージに追加、またはキーが既に存在する場合は値を更新します 4。
- 例: localStorage.setItem(‘username’, ‘john_doe’); 12
- localStorage.getItem(key): 指定されたキーに対応する値を取得します。キーが存在しない場合はnullを返します 4。
- 例: const user = localStorage.getItem(‘username’); 12
- localStorage.removeItem(key): 指定されたキーと値のペアを削除します 4。
- 例: localStorage.removeItem(‘username’); 12
- localStorage.clear(): そのオリジンの全てのキーと値のペアを削除します 4。
- 例: localStorage.clear();
- localStorage.length: 読み取り専用プロパティで、保存されているアイテムの数を返します。
- localStorage.key(index): 指定されたインデックスにあるキーの名前を返します。
これらのAPIは意図的にシンプルに設計されています。習熟のためには、文字列変換の必要性や、クォータ超過エラー、JSONパースエラーなどのエラーハンドリングを理解することが重要です。このシンプルさは特徴である一方、型付けされたストレージや名前空間のようなより複雑なロジックは開発者自身が構築する必要があることを意味します。
表2:ローカルストレージAPIメソッド概要
| メソッド | 説明 | パラメータ | 戻り値 | 例 |
| setItem(keyName, keyValue) | キーと値のペアを追加または更新します。 | keyName (文字列), keyValue (文字列) | undefined | localStorage.setItem(‘theme’, ‘dark’); |
| getItem(keyName) | 指定されたキーの値を取得します。 | keyName (文字列) | 文字列 または null | const theme = localStorage.getItem(‘theme’); |
| removeItem(keyName) | 指定されたキーと値のペアを削除します。 | keyName (文字列) | undefined | localStorage.removeItem(‘theme’); |
| clear() | 全てのキーと値のペアを削除します。 | なし | undefined | localStorage.clear(); |
| length (プロパティ) | 保存されているアイテムの数を返します。 | なし | 数値 | const itemCount = localStorage.length; |
| key(index) | 指定されたインデックスにあるキーの名前を返します。 | index (数値) | 文字列 または null | const firstKey = localStorage.key(0); |
データソース: 4
7.2. JSONデータの取り扱い
ローカルストレージは文字列しか保存できないため、オブジェクトや配列のような複雑なデータ構造を保存するには、シリアライズとデシリアライズが必要です。
- オブジェクト/配列の保存: setItem()の前にJSON.stringify()を使用します 10。
- 例: localStorage.setItem(‘user’, JSON.stringify({ name: ‘Alex’, age: 30 })); 10
- オブジェクト/配列の取得: getItem()の後にJSON.parse()を使用します 10。
- 例: const userObj = JSON.parse(localStorage.getItem(‘user’)); 10
エラーハンドリングも重要です。JSON.parse()は、引数が有効なJSON文字列でない場合(例えば、getItem()がnullを返した場合や、保存されている文字列がJSON形式でない場合)にエラーをスローする可能性があります。そのため、try…catchブロックを使用して適切に処理する必要があります。このパターンは一般的ですが、getItemがnullや不正なJSON文字列を返した場合にJSON.parseが失敗する可能性があるという一般的な落とし穴があり、開発者はこれを防ぐ必要があります。
7.3. ブラウザ開発者ツールによるローカルストレージの検査
各主要ブラウザは、ローカルストレージの内容を検査し、デバッグするための開発者ツールを提供しています。
- Chrome: 「Application」タブ > 「Storage」セクション > 「Local Storage」を展開し、ドメインを選択します 24。キーと値のペアの表示、追加、編集、削除が可能です。
- Firefox: 「ストレージインスペクター」(Shift+F9、または「アプリケーション」タブ経由)> 「ローカルストレージ」を選択し、ドメインを選択します。
- Safari: 「開発」メニュー > 「Webインスペクタを表示」 > 「ストレージ」タブ > 「ローカルストレージ」。
- Edge: Chromeと同様に「Application」タブからアクセスできます。
これらのツールでは一般的に、キーと値の表示、新しいエントリの追加、既存エントリの変更、特定エントリの削除、全エントリのクリアといった操作が可能です 25。また、コンソールから直接localStorage.getItem(‘myKey’)のようにして対話的に操作することもできます 11。
開発者ツールは、ローカルストレージの使用状況をデバッグし、データを確認し、開発中にストレージを手動でクリアするために不可欠です。これにより、開発者は自分のコードが何をしているかを理解し、問題をデバッグすることが極めて容易になります。
7.4. ブラウザ互換性の概要
ローカルストレージは、全ての主要な最新デスクトップおよびモバイルブラウザで広くサポートされています 3。MDNの互換性テーブル 4 によれば、Chromeではバージョン4(2010年リリース)以降、Firefoxではバージョン3.5(2009年リリース)以降、Safariではバージョン4(2009年リリース)以降、Edgeではバージョン12(2015年リリース)以降で完全サポートされており、その歴史は長いです。2018年12月時点で「93.87%のカバー率」3 と報告されており、現在ではさらに高いと考えられます。
このため、ローカルストレージの基本機能を使用する上で、互換性が問題となることは、合理的に最新のブラウザ環境であればまずありません。これは、到達可能性の観点からローカルストレージを信頼できる選択肢にしています。この高い互換性は強力な利点です。
8. 高度なトピックと将来の展望
8.1. ストレージクォータ、削除基準、永続的ストレージ
ローカルストレージのクォータはオリジンあたり約5MBであることは既に述べました 1。ブラウザは、これを含むクライアントサイドストレージ全体を管理するためのメカニズムを備えています。
- ベストエフォートストレージ: ほとんどのデータのデフォルトの保存方法です。ストレージプレッシャー(ディスク容量の不足)が発生した場合、LRU(Least Recently Used)ポリシーに基づいて削除される可能性があります 1。
- 永続的ストレージ: オリジンはnavigator.storage.persist()メソッドを使用して永続的ストレージを要求できます。この方法で保存されたデータは、ユーザーが明示的に削除を選択しない限り、ブラウザによって自動的に削除されません 1。この永続的ストレージメカニズムは、主にIndexedDBやCache APIのようなAPIに適用されます。ローカルストレージ自体は一般的に「ベストエフォート」と見なされますが、調査によれば、ユーザー操作やクォータ問題以外でブラウザによってデータが削除されることは稀であるとされています 1。
ブラウザによっては、オリジンが使用できる総ストレージ容量に上限が設けられています(例:Firefoxではディスク容量の10%または10GiB、Chromiumベースではディスク容量の60%)1。
ローカルストレージは独自の単純なクォータを持っていますが、それはより大きなブラウザストレージエコシステム内に存在します。ブラウザがストレージ全体をどのように管理し、「永続的ストレージ」の概念(ローカルストレージ自体をAPI呼び出しで「永続的」にするものではないとしても)を理解することは、複数のストレージタイプを使用するアプリケーションにとって重要です。navigator.storage.persist()は主にIndexedDB/Cache API用ですが、ローカルストレージのデータが失われる可能性があること(例:ユーザーによるキャッシュクリア 6)を理解することは、それが絶対的に永続的ではないことを補強します。
8.2. 埋め込みコンテンツのためのStorage Access API
Storage Access APIは、サードパーティのコンテキスト(例:<iframe>内)で読み込まれたクロスサイトコンテンツが、そのファーストパーティ(パーティション化されていない)のクッキーやストレージへのアクセスを要求できるようにするものです 16。これは、プライバシー向上(トラッキング防止など)のためにブラウザがデフォルトでサードパーティのクッキー/ストレージアクセスをブロックする場合に関連します。
このAPIには、document.hasStorageAccess()(アクセス権の有無を確認)やdocument.requestStorageAccess()(アクセス権を要求)といったメソッドが含まれます 16。ブラウザによっては、ユーザーへのプロンプトが表示されることがあります 16。
ローカルストレージのコアな動作を直接変更するものではありませんが、Storage Access APIは、iframe内のローカルストレージ(または他のストレージ)が、通常はブロックされる可能性のある「通常の」パーティション化されていないストレージにアクセスする必要があるシナリオで重要となります。これは、ブラウザがサードパーティの制限を強化するにつれて、ますます重要になるAPIです。例えば、mainsite.comに埋め込まれたservice.comのiframeがlocalStorageを使用しようとすると、通常はmainsite.comに埋め込まれたservice.com用にパーティション化されたストレージにアクセスします。もしservice.comが(直接アクセスした場合と同様に)主要なservice.comのローカルストレージにアクセスしたい場合、特にサードパーティストレージがブロックされていれば、Storage Access APIが必要になります。
8.3. クライアントサイドストレージの将来
クライアントサイドストレージのトレンドとして、より大容量で、より高性能で、より高機能なストレージへのニーズが高まっていることが挙げられます(OPFSやWASM-SQLiteの登場がその証左です)。
ローカルストレージの役割は、その使いやすさと幅広いサポートにより、シンプルなユースケースにおいては今後も維持されるでしょう。しかし、複雑なデータ管理には向いていません。ローカルストレージ自体は成熟し安定したAPIであるため、新しいAPIや機能強化の可能性は低いと考えられます。その安定性は、信頼できるという利点であると同時に、新機能が期待できないという欠点でもあります。OPFSやWASM-SQLiteのような新しくより強力なAPI 2 の存在や、「ローカルファーストアプリ」2 に関する議論は、クライアントサイドの能力が将来はるかに大きくなることを示唆しています。ローカルストレージはそのニッチな用途で存続しますが、最先端の開発が集中する分野ではありません。
9. 結論と戦略的推奨事項
9.1. 現代のウェブ開発におけるローカルストレージの役割の要約
ローカルストレージは、シンプルで永続的なクライアントサイドのキーバリューストアとして、ウェブ開発において一定の地位を確立しています。その主な強みは、使いやすさ、小規模データに対する十分な容量、そして読み書きにおけるネットワークオーバーヘッドがない点です。
しかしながら、その利用には重大な弱点も伴います。同期APIであることによるパフォーマンスへの潜在的な悪影響、文字列しか保存できないことによるシリアライズ・デシリアライズのオーバーヘッド、XSS脆弱性によるセキュリティリスク、そしてクエリ機能の欠如は、特に現代の複雑なウェブアプリケーションにおいては無視できない制約となります。
9.2. 適切なクライアントサイドストレージソリューション選択のためのガイダンス
クライアントサイドストレージを選択する際には、アプリケーションの具体的な要件を慎重に評価する必要があります。
意思決定要因:
- データサイズと複雑性: 小規模で単純な文字列データであればローカルストレージが適していますが、大規模で複雑なオブジェクトの場合はIndexedDBが推奨されます。
- パフォーマンスニーズ: アクセス頻度が低い場合はローカルストレージでも問題ないかもしれませんが、頻繁なバルク操作やUIの応答性が重要な場合は、非同期APIを持つIndexedDBが適しています。
- クエリ要件: クエリが不要であればローカルストレージ、複雑なクエリやインデックス作成が必要であればIndexedDBを選択します。
- データの機密性: 機密性の低いデータであれば、XSS対策を施した上でローカルストレージを利用できますが、機密性の高いデータの場合はブラウザストレージを避け、サーバーサイドセッションやHttpOnlyクッキー(トークン用)などを検討すべきです。
- データの寿命: セッションを跨いで永続させたい場合はローカルストレージ、単一セッションのみであればセッションストレージが適しています。
- オフラインニーズ: 小規模データの基本的なキャッシュであればローカルストレージも利用可能ですが、堅牢なオフラインアプリケーションにはIndexedDB、Cache API、Service Workerの組み合わせがより適切です。
ローカルストレージは、そのトレードオフを理解した上で慎重に利用することが推奨されます。多くの現代的でデータ集約型のSPAにおいては、主要なアプリケーションデータには(使いやすさのためにラッパーライブラリを介することもあるでしょうが)IndexedDBがしばしばより適切な選択肢となります。
最終的に、ローカルストレージは価値のあるツールですが、万能な解決策ではありません。明確な要件に基づいた戦略的な選択が、堅牢でパフォーマンスが高く、安全なウェブアプリケーションを構築するための鍵となります。ローカルストレージを過度に使用したり、不適切なタスクに使用したりすることは、技術的負債やユーザーエクスペリエンスの低下につながる可能性があります。アプリケーションの要件(データサイズ、パフォーマンス、セキュリティ)をローカルストレージや代替手段(IndexedDB、セッションストレージ、クッキー)の特性と照らし合わせることで、開発者は情報に基づいた選択を行うことができます。ローカルストレージの制約(同期性、XSSリスク)は、それらの制約がユースケースにとって許容できない場合に、他のソリューションを選択する主な動機となります。
引用文献
- Storage quotas and eviction criteria – Web APIs – MDN Web Docs https://developer.mozilla.org/en-US/docs/Web/API/Storage_API/Storage_quotas_and_eviction_criteria
- LocalStorage vs. IndexedDB vs. Cookies vs. OPFS vs. WASM … https://rxdb.info/articles/localstorage-indexeddb-cookies-opfs-sqlite-wasm.html
- クッキーはもう古い!?HTML5 LocalStorageの使い方 https://wp.tech-style.info/archives/742
- Window: localStorage property – Web APIs | MDN https://developer.mozilla.org/en-US/docs/Web/API/Window/localStorage
- Web Storage API – Web APIs | MDN https://developer.mozilla.org/en-US/docs/Web/API/Web_Storage_API
- ReactとLocalStorage保存 #フロントエンド – Qiita https://qiita.com/ORCHESTRA_TAPE/items/720ee8431ed2bd2902a8
- ブラウザストレージ101:LocalStorage、SessionStorage、Cookieを比較 – Qiita https://qiita.com/minimabot/items/0053f3b897f5a36837a2
- ブラウザ標準データ保管機能まとめ:Cookie / SessionStorage … https://zenn.dev/tm35/articles/584ece2d771a4b
- Difference Between Local Storage, Session Storage And Cookies | GeeksforGeeks https://www.geeksforgeeks.org/difference-between-local-storage-session-storage-and-cookies/
- Storage: setItem() method – Web APIs – MDN Web Docs https://developer.mozilla.org/en-US/docs/Web/API/Storage/setItem
- JavaScript and localStorage in a nutshell with examples – TinyMCE https://www.tiny.cloud/blog/javascript-localstorage/
- Using localStorage in Modern Applications – A Comprehensive Guide | RxDB – JavaScript Database https://rxdb.info/articles/localstorage.html
- ブラウザのデータストレージについてまとめ – Zenn https://zenn.dev/osushi02/articles/4300b9b4dcac55
- HTML5のLocal Storageを使ってはいけない(翻訳) – TechRacho – BPS株式会社 https://techracho.bpsinc.jp/hachi8833/2024_04_05/80851
- Are there any benefits to Session Storage over Local Storage? – Stack Overflow https://stackoverflow.com/questions/5523140/are-there-any-benefits-to-session-storage-over-local-storage
- Storage Access API – MDN Web Docs – Mozilla https://developer.mozilla.org/en-US/docs/Web/API/Storage_Access_API
- コピペで使える!JavaScriptでローカルストレージを使用する方法 https://blog.future.ad.jp/%E3%82%B3%E3%83%94%E3%83%9A%E3%81%A7%E4%BD%BF%E3%81%88%E3%82%8Bjavascript%E3%81%A7%E3%83%AD%E3%83%BC%E3%82%AB%E3%83%AB%E3%82%B9%E3%83%88%E3%83%AC%E3%83%BC%E3%82%B8%E3%82%92%E4%BD%BF%E7%94%A8%E3%81%99%E3%82%8B%E6%96%B9%E6%B3%95
- セッションストレージ、クッキーの使い分け(使用する場面、判断基準も)|とま – note https://note.com/broccolinlin/n/ne8639d91d2ed
- トークン保管のベストプラクティス | CyberArk Docs https://docs.cyberark.com/wpm/latest/ja/content/developer/oidc/tokens/token-storage.htm
- Cross Site Scripting (XSS) – OWASP Foundation https://owasp.org/www-community/attacks/xss/
- ローカル保存は禁止すべき?ローカル保存が禁止される理由とリスク – セキュアSAMBA https://info.securesamba.com/media/14888/
- Cross Site Scripting Prevention – OWASP Cheat Sheet Series https://cheatsheetseries.owasp.org/cheatsheets/Cross_Site_Scripting_Prevention_Cheat_Sheet.html
- 【2025年最新】PHP脆弱性対策完全ガイド – 9つの危険な脆弱性と実践的な対策コード例 https://dexall.co.jp/articles/?p=3472
- How-to: View Local Storage in Chrome and Firefox – UI Vision https://ui.vision/howto/view-local-storage
- View and edit local storage | Chrome DevTools https://developer.chrome.com/docs/devtools/storage/localstorage



