BFF パターンとトークン保護のセキュリティモデル
概要
BFF (Backend for Frontend) は、SPA(シングルページアプリケーション)専用のサーバー側レイヤーを 置き、認証とトークン管理をサーバー側に集約する設計パターンです。ブラウザにアクセストークンや リフレッシュトークンを一切渡さないため、XSS によるトークン窃取という SPA 最大の弱点を構造的に解消します。
OAuth 2.0 Security Best Current Practice(RFC 9700)および IETF の "OAuth 2.0 for Browser-Based Applications" は、高いセキュリティを要するブラウザアプリに対して この BFF パターンを推奨しています。
本ドキュメントは BFF のセキュリティ上の動機と脅威モデルを扱います。.NET / YARP を使った具体的な 実装手順は BFF パターン with YARP、 UI アセットのホスティング戦略は BFF UIホスティング戦略 を参照してください。
なぜ BFF か:ブラウザにトークンを置くリスク
従来の SPA は、Authorization Code + PKCE フローでトークンを取得し、localStorage や
sessionStorage、あるいはメモリに保持して Authorization: Bearer ヘッダで API を呼び出します。
この方式には以下のリスクがあります。
| リスク | 説明 |
|---|---|
| XSS によるトークン窃取 | localStorage のトークンは、注入された任意の JavaScript から localStorage.getItem() で読み取れる |
| トークンの露出 | ブラウザの DevTools(Network / Application タブ)でトークンが見える |
| リフレッシュトークンのブラウザ保管 | 長命なリフレッシュトークンがブラウザ上にあると、流出時の被害が大きい |
| クライアントシークレット不在 | SPA は秘密を安全に保持できず、PKCE のみに依存する |
BFF はトークンをサーバー側にだけ置くことで、これらをまとめて排除します。
パブリッククライアント vs コンフィデンシャルクライアント
OAuth 2.0 のクライアントは、クライアントシークレットを安全に保持できるかどうかで2種類に分かれます。
- パブリッククライアント:シークレットを安全に保持できない。SPA・ネイティブモバイルアプリが該当。 認可コード横取り対策として PKCE が必須。
- コンフィデンシャルクライアント:シークレットを安全に保持できる。サーバー側アプリが該当。
BFF を導入すると、ブラウザアプリは「パブリッククライアント」から、サーバー側で動く コンフィデンシャルクライアントへと変わります。これによりクライアントシークレットによる強固な クライアント認証(PKCE との多層防御)が可能になります。
BFF の構成
BFF が担う責務は次のとおりです。
- 同一オリジン配信:SPA の静的ファイルと API プロキシを同一オリジンで提供(CORS 不要)。
- OIDC 認証:コンフィデンシャルクライアントとして Authorization Code + PKCE フローをサーバー側で実行。
- Cookie / セッション管理:ブラウザには
HttpOnly・Secure・SameSiteクッキー(中身は不透明な セッション参照のみ)を発行。トークン本体はサーバー側ストアに保管。 - CSRF 保護:Cookie 認証は CSRF 対策が必須(CSRF・SameSite・CSP 参照)。
- リバースプロキシ:API への転送時に Cookie を Bearer トークンへ変換し、トークンの期限確認・ 自動リフレッシュ・ローテーションを行う。
脅威モデル:BFF が防ぐもの・防がないもの
BFF の効果を正しく理解するうえで、最も重要なのが「トークン窃取」と「セッションライディング」の区別です。
| 脅威 | BFF の効果 |
|---|---|
| XSS によるトークン窃取(持ち出し) | ✅ 防げる。トークンはブラウザに存在せず、HttpOnly クッキーは JS から読めない |
| トークンのネットワーク露出 | ✅ 防げる。トークンはサーバー側にのみ存在 |
| API の外部公開 | ✅ 縮小できる。API を内部限定にし、BFF 経由に一本化 |
| XSS によるセッションライディング | ⚠️ 防げない。クッキーは自動送信されるため、注入スクリプトは BFF 経由で認証済み API を呼べる |
BFF は脅威を「トークン窃取」から「セッションライディング」へ移すだけです。XSS が成立すれば、攻撃者は トークンを盗めなくても、被害者のセッションで API を操作できます。したがって、厳格な CSP(Content Security Policy) と XSS の根本対策は引き続き必須です。
標準・ベストプラクティスとの対応
- RFC 9700(OAuth 2.0 Security BCP):機密性の高いブラウザアプリに BFF を推奨。
- IETF "OAuth 2.0 for Browser-Based Applications":トークンをブラウザに置かない構成を推奨。
- 「トークンはサーバー側に保持する」:これはトークン拘束(DPoP / mTLS) を不要にする最も簡単な方法でもあります。サーバー側保持なら盗まれるトークンがそもそも存在しません。
まとめ
- BFF は SPA のトークン管理をサーバー側に集約し、XSS によるトークン窃取を構造的に排除する。
- ブラウザアプリをコンフィデンシャルクライアント化し、クッキー(不透明なセッション参照)+ CSRF 保護で 認証する。
- BFF が防ぐのはトークン窃取であり、セッションライディングは防げない → CSP と XSS 対策は必須。
- 実装の詳細は YARP ベースの BFF 実装ドキュメントを参照。
関連ドキュメント
- BFF パターン with YARP(実装)
- BFF UIホスティング戦略
- CSRF・SameSite・CSP とXSS対策
- サーバーサイドトークンストアと分散セッション
- 送信者拘束トークン(DPoP / mTLS)
- OpenID Connect と OAuth 2.0
- HTTP-only Cookie 認証