こんにちは、Ryohei(@ityryohei)です!

Webアプリケーションにおいて、ユーザーの設定や認証トークンといったデータをブラウザ側に保持し、次回アクセス時にも利用できるようにするデータの永続化は不可欠です。この目的のために利用される主要なブラウザストレージ技術が、Web Storage(localStoragesessionStorage)とCookieです。

しかし、これらの技術は保存容量、有効期限、そして最も重要なセキュリティの側面に大きな違いがあります。誤った選択や不適切な使用は、アプリケーションのパフォーマンス低下や深刻なセキュリティリスク(例: XSS攻撃による情報漏洩)を招く可能性があります。

本記事では、localStorageとCookieの基本的な違いから、両者のメリット・デメリットを比較し、セキュリティリスクを最小限に抑えるための利用戦略と具体的な実装テクニックを徹底解説します。

ユーザーの認証トークンをどこに保存するのが一番安全で、CookieとlocalStorageのどちらを使うべき?

上記の疑問にお答えします。

1. 基礎知識:Web StorageとCookieの根本的な違い

localStorageとCookieはブラウザにデータを保存しますが、その目的、容量、そしてアクセス方法が大きく異なります。

1.1. Web Storage (localStorage / sessionStorage)

Web Storageは、より大容量のデータをフロントエンドで安全に保持するためにECMAScript標準とは別に策定されたAPIです。

特徴localStoragesessionStorage
有効期限永続的。ユーザーが明示的に削除するか、キャッシュをクリアするまで残る。セッション限り。タブまたはブラウザウィンドウを閉じると自動で削除される。
容量5MB〜10MB程度(ブラウザ依存)。5MB〜10MB程度。
サーバー送信なし。サーバーに自動送信されない。なし。サーバーに自動送信されない。
アクセスJavaScript (window.localStorage / window.sessionStorage) のみ。JavaScript のみ。

1.2. Cookie

Cookieは、本来サーバーとの状態管理のために設計された古い技術です。HTTPヘッダーを通じてサーバーとデータをやり取りします。

特徴Cookie
有効期限設定可能(セッション限り、または最大期限まで)。
容量4KB以下と非常に小さい。
サーバー送信あり。すべてのHTTPリクエストで自動的にサーバーへ送信される。
アクセスJavaScript (document.cookie) または HTTPヘッダー。

比較:永続化のユースケース

ストレージ最適なユースケース
localStorageユーザーのテーマ設定、UIの表示状態、長期間保持する非機密データ。
sessionStorageフォームの入力内容の一時保存、ワンタイムセッションの非機密データ。
Cookie認証トークン(特にHttpOnly属性を利用する場合)、サーバーでのセッション管理。

2. Web Storageの利用戦略とデータ構造化

localStorageは文字列としてのみデータを保存するため、オブジェクトや配列を扱うには前処理が必要です。

2.1. データ保存の基本とJSONによる構造化

localStorageはキーと値のペアを保存しますが、値は必ず文字列です。オブジェクトや配列を保存する場合は、JSON.stringify()で文字列に変換する必要があります。

JavaScript

const userSettings = { theme: 'dark', notifications: true };
const key = 'app_settings';

// 1. 保存: オブジェクトをJSON文字列に変換
localStorage.setItem(key, JSON.stringify(userSettings));

// 2. 取得: JSON文字列を元のオブジェクトに戻す
const storedValue = localStorage.getItem(key);
const settings = JSON.parse(storedValue);

console.log(settings.theme); // -> 'dark'

2.2. 容量制限とエラーハンドリング

Web Storageの容量(約5~10MB)を超えてデータを書き込もうとすると、ブラウザはQuotaExceededErrorを投げます。データを保存する際には、必ずエラーハンドリングを組み込むべきです。

JavaScript

function safeSetItem(key, value) {
  try {
    localStorage.setItem(key, value);
    return true;
  } catch (e) {
    if (e.name === 'QuotaExceededError') {
      console.warn("localStorageの容量を超過しました。");
      // 古いデータを削除するなどのリカバリ処理を実装
      return false;
    }
    console.error("localStorageへの書き込みエラー:", e);
    return false;
  }
}

3. Web StorageとCookieのセキュリティ考慮事項

ストレージ技術の選択において、最も重要な判断基準はセキュリティです。機密性の高い認証情報(例: アクセストークン)をどこに保存するかは、XSS攻撃への耐性に直結します。

3.1. 致命的なリスク:XSS攻撃とlocalStorage

localStorageに認証トークン(例: JWT)などの機密情報を保存することは、一般的に非推奨とされています。

  • XSS (Cross-Site Scripting) 攻撃:
    攻撃者がWebサイトに悪意のあるJavaScriptコードを注入(インジェクション)した場合、そのコードはwindow.localStorageに容易にアクセスし、保存されている認証トークンを外部サーバーへ盗み出すことができます。
  • アクセス制御の欠如:
    localStorageは、同じオリジン(ドメイン、プロトコル、ポート)であれば、すべてのJavaScriptから無制限にアクセス可能です。

3.2. Cookieによる安全性の向上:HttpOnly属性

認証トークンを安全に保持するための最も効果的な方法は、CookieとHttpOnly属性の組み合わせです。

属性役割セキュリティへの影響
HttpOnlyJavaScriptからのdocument.cookieによるアクセスを完全に禁止する。XSS攻撃が発生しても、攻撃者のJavaScriptはトークンを読み出せないため、情報漏洩リスクが大幅に減少する。
SecureHTTPS接続(暗号化された通信)でのみCookieを送信するように強制する。中間者攻撃(MITM)による盗聴リスクを防ぐ。
SameSite他サイトからのリクエスト時にCookieが送信されるか制御する。CSRF(Cross-Site Request Forgery)攻撃を防ぐのに役立つ。

結論:機密情報(特に認証トークン)は、サーバー側でHttpOnly属性を付けてCookieに保存するのが最も安全です。

最後に

フロントエンドでデータを永続化する際は、データの機密性と利用目的によってストレージを厳密に使い分ける必要があります。

データ特性推奨ストレージ理由と注意点
機密性が高い(認証トークン)Cookie(HttpOnly + SecureJavaScriptから隔離し、XSSによる盗難リスクを防ぐ。
非機密、長期間保持localStorage大容量で永続的。設定や非同期データのキャッシュに最適。
非機密、一時的sessionStorageセッション終了時に自動消去されるため、一時的な状態管理に利用。

これらのセキュリティ原則と利用戦略を理解し、堅牢なWebアプリケーションを構築しましょう。

以上、JavaScriptにおけるWeb StorageとCookieによるデータ永続化とセキュリティ戦略のご紹介でした!

この記事を書いた人

Ryohei

Webエンジニア / ブロガー

福岡のWeb制作会社に務めるWebエンジニアです。エンジニア歴は10年程で、好きな言語はPHPとJavaScriptです。本サイトは私がインプットしたWebに関する知識を整理し、共有することを目的に2015年から運営しています。Webに関するご相談があれば気軽にお問い合わせください。