インターネットドラフト ブラウザベースのアプリケーション向け OAuth 2.0 2025年12月
Parecki ほか 2026年6月7日に失効 [ページ]
ワーキンググループ:
Web Authorization Protocol
インターネットドラフト:
draft-ietf-oauth-browser-based-apps-26
公開日:
想定されるステータス:
Best Current Practice
失効日:
著者:
A. Parecki
Okta
P. De Ryck
Pragmatic Web Security
D. Waite
Ping Identity

ブラウザベースのアプリケーション向け OAuth 2.0

概要

本仕様は、OAuth 2.0 を使用するブラウザベースのアプリケーションを 開発する際に考慮しなければならない脅威、攻撃の影響、 セキュリティ上の考慮事項、およびベストプラクティスについて詳述します。

議論の場

この注記は、RFC として公開される前に削除される予定です。

この文書に関する議論は、 Web Authorization Protocol ワーキンググループのメーリングリスト(oauth@ietf.org)で行われ、 そのアーカイブは https://mailarchive.ietf.org/arch/browse/oauth/ にあります。

このドラフトのソースと課題トラッカーは、 https://github.com/oauth-wg/oauth-browser-based-apps にあります。

このメモの位置付け

このインターネットドラフトは、BCP 78 および BCP 79 の 規定に完全に準拠して提出されています。

インターネットドラフトは、Internet Engineering Task Force(IETF)の作業文書です。なお、他のグループも作業文書を インターネットドラフトとして配布する場合があります。現在のインターネットドラフトの一覧は https://datatracker.ietf.org/drafts/current/ にあります。

インターネットドラフトは最長 6 か月間有効なドラフト文書であり、 いつでも他の文書によって更新、置換、または廃止される可能性があります。 インターネットドラフトを参考資料として使用したり、「作業中」以外のものとして 引用したりすることは適切ではありません。

このインターネットドラフトは 2026年6月7日に失効します。

目次

1. はじめに

本仕様は、ブラウザ内で実行されるアプリケーションにおいて OAuth 2.0 クライアントを実装するための、さまざまなアーキテクチャパターンについて説明します。本仕様は、 ブラウザベースのアプリケーションにおけるセキュリティ上の課題を概説し、 さまざまなパターンがそれらの課題の一部にどのように対処できるかを分析します。

本書は、OAuth クライアントとして動作する JavaScript フロントエンドアプリケーション ([RFC6749] の Section 1.1 で定義)に焦点を当てます。これらは、アクセストークン、および任意でリフレッシュトークンを取得するために、 認可サーバー([RFC6749] の Section 1.1)と対話します。 クライアントはアクセストークンを使用して、リソースサーバー上の保護された リソース([RFC6749] の Section 1.1)にアクセスします。 OAuth を使用する場合、クライアント、認可サーバー、およびリソースサーバーは、 それぞれが同一の主体によって所有または運用されているかどうかにかかわらず、 すべて独立した当事者であると見なされます。

なお、多くの Web アプリケーションは、共通のドメイン上で動作する フロントエンドと API で構成されており、OAuth 2.0 に依存しないアーキテクチャを可能にします。 これについては Section 7.1 でより詳しく説明します。 このようなシナリオでは、フェデレーションされたユーザー認証に OpenID Connect [OpenID] を利用でき、その後アプリケーションが ユーザーの認証状態を維持します。このようなシナリオ (OpenID Connect の基礎仕様としてのみ OAuth 2.0 を使用するもの)は、 本仕様の範囲外です。

OAuth 2.0 および OpenID Connect を使用するネイティブアプリケーション開発者向けには、 これらの技術の統合を導く IETF BCP(best current practice)が公開されています。 この文書は正式には [RFC8252] または BCP212 として知られていますが、多くの場合、開発者がこれらの プラクティスを採用するのを支援する OpenID Foundation スポンサーのライブラリ群にちなみ、 "AppAuth" と呼ばれます。[RFC8252] は、 必要に応じて追加の OAuth 拡張を組み込むことを含め、ネイティブ アプリケーションにおいて OAuth クライアントを安全に実装する方法について、 具体的な推奨事項を示しています。

本仕様、OAuth 2.0 for Browser-Based Applications は、 ブラウザベースのアプリケーションのセキュリティ特性がネイティブ アプリケーションのものとは大きく異なることを強調するとともに、 OAuth クライアントをネイティブアプリケーションおよびブラウザベースの アプリケーションとして実装する際の類似点にも対応します。本書は、 OpenID Connect が追加の考慮事項を提供する箇所を除き、主に OAuth に焦点を当てています。

これらの推奨事項の多くは、OAuth 2.0 Security の Best Current Practice [RFC9700] から派生したものです。ブラウザベースのアプリケーションも、 これらの推奨事項に従うことが期待されるためです。本書は、 [RFC9700] で示されたさまざまな推奨事項を拡張し、さらに制限します。

2. 表記規則

本書における "MUST"、"MUST NOT"、"REQUIRED"、"SHALL"、"SHALL NOT"、"SHOULD"、"SHOULD NOT"、"RECOMMENDED"、"NOT RECOMMENDED"、 "MAY"、および "OPTIONAL" というキーワードは、 ここに示すようにすべて大文字で出現する場合に限り、BCP 14 [RFC2119] [RFC8174] で説明されているように解釈されます。

3. 用語

本仕様では、OAuth 2.0 [RFC6749] によって定義される "access token"、"authorization endpoint"、 "authorization grant"、"authorization server"、"client"、"client identifier"(client ID)、"protected resource"、"refresh token"、"resource owner"、"resource server"、および "token endpoint" という用語、 ならびに [RFC6750] によって定義される "bearer token" を使用します。

参照仕様で定義されている用語に加えて、本書では 次の用語を使用します。

"OAuth":

本書において、"OAuth" は OAuth 2.0、 [RFC6749] および [RFC6750] を指します。

"Browser-based application":

Web ブラウザ内で動的にダウンロードされ実行されるアプリケーションであり、 通常は JavaScript で記述されます。"single-page application" または "SPA" と呼ばれることもあります。

本書では、ブラウザによってランタイム環境内で実行される ブラウザベースのアプリケーションのセキュリティについて説明します。ほとんどのシナリオでは、 これらのアプリケーションは JavaScript 実行環境で動作する JavaScript(JS) アプリケーションです。このシナリオが広く普及していることを踏まえ、本書では、 アプリケーションのブラウザ内ランタイムでコードを実行できるようにするすべての仕組みを指して "JavaScript" という用語を使用します。本書の推奨事項および考慮事項は、 JavaScript 言語またはそのランタイムだけに結び付くものではなく、 Web Assembly([W3C.wasm-core-2])など、ブラウザ内の他の言語および ランタイム環境にも適用されます。

"PKCE":

Proof Key for Code Exchange(PKCE) [RFC7636] は、OAuth 認可コードに対する さまざまな攻撃を防止する仕組みです。

"DPoP":

OAuth 2.0 Demonstrating of Proof of Possession(DPoP) [RFC9449] は、アクセストークンを それが発行されたクライアントだけが使用できるように制限する仕組みです。

"CORS":

Cross-Origin Resource Sharing [Fetch] は、ブラウザの同一オリジンポリシーに対する 例外を可能にする仕組みです。

"CSP":

Content Security Policy [W3C.CSP3] は、特定の Web ページが取得または実行できる リソースを制限する仕組みです。

4. ブラウザベースのアプリケーションにおける OAuth 2.0 の歴史

OAuth 2.0 が [RFC6749] および [RFC6750] で最初に規定された当時、 ブラウザベースの JavaScript アプリケーションには、同一オリジンポリシーに厳密に準拠する解決策が必要でした。 OAuth 2.0 の一般的なデプロイでは、アプリケーションが認可サーバーとは異なるドメインで 実行されていたため、クロスオリジン POST リクエストを必要とする Authorization Code grant type([RFC6749] の Section 4.1)を使用することは、 歴史的に不可能でした。この制限は、URL のフラグメント部分を通じて フロントチャネルでアクセストークンを返し、クロスオリジン POST リクエストの必要性を回避する Implicit フロー([RFC6749] の Section 4.2)の 定義の動機の 1 つでした。

しかし、Implicit フローには、一般に URL 内でアクセストークンが露出することに関連する 脆弱性を伴う、いくつかの欠点があります。これらの攻撃の分析と、 ブラウザで Implicit フローを使用することの欠点については、 Section 7.2 を参照してください。 追加の攻撃およびセキュリティ上の考慮事項は、 [RFC9700] にあります。

現代の Web 開発では、Cross-Origin Resource Sharing(CORS) [Fetch](同一オリジンポリシーに対する例外を可能にするもの) が広く採用されたことで、ブラウザベースのアプリケーションは OAuth 2.0 Authorization Code フローを使用し、トークンエンドポイントで認可コードをアクセストークンと交換するために POST リクエストを行えるようになりました。Authorization Code grant type は リフレッシュトークンの使用を可能にするため、この振る舞いはブラウザベースの クライアントにも採用されるようになりました。ただし、これらのクライアントは依然として 安全なストレージへのアクセスが限定的またはまったくない public client ([RFC6749] の Section 2.1 で定義) です。さらに、フローに Proof Key for Code Exchange(PKCE) [RFC7636] を追加することで、認可コードインジェクションを防止し、 また、認可コードが傍受された場合でも、それを攻撃者が使用できないようにします。

この理由およびその他の得られた教訓から、ブラウザベースのアプリケーションにおける 現在のベストプラクティスは、PKCE とともに OAuth 2.0 Authorization Code grant type を使用することです。 ブラウザベースのアプリケーションをデプロイするためのさまざまなアーキテクチャパターンがあり、 対応するサーバーサイドコンポーネントを伴うものと伴わないものがあります。これらの各アーキテクチャには、 本書でさらに説明する特定のトレードオフおよび考慮事項があります。 ファーストパーティの共通ドメインアプリケーションには、追加の考慮事項が適用されます。

5. 悪意ある JavaScript の脅威

悪意ある JavaScript は、ブラウザベースのアプリケーションに重大なリスクをもたらします。 クロスサイトスクリプティング(XSS)やリモートコードファイルの侵害などの攻撃ベクトルは、 攻撃者に、アプリケーションの実行コンテキスト内で任意のコードを実行する能力を与えます。 この悪意あるコードは、メインアプリケーションのコードからいかなる形でも分離されていません。 その結果、悪意あるコードは実行中の実行コンテキストを制御できるだけでなく、 アプリケーションのオリジン内でアクションを実行することもできます。具体的には、 悪意あるコードは現在のページからデータを窃取し、他の同一オリジンの閲覧コンテキストと対話し、 アプリケーションのオリジン内からバックエンドへリクエストを送信し、 オリジンベースのストレージ機構(例: localStorage、IndexedDB)からデータを窃取する、などが可能です。

何よりもまず、攻撃者が最初の足掛かりを得ることを避けるために、 予防的な対策を講じることが極めて重要です。これには、次の事項が含まれますが、 これらに限定されません。

さらなる推奨事項は、OWASP Cheat Sheet series [OWASPCheatSheet] にあります。

残念ながら、これらのセキュリティガイドラインを適用している場合でも、 攻撃者が悪意ある JavaScript の実行を引き起こす方法を見つけるリスクが残ることは、 歴史が示しています。悪意ある JS の存在を前提としてブラウザベースのアプリケーションのセキュリティを 分析する際には、悪意ある JavaScript コードは正当な アプリケーションコードと同じ権限を持つことを認識することが極めて重要です。 すべての JS アプリケーションは、程度の差こそあれこのリスクにさらされています。

アプリケーションは、その機能に必要な認可を付与する OAuth トークンを 取得する場合があります。これと組み合わさることで、侵害されたコードには、 その認可を悪意ある目的に使用する能力が実質的に与えられます。 攻撃者による認可の悪用リスクは避けられないものの、侵害された アプリケーションがその認可を悪用できる範囲を制限する方法があります。 たとえば、このアクセスは、アプリケーションがアクティブに使用されている間に限定したり、 取得できるトークンの種類を制限したり、トークンをブラウザにバインドしたりすることで 制限できる場合があります。

正当なアプリケーションコードが変数にアクセスしたり関数を呼び出したりできる場合、 悪意ある JS コードもまったく同じことができます。さらに、悪意ある JS コードは、 アプリケーションの通常の実行フローや、アプリケーションレベルの防御策に干渉できます。 これは、それらが通常アプリケーション内から制御されているためです。たとえば、 攻撃者はイベントリスナーを削除または上書きしたり、組み込み関数の振る舞いを変更したり (プロトタイプ汚染)、フレーム内のページの読み込みを停止したりできます。

悪意ある JavaScript がブラウザベースのアプリケーションに与える影響は、 広く研究され、よく理解されているトピックです。しかし、OAuth クライアントとして動作する ブラウザベースのアプリケーションに対する悪意ある JavaScript の具体的な影響は、 悪意ある JavaScript が OAuth フロー中の相互作用に影響を及ぼせるようになるため、 かなり独特です。本節では、悪意ある JS コードが OAuth クライアントの責務を持つ ブラウザベースのアプリケーションにもたらす脅威を検討します。 Section 5.1 では、攻撃者が悪意ある JavaScript コードを 実行する方法を見つけた後に使用できるいくつかのシナリオを説明します。 これらのシナリオは、単純なトークン流出をはるかに超える、攻撃者の真の能力を 明確に示します。Section 5.2 では、これらの攻撃シナリオが OAuth クライアントに与える影響を分析します。

本仕様の残りの部分では、さまざまなアーキテクチャパターンの セキュリティ特性を分析するために、これらの攻撃シナリオおよび影響を参照します。

5.1. 攻撃シナリオ

本節では、悪意ある JavaScript コードの実行を可能にする脆弱性を 攻撃者が見つけた後に実行できる、いくつかの攻撃シナリオを提示します。 攻撃シナリオには、単純なシナリオ(Section 5.1.1)と複雑なシナリオ(Section 5.1.3)が含まれます。 なお、この列挙は網羅的ではなく、OAuth 固有の機能に狭く範囲を限定しており、 特定の順序で提示されているものではありません。

5.1.1. 単一実行によるトークン窃取

このシナリオは、攻撃者がクライアントの現在のトークンを取得し、 流出させる単純なトークン流出攻撃を扱います。このシナリオは 次の手順で構成されます。

  • 悪意ある JS コードを実行する

  • アプリケーションが優先するストレージ 機構からトークンを取得する(Section 8 を参照)

  • 攻撃者が制御するサーバーへトークンを送信する

  • 窃取したトークンを保存または悪用する

侵害されたアクセストークンに関連するリスクを低減するための 推奨される防御戦略は、トークンのスコープと有効期間を短縮することです。 リフレッシュトークンについては、リフレッシュトークンローテーション ([RFC9700] の Section 4.14.2 で定義)の使用が、 検出および是正の仕組みを提供します。送信者制約付きトークン (Section 9.2)は、 窃取されたアクセストークンに対する追加の保護層を提供します。

なお、この攻撃シナリオは単純であり、悪意ある JavaScript の危険性を 説明するためによく使用されます。ブラウザベースのアプリケーションのセキュリティを 議論する際には、攻撃者の能力をこのシナリオで説明した攻撃に限定しないことが 重要です。

5.1.2. 継続的なトークン 窃取

この攻撃シナリオは、単一実行によるトークン窃取シナリオ (Section 5.1.1)のより高度な変形です。 悪意あるコードの実行時に即座にトークンを窃取するのではなく、 攻撃者はアプリケーションのトークンを継続的に窃取するために必要な ハンドラーを設定します。このシナリオは次の手順で構成されます。

  • 悪意ある JS コードを実行する

  • 継続的なトークン窃取の仕組みを設定する (例: 10 秒間隔)

    • アプリケーションが優先する ストレージ機構からトークンを取得する(Section 8 を参照)

    • 攻撃者が制御するサーバーへ トークンを送信する

    • トークンを保存する

  • 窃取したトークンの最新バージョンを悪用する 好機を待つ

このシナリオにおける決定的な違いは、攻撃者が常に アプリケーションによって使用される最新のトークンにアクセスできることです。 この攻撃シナリオのわずかな変形だけでも、短い有効期間や リフレッシュトークンローテーションなど、トークン窃取に対する典型的な防御策を 回避するには十分です。

アクセストークンについては、ユーザーのブラウザがオンラインである限り、 攻撃者は最新のアクセストークンを取得します。リフレッシュトークンローテーションは、 リフレッシュトークンの悪用を防ぐには十分ではありません。攻撃者は、 アプリケーションが最新のリフレッシュトークンを使用しないようにすることが容易にできます。 たとえば、攻撃者はトークンを窃取した後にアプリケーションのトークンを消去したり、 ユーザーがアプリケーションを閉じるまで待ったり、ユーザーのブラウザがオフラインになるまで 待ったりできます。アプリケーションが最新のリフレッシュトークンを使用しないため、 検出可能なリフレッシュトークンの再利用は発生せず、攻撃者は窃取した リフレッシュトークンを完全に制御できます。

5.1.3. 新しいトークンの 取得および抽出

この高度な攻撃シナリオでは、攻撃者はアプリケーションがすでに 取得しているトークンを完全に無視します。代わりに、攻撃者はアプリケーションの オリジンに関連付けられた悪意あるコードを実行できる能力を利用します。その能力により、 攻撃者は隠し iframe を注入し、サイレントな Authorization Code フローを開始できます。 このサイレントフローは、認可サーバーとのユーザーの既存セッションを再利用し、 新しい独立したアクセストークン(および任意でリフレッシュトークン)の発行につながります。 このシナリオは次の手順で構成されます。

  • 悪意ある JS コードを実行する

  • iframe から認可コードを取得するための ハンドラーを設定する(例: フレームの URL を監視する、または Web Messaging [WebMessaging] を介する)

  • 隠し iframe をページに挿入し、認可リクエストで 初期化する。iframe 内の認可リクエストはユーザーのセッション内で発生し、 セッションがまだ有効であれば、認可コードの発行につながります。 なお、この手順は、本シナリオの最後の段落で説明するように、 Authorization Server がサイレントなフレームベースのフローを サポートしていることに依存します。

  • 以前にインストールしたハンドラーを使用して、 iframe から認可コードを抽出する

  • 攻撃者が制御するサーバーへ認可コードを送信する

  • 認可コードを新しいトークンセットと交換する

  • 窃取したトークンを悪用する

このシナリオから得られる最も重要な点は、既存のトークンの窃取に 焦点を当てるのではなく、新しい OAuth フローを実行することです。本質的に、 アプリケーションが保存済みトークンを攻撃者から完全に分離できるトークン ストレージ機構を見つけたとしても、攻撃者は依然として新しいトークンセットを リクエストできます。なお、攻撃者はブラウザ内のアプリケーションを制御しているため、 攻撃者の Authorization Code フローは正当な Authorization Code フローと 区別できません。

この攻撃シナリオが可能なのは、public な ブラウザベースの OAuth クライアントのセキュリティが、リダイレクト URI と アプリケーションのオリジンに完全に依存しているためです。攻撃者がアプリケーションの オリジンで悪意ある JavaScript コードを実行すると、同一オリジンのフレームを 検査する能力を得ます。その結果、メインの実行コンテキストで動作する攻撃者のコードは、 同一オリジンのフレームに読み込まれたリダイレクト URI を検査して、認可コードを 抽出できます。

この攻撃シナリオに対抗できる、フロントエンドアプリケーション向けの 実用的なセキュリティ機構はありません。短いアクセストークンの有効期間や リフレッシュトークンローテーションは、攻撃者が新しい独立したトークンセットを持つため、 効果がありません。DPoP [RFC9449] のような高度なセキュリティ機構も同様に 効果がありません。攻撃者は、新しく取得したトークンに対して、自身の鍵ペアを使用して DPoP を設定し利用できるためです。すべての Authorization Code フローでユーザー操作を 要求すれば、新しいトークンの自動的なサイレント発行を実質的に止めることができますが、 これは、アプリケーションの初回ページロード時のブートストラップや、複数の関連アプリケーション間の シングルサインオンなど、広く確立されたパターンに大きな影響を与えるため、 実用的な対策ではありません。

5.1.4. ユーザーのブラウザを 介したリクエストのプロキシ

この攻撃シナリオでは、攻撃者がユーザーのブラウザ内で動作している OAuth クライアントアプリケーションの内部から、OAuth リソースサーバーへ直接リクエストを 送信します。このシナリオでは、ブラウザが自身の Cookie またはトークンをリクエストに 含めるため、攻撃者がトークンを取得するためにアプリケーションを悪用する必要はありません。 攻撃者がリソースサーバーへ送信するリクエストは、正当なアプリケーションが送信するリクエストと 区別できません。攻撃者が正当なアプリケーションと同じコンテキストでコードを実行しているためです。 このシナリオは次の手順で構成されます。

  • 悪意ある JS コードを実行する

  • リソースサーバーへリクエストを送信し、 レスポンスを処理する

リソースサーバーへのリクエストを認可するために、攻撃者は クライアントアプリケーションの振る舞いを単純に模倣します。たとえば、 クライアントアプリケーションが送信リクエストにアクセストークンをプログラム的に添付する場合、 攻撃者も同じことを行います。クライアントアプリケーションが適切なアクセストークンで リクエストを拡張する外部コンポーネントに依存している場合、その外部コンポーネントは 攻撃者のリクエストも同様に拡張します。

この攻撃パターンはよく知られており、 HttpOnly セッション Cookie を使用する従来型アプリケーションでも発生します。 このシナリオは、アプリケーションレベルのセキュリティ対策では停止または防止できないと 一般に受け入れられています。たとえば、DPoP [RFC9449] は、この攻撃シナリオを 明示的に範囲外と見なしています。

5.2. 攻撃の影響

攻撃シナリオの実行に成功すると、アクセストークンおよび リフレッシュトークンの窃取、またはユーザーのブラウザ内で動作するクライアントアプリケーションを 乗っ取る能力につながる可能性があります。これらの影響はいずれも、 ブラウザベースの OAuth クライアントに関連します。以下では、 重大度の高い順に説明します。

5.2.1. 窃取された リフレッシュトークンの悪用

攻撃者がブラウザベースの OAuth クライアントから有効な リフレッシュトークンを取得すると、認可サーバーで Refresh Token grant を実行することで そのリフレッシュトークンを悪用できます。Refresh Token grant のレスポンスには アクセストークンが含まれており、これによって攻撃者は保護されたリソースにアクセスする 能力を得ます(Section 5.2.2 を参照)。 本質的に、窃取されたリフレッシュトークンを悪用することで、 リソースサーバーに対して正当なクライアントアプリケーションを長期的に偽装できます。

攻撃は、認可サーバーがリフレッシュトークンの期限切れまたは ローテーションを理由に拒否した場合、またはリフレッシュトークンが失効された場合にのみ 停止します。典型的なブラウザベースの OAuth クライアントでは、リフレッシュトークンが 複数時間、あるいは数日間有効であり続けることも珍しくありません。

5.2.2. 窃取された アクセストークンの悪用

攻撃者が有効なアクセストークンを取得すると、 リソースサーバーへのリクエストにおいて、正当なクライアントアプリケーションを偽装する 能力を得ます。具体的には、アクセストークンを所持することで、攻撃者はその有効な アクセストークンを受け入れる任意のリソースサーバーへ、任意のリクエストを送信できます。 本質的に、窃取されたアクセストークンを悪用することで、リソースサーバーに対して 正当なクライアントアプリケーションを短期的に偽装できます。

攻撃は、アクセストークンの期限が切れた場合、 または認可サーバーでトークンが失効された場合に終了します。典型的な ブラウザベースの OAuth クライアントでは、アクセストークンの有効期間はかなり短く、 分単位から時間単位までの範囲になり得ます。

なお、アクセストークンの所持により、攻撃者はそれを無制限に 使用できます。攻撃者は、任意の HTTP メソッド、宛先 URL、ヘッダー値、 または本文を使用して、リソースサーバーへ任意のリクエストを送信できます。

アプリケーションは DPoP を使用して、アクセストークンがブラウザに 保持されたエクスポート不可能な鍵にバインドされるようにできます。その場合、 攻撃者が窃取したアクセストークンを悪用することは著しく難しくなります。 より具体的には、DPoP では、攻撃者は、証明をユーザーのブラウザ内で計算する オンライン攻撃を実行することによってのみ、窃取したアプリケーションのトークンを 悪用できます。この攻撃は、[RFC9449] の Section 11.4 で詳細に説明されています。 しかし、Section 5.1.3 で説明したように、 攻撃者が新しいアクセストークン(および任意でリフレッシュトークン)を取得すると、 攻撃者が制御する鍵ペアを使用してこれらのトークンに対して DPoP を設定できます。 その場合、攻撃者は再び、この新しく取得したアクセストークンを制限なく 悪用できます。

5.2.3. クライアントの乗っ取り

トークンの窃取が不可能または望ましくない場合、 攻撃者はユーザーのブラウザ内で動作している OAuth クライアントアプリケーションを 乗っ取ることも選択できます。これにより、攻撃者は、正当なクライアントアプリケーションが 実行できるあらゆる操作を実質的に実行できます。例としては、ページ上のデータを検査する、 ページを変更する、バックエンドシステムへリクエストを送信する、などがあります。 あるいは、攻撃者はアプリケーションへのアクセスを悪用して、セッション固定 ([SessionFixation]) のような攻撃を使用して、クライアントを攻撃者の代理として動作させるなど、 追加の攻撃を開始することもできます。

なお、クライアントの乗っ取りは、窃取したユーザートークンを直接 悪用することほど強力ではありません。クライアント乗っ取りのシナリオでは、 攻撃者はトークンを直接制御できず、クライアントアプリケーション上で適用されている セキュリティポリシーによって制限されます。たとえば、 admin.example.org 上で動作するリソースサーバーは、 web.example.org 上で動作するクライアントからのリクエストを拒否する CORS ポリシーで構成できます。クライアントが使用するアクセストークンが リソースサーバーによって受け入れられる場合であっても、リソースサーバーの厳格な CORS 構成は、そのようなリクエストを許可しません。このような厳格な CORS ポリシーを持たないリソースサーバーは、侵害されたクライアントアプリケーションからの 敵対的なリクエストの対象となり得ます。

6. 애플리케이션 아키텍처 패턴

보호된 리소스에 접근하기 위해 OAuth에 의존하는 브라우저 기반 애플리케이션을 구축할 때 사용할 수 있는 세 가지 주요 아키텍처 패턴이 있다.

이러한 각 아키텍처 패턴은 보안과 단순성 사이에서 서로 다른 절충점을 제공한다. 이 절의 패턴은 보안성이 높은 순서에서 낮은 순서로 제시된다.

6.1. 프런트엔드용 백엔드 (BFF)

이 절은 모든 OAuth 책임과 API 상호 작용을 처리하기 위해 백엔드 구성 요소에 의존하는 브라우저 기반 애플리케이션의 아키텍처를 설명한다. BFF에는 세 가지 핵심 책임이 있다:

  1. BFF는 기밀 OAuth 클라이언트([RFC6749]의 2.1절에 정의됨)로서 권한 부여 서버와 상호 작용한다

  2. BFF는 쿠키 기반 세션의 컨텍스트에서 OAuth 접근 및 갱신 토큰을 관리하여, 브라우저 기반 애플리케이션에 토큰이 직접 노출되는 것을 피한다

  3. BFF는 모든 요청을 리소스 서버로 전달하며, 리소스 서버에 전달하기 전에 올바른 접근 토큰을 추가한다

이 아키텍처에서 BFF는 서버 측 구성 요소로 실행되지만, 프런트엔드 애플리케이션의 구성 요소이다. API 게이트웨이나 리버스 프록시와 같은 다른 아키텍처 개념과 혼동하지 않으려면, BFF가 프런트엔드 애플리케이션을 위한 OAuth 클라이언트가 된다는 점을 염두에 두는 것이 중요하다.

공격자가 브라우저 기반 애플리케이션 내에서 악성 코드를 실행할 수 있다면, 이 애플리케이션 아키텍처는 앞서 논의한 대부분의 공격 시나리오를 견딜 수 있다. 토큰은 BFF에서만 사용할 수 있으므로, 브라우저에서 추출할 수 있는 토큰이 없다 (단일 실행 토큰 탈취(5.1.1절) 및 지속적 토큰 탈취(5.1.2절)). BFF는 기밀 클라이언트이므로, 공격자가 브라우저 내에서 새 흐름을 실행하는 것을 방지한다 (새 토큰의 획득 및 추출(5.1.3절)). 악성 브라우저 기반 코드는 여전히 애플리케이션의 출처 내에서 실행되므로, 공격자는 사용자의 브라우저 내부에서 BFF로 요청을 보낼 수 있다(사용자의 브라우저를 통한 요청 프록시(5.1.4절)). HttpOnly 쿠키를 사용하면 공격자가 세션 상태에 직접 접근하지 못하게 되어, 클라이언트 하이재킹에서 세션 하이재킹으로 확대되는 것을 방지한다는 점에 유의한다.

6.1.1. 애플리케이션 아키텍처

Authorization Token Resource Endpoint Endpoint Server (F) (K) Backend for Frontend (BFF) (D) (B,I) (C) (E) (G) (J) (L) (A,H) Static Web Host Browser
그림 1: OAuth 2.0 BFF 패턴

이 아키텍처에서는 브라우저 코드(일반적으로 JavaScript)가 먼저 정적 웹 호스트에서 브라우저로 로드되고(A), 그다음 애플리케이션이 브라우저에서 실행된다. 애플리케이션은 "check session" API 엔드포인트를 호출하여 활성 세션이 있는지 BFF에 확인한다(B). 활성 세션이 발견되면, 애플리케이션은 인증된 상태를 재개하고 J 단계로 건너뛴다.

활성 세션이 발견되지 않으면, 브라우저 기반 애플리케이션은 PKCE 확장(6.1.3.1절에 설명됨)을 사용하는 Authorization Code 흐름을 시작하기 위해 BFF로의 내비게이션을 트리거한다(C). 이에 대해 BFF는 브라우저를 권한 부여 엔드포인트로 리디렉션하여 응답한다(D). 사용자가 다시 리디렉션되면, 브라우저는 권한 부여 코드를 BFF에 전달하고(E), BFF는 자신의 클라이언트 자격 증명과 PKCE 코드 검증자를 사용하여 토큰 엔드포인트에서 이를 토큰으로 교환할 수 있다(F).

BFF는 획득한 토큰을 사용자의 세션과 연결하고(6.1.2.3절 참조), 이 세션을 추적하기 위해 응답에 쿠키를 설정한다(G). 이 시점에서 리디렉션 기반 Authorization Code 흐름이 완료되었으므로, BFF는 제어를 프런트엔드 애플리케이션에 다시 넘길 수 있다. BFF는 응답에 리디렉션을 포함하여 이를 수행하며(G), 브라우저가 서버에서 프런트엔드를 가져오도록 트리거한다(H). (H) 단계는 (A) 단계와 동일하다는 점에 유의한다. 이는 요청된 리소스가 브라우저의 캐시에서 로드될 가능성이 있음을 의미한다. 프런트엔드가 로드되면, 기존 세션이 있는지 BFF에 확인하여(I), 애플리케이션이 인증된 상태를 재개할 수 있게 한다.

브라우저의 애플리케이션이 리소스 서버로 요청을 보내려 할 때, BFF의 해당 엔드포인트로 요청을 보낸다(J). 이 요청에는 G 단계에서 설정된 쿠키가 포함되어, BFF가 이 사용자 세션에 적절한 토큰을 얻을 수 있게 한다. BFF는 요청에서 쿠키를 제거하고, 사용자의 접근 토큰을 요청에 첨부한 뒤, 실제 리소스 서버로 전달한다(K). 그런 다음 BFF는 응답을 브라우저 기반 애플리케이션으로 다시 전달한다(L).

6.1.2. 구현 세부 사항

6.1.2.1. 세션 및 OAuth 엔드포인트

BFF는 브라우저 기반 애플리케이션과 BFF 사이의 상호 작용을 구현하는 데 핵심적인 엔드포인트 집합을 제공한다. 이 절은 이러한 엔드포인트의 목적과 사용 사례를 명확히 하기 위해 조금 더 자세히 논의한다.

"check session" 엔드포인트(위 그림의 B 및 I 단계)는 브라우저 기반 애플리케이션이 호출하는 API 엔드포인트이다. 요청에는 사용 가능한 경우 세션 정보가 포함되어, BFF가 활성 세션이 있는지 확인할 수 있게 한다. 응답은 세션이 활성 상태인지 여부를 브라우저 기반 애플리케이션에 표시해야 한다. 또한 BFF는 인증된 사용자에 대한 신원 정보와 같은 다른 정보를 포함할 수 있다.

Authorization Code 흐름을 시작하는 엔드포인트 (C 단계)는 브라우저가 내비게이션을 통해 접촉한다. 애플리케이션이 세션을 확인한 뒤(B 단계) 인증되지 않은 상태를 감지하면, 브라우저를 이 엔드포인트로 이동시킬 수 있다. 이렇게 하면 BFF가 리디렉션으로 응답하여 브라우저를 권한 부여 서버로 이동시킬 수 있다. 이 흐름을 시작하는 엔드포인트는 일반적으로 웹 서버에서 실행되는 기밀 클라이언트용 OAuth 2.0을 지원하는 라이브러리에서 "login" 엔드포인트로 포함된다. BFF가 활성 세션이 없음을 감지했을 때 B 단계에서 Authorization Code 흐름을 시작할 수도 있다는 점에 유의한다. 이 경우 BFF는 응답에 권한 부여 URI를 반환하고, 애플리케이션이 이 URI로 내비게이션 이벤트를 트리거하기를 기대한다. 그러나 이 시나리오는 사용자 지정 구현이 필요하며 표준 OAuth 라이브러리를 사용하기 더 어렵게 만든다.

권한 부여 코드를 수신하는 엔드포인트(E 단계)는 브라우저 내부의 내비게이션 이벤트에 의해 호출된다. 이 시점에서 애플리케이션은 로드되어 있지 않으며 리디렉션을 처리할 위치에 있지 않다. 흐름 시작과 유사하게, 리디렉션을 처리하는 엔드포인트는 표준 OAuth 라이브러리에서 제공된다. BFF는 애플리케이션을 로드하도록 브라우저를 트리거하는 리디렉션으로 이 요청에 응답할 수 있다.

마지막으로, BFF는 위 그림에 표시되지 않은 "logout" 엔드포인트도 애플리케이션에 제공할 수 있다. logout 엔드포인트의 정확한 동작은 애플리케이션 요구 사항에 따라 달라진다. 표준 OAuth 라이브러리도 일반적으로 "logout" 엔드포인트의 구현을 제공한다는 점에 유의한다.

6.1.2.2. 갱신 토큰

[RFC9700]의 4.14절에 설명된 것처럼 갱신 토큰을 사용할 때, BFF는 갱신 토큰(F 단계)을 획득하고 이를 사용자의 세션과 연결한다.

BFF가 사용자의 접근 토큰이 만료되었고 BFF에 갱신 토큰이 있음을 감지하면, 갱신 토큰을 사용하여 새 접근 토큰을 얻을 수 있다. BFF OAuth 클라이언트는 기밀 클라이언트이므로, 갱신 토큰 요청에서 클라이언트 인증을 사용한다. 일반적으로 BFF는 프런트엔드의 API 호출을 처리할 때 이러한 단계를 인라인으로 수행한다. 이 경우 그림에 명시적으로 표시되지 않은 이 단계들은 J 단계와 K 단계 사이에서 발생한다. 모든 토큰 정보를 서버 측에서 사용할 수 있도록 유지하는 BFF는 API 요청의 성능을 높이기 위해 토큰 만료 이벤트를 관찰할 때 새 접근 토큰을 요청할 수도 있다.

갱신 토큰이 만료되면, 완전히 새로운 Authorization Code 흐름을 실행하지 않고는 유효한 접근 토큰을 얻을 방법이 없다. 따라서 BFF가 관리하는 쿠키 기반 세션의 수명을 갱신 토큰의 최대 수명과 같게 구성하는 것이 타당하다. 또한 BFF가 활성 세션의 갱신 토큰이 더 이상 유효하지 않음을 알게 되면, 세션도 무효화하는 것이 타당하다.

BFF는 사용자의 토큰에 접근하는 데 사용되는 사용자의 세션을 추적하기 위해 브라우저 쿠키([I-D.ietf-httpbis-rfc6265bis])에 의존한다. 서버 측 및 클라이언트 측 쿠키 기반 세션에는 몇 가지 단점이 있다.

서버 측 세션은 세션 식별자만 노출하고 모든 데이터를 서버에 보관한다. 이렇게 하면 활성 세션에 대한 높은 수준의 제어와 원하는 시점에 어떤 세션이든 폐기할 수 있는 가능성이 보장된다. 이 접근 방식의 단점은 확장성에 미치는 영향이며, "sticky sessions" 또는 "session replication"과 같은 해결책이 필요하다. 이러한 단점을 고려할 때, BFF와 함께 서버 측 세션을 사용하는 것은 소규모 시나리오에서만 권장된다.

클라이언트 측 세션은 모든 데이터를 서명되고 선택적으로 암호화된 객체로 브라우저에 푸시한다. 이 패턴은 서버가 세션 데이터를 추적할 필요를 없애지만, 활성 세션에 대한 제어를 심각하게 제한하고 세션 폐기를 처리하기 어렵게 만든다. 그러나 클라이언트 측 세션이 BFF의 컨텍스트에서 사용될 때 이러한 속성은 크게 달라진다. 쿠키 기반 세션은 사용자의 토큰을 얻는 데만 사용되므로, 모든 제어 및 폐기 속성은 접근 토큰과 갱신 토큰의 사용에서 비롯된다. 쿠키 기반 세션을 명시적으로 무효화할 필요 없이 사용자의 접근 토큰 및/또는 갱신 토큰을 폐기하는 것만으로 보호된 리소스에 대한 지속적인 접근을 방지하기에 충분하다.

세션 쿠키를 보호하기 위한 모범 사례는 6.1.3.2절에서 논의된다.

6.1.2.4. OAuth와 OpenID Connect 결합

이 애플리케이션 아키텍처에서 사용하는 OAuth 흐름은 권한 부여 요청(C)에 필요한 OpenID Connect 범위를 포함함으로써 OpenID Connect와 결합될 수 있다([OpenID]의 3.1.2.1절에 정의된 최소한 openid 범위). 이 경우 BFF는 F 단계에서 ID Token을 받는다. BFF는 ID Token의 정보를 사용자의 세션과 연결하고 이를 B 단계 또는 I 단계에서 애플리케이션에 제공할 수 있다.

필요할 때 BFF는 사용자의 세션과 연결된 접근 토큰을 사용하여 UserInfo 엔드포인트로 요청을 보낼 수 있다.

6.1.2.5. 실용적 배포 전략

정적 JavaScript 코드를 제공하는 것은 OAuth 토큰 처리 및 요청 전달과 별도의 책임이다. 위에 제시된 그림에서 BFF와 정적 웹 호스트는 두 개의 별도 엔티티로 표시된다. 실제 배포에서는 이러한 구성 요소가 단일 서비스(즉, BFF가 정적 JS 코드를 제공), 두 개의 별도 서비스(즉, CDN과 BFF), 또는 단일 서비스 내 두 구성 요소 (즉, 클라우드 플랫폼의 정적 호스팅과 서버리스 함수)로 배포될 수 있다.

특정 시나리오에 맞추기 위해 이 아키텍처를 더 사용자 지정할 수 있다는 점에 유의한다. 예를 들어, 내부 및 외부 리소스 서버 모두에 의존하는 애플리케이션은 내부 리소스 서버를 BFF와 함께 호스팅하도록 선택할 수 있다. 이 시나리오에서 내부 리소스 서버로의 요청은 네트워크를 통해 요청을 전달할 필요 없이 BFF에서 직접 처리된다. 리소스 서버의 관점에서 권한 부여는 변하지 않으며, 사용자의 세션은 내부적으로 접근 토큰과 그 클레임으로 변환된다.

6.1.3. 보안 고려 사항

6.1.3.1. Authorization Code 권한 부여

BFF를 사용하는 주요 이점은 BFF가 기밀 클라이언트로 동작할 수 있는 능력이다. 따라서 BFF는 권한 부여 서버와 자격 증명을 설정하여 기밀 클라이언트로 동작해야 한다(MUST). 또한 BFF는 접근 토큰 요청을 시작하기 위해 [RFC9700]의 2.1.1절에 설명된 OAuth 2.0 Authorization Code 권한 부여를 사용해야 한다(MUST).

6.1.3.3. 교차 사이트 요청 위조 보호

브라우저 기반 애플리케이션과 BFF 사이의 상호 작용은 인증 및 권한 부여를 위해 쿠키에 의존한다. 다른 쿠키 기반 상호 작용과 유사하게, BFF는 Cross-Site Request Forgery (CSRF) 공격을 고려해야 한다. 성공적인 CSRF 공격은 공격자의 BFF 요청이 보호된 리소스로 나가는 호출을 트리거하도록 허용할 수 있다.

BFF는 적절한 CSRF 방어를 구현해야 한다(MUST). 정확한 메커니즘 또는 메커니즘의 조합은 아래에서 논의한 것처럼 BFF가 배포된 정확한 도메인에 따라 달라진다.

6.1.3.3.2. Cross-Origin Resource Sharing

BFF는 CORS를 CSRF 방어 메커니즘으로 의존할 수 있다. CORS는 서버가 적절한 CORS 헤더를 설정하여 그러한 요청을 명시적으로 승인하지 않는 한, cross-origin 요청을 제한하는 브라우저 구현 보안 메커니즘이다.

브라우저는 일반적으로 스크립트에서 시작된 cross-origin HTTP 요청을 제한한다. CORS는 대상 서버가 요청을 승인하면 이 제한을 제거할 수 있으며, 이는 초기 "preflight" 요청을 통해 확인된다. preflight 응답이 요청을 명시적으로 승인하지 않는 한, 브라우저는 전체 요청 전송을 거부한다.

이 속성 때문에 BFF는 CORS를 CSRF 방어로 의존할 수 있다. 공격자가 사용자의 브라우저에서 BFF로 cross-origin 요청을 시작하려 할 때, BFF는 preflight 응답에서 요청을 승인하지 않아 브라우저가 실제 요청을 차단하게 한다. 공격자는 항상 자신의 컴퓨터에서 요청을 시작할 수 있지만, 그러면 요청에 사용자의 쿠키가 포함되지 않으므로 공격은 실패한다는 점에 유의한다.

CORS를 CSRF 방어로 의존할 때는 특정 요청이 preflight 없이 가능하다는 점을 인식하는 것이 중요하다. "CORS-safelisted Requests"라고 불리는 이러한 요청의 경우, 브라우저는 단순히 요청을 보내고, 서버가 적절한 CORS 헤더를 보내지 않았다면 응답에 대한 접근을 방지한다. 이 동작은 GET 요청이나 form 기반 POST 요청처럼 JavaScript 이외의 수단으로 트리거될 수 있는 요청에 적용된다.

이 동작의 결과로, 리소스 서버의 특정 엔드포인트는 CORS가 방어로 활성화되어 있어도 CSRF에 취약해질 수 있다. 예를 들어 리소스 서버가 body 없는 POST 요청을 받는 엔드포인트를 노출하는 API라면, preflight 요청이 없고 CSRF 방어도 없다.

CORS 정책에 대한 이러한 우회를 피하기 위해, BFF는 브라우저 기반 애플리케이션이 사용자 지정 요청 헤더를 포함하도록 요구하는 것이 좋다(SHOULD). 사용자 지정 요청 헤더가 있는 cross-origin 요청은 항상 preflight를 필요로 하므로, CORS가 효과적인 CSRF 방어가 된다. 이 메커니즘을 사용할 때 BFF는 모든 들어오는 요청이 이 정적 헤더를 포함하는지 확인해야 한다(MUST). 이 헤더의 정확한 이름은 애플리케이션과 BFF의 재량에 따른다. 예시 구성은 My-Static-Header: 1과 같은 정적 값을 가진 요청 헤더일 수 있다.

브라우저 기반 애플리케이션을 BFF와 동일한 출처에 배포하는 것도 가능하다. 이렇게 하면 프런트엔드와 BFF 사이의 합법적인 상호 작용에 preflight가 필요하지 않으므로 추가 오버헤드가 없다.

6.1.3.3.3. 위조 방지/이중 제출 쿠키 사용

일부 기술 스택과 프레임워크에는 위조 방지 쿠키를 사용하는 내장 CRSF 보호가 있다. 이 메커니즘은 쿠키에 저장되는 세션별 비밀에 의존하며, 이 비밀은 쿠키와 연결된 도메인에서 실행되는 합법적인 프런트엔드만 읽을 수 있다. 프런트엔드는 쿠키를 읽고 그 값을 요청에 삽입해야 하며, 일반적으로 사용자 지정 요청 헤더를 추가하여 수행한다. 백엔드는 쿠키의 값을 프런트엔드가 제공한 값과 비교하여 합법적인 요청을 식별한다. 모든 상태 변경 요청에 대해 올바르게 구현되면, 이 메커니즘은 CSRF를 효과적으로 완화한다.

이 메커니즘이 CORS 접근 방식보다 반드시 권장되는 것은 아니라는 점에 유의한다. 그러나 프레임워크가 이 메커니즘에 대한 내장 지원을 제공한다면, CSRF 방어를 위한 낮은 노력의 대안으로 사용될 수 있다.

6.1.3.4. BFF 아키텍처의 개인정보 보호 고려 사항

BFF 패턴은 브라우저 기반 애플리케이션이 리소스 서버로 보내는 모든 요청을 백엔드 BFF 구성 요소를 통해 전달하도록 요구한다. 그 결과 BFF 구성 요소는 애플리케이션과 리소스 서버 사이의 모든 요청과 응답을 관찰할 수 있으며, 이는 상당한 개인정보 보호 영향을 가질 수 있다.

브라우저 기반 애플리케이션과 BFF가 같은 당사자에 의해 구축되고 배포되는 경우, 개인정보 보호 영향은 대체로 미미할 가능성이 높다. 그러나 이 패턴이 제3자가 제공하거나 호스팅하는 BFF 구성 요소를 사용하여 구현되는 경우, 이러한 개인정보 보호 영향을 고려해야 한다.

6.1.3.5. 운영 고려 사항

BFF가 프런트엔드를 대신하여 모든 요청을 리소스 서버로 전달하므로, 리소스 서버가 이 구성 요소를 인지하고 속도 제한 및 기타 남용 방지 조치에 적절한 정책을 사용하도록 주의해야 한다. 예를 들어 BFF가 단일 인스턴스 서비스로 배포되고 리소스 서버가 IP 주소 기반으로 요청을 속도 제한하는 경우, 많은 사용자의 브라우저가 BFF의 단일 IP 주소에서 오는 것처럼 보이므로 요청을 차단하기 시작할 수 있다.

6.1.3.6. 프록시 제한

BFF는 프런트엔드의 요청을 수락하고 리소스 서버로 전달함으로써 프록시 서비스로 동작한다. 들어오는 요청은 쿠키를 포함하며, BFF는 이를 나가는 요청의 접근 토큰으로 변환한다. (이는 HTTP 프록시라기보다 애플리케이션 계층 리버스 프록시에 더 가깝다는 점에 유의한다.) CSRF 공격 외에도, 공격자는 BFF를 조작하여 의도하지 않은 호스트로 요청을 전달하게 하려 시도할 수 있다. 공격자가 이를 성공적으로 악용하면, BFF를 임의의 서버로 리디렉션하여 사용자의 접근 토큰을 잠재적으로 노출할 수 있다.

이 위험을 완화하기 위해, BFF는 요청을 전달하기 전에 목적지 호스트를 검증하여 엄격한 발신 요청 제어를 강제해야 한다(MUST). 이를 위해 승인된 리소스 서버의 명시적 allowlist를 유지해야 하며, 요청이 사전 정의된 백엔드로만 프록시되도록 보장해야 한다(예: /bff/orders/createhttps://order-api.example.com/create에만 매핑됨). 경로 기반 동적 라우팅(예: /bff/orders/{id})이 필요한 경우, BFF는 승인된 목적지만 접근 가능하도록 엄격한 검증을 적용해야 한다(MUST). 또한 엔드포인트별로 허용되는 HTTP 메서드를 제한하면 공격 벡터를 추가로 줄일 수 있다.

동적으로 구성 가능한 프록시를 구현할 때, BFF는 명시적으로 허용된 호스트와 경로에 대한 요청만 허용하도록 보장해야 한다(MUST). 이러한 제한을 강제하지 못하면 무단 접근과 접근 토큰 유출로 이어질 수 있다.

6.1.3.7. 고급 보안

BFF 패턴에서는 모든 OAuth 책임이 기밀 클라이언트로 동작하는 서버 측 구성 요소인 BFF로 이동되었다. 서버 측 애플리케이션은 브라우저 기반 애플리케이션보다 더 통제된 환경에서 실행되므로, 고급 OAuth 보안 관행을 채택하기가 더 쉬워진다. 예에는 키 기반 클라이언트 인증 및 송신자 제한 토큰이 포함된다.

6.1.4. 위협 분석

이 절은 5절의 공격 시나리오와 결과를 다시 살펴보고, 잠재적인 추가 방어책을 논의한다.

6.1.4.1. 공격 시나리오 및 결과

공격자가 애플리케이션의 실행 컨텍스트에서 악성 코드(예: JavaScript 또는 WASM)를 실행할 수 있다면, 다음 공격 시나리오가 관련된다:

  • 사용자의 브라우저를 통한 요청 프록시(5.1.4절)

이 공격 시나리오는 다음 결과로 이어진다는 점에 유의한다:

클라이언트 하이재킹은 브라우저 기반 애플리케이션의 본질에 내재한 공격 시나리오라는 점에 유의한다. 따라서 애초에 악성 코드 실행을 막는 것 외에는 이러한 공격을 방지할 수 있는 것이 없다. 이를 달성하는 데 도움이 되는 기법으로는 보안 코딩 지침 준수, 코드 분석, Content Security Policy([W3C.CSP3])와 같은 심층 방어 메커니즘 배포가 있다.

이 아키텍처에서 BFF는 다양한 보안 관련 책임과 프록시 기반 동작을 처리하는 핵심 구성 요소이다. 프록시 기반 애플리케이션의 안전한 구현을 논의하는 것은 이 문서의 범위를 벗어나지만, BFF의 보안 취약점이 애플리케이션에 중대한 영향을 미칠 수 있다는 점을 주목하는 것이 중요하다.

마지막으로, BFF는 브라우저 기반 애플리케이션과 리소스 서버 사이의 모든 트래픽을 관찰할 수 있는 독특한 위치에 있다. 고보안 애플리케이션이 이상 탐지나 속도 제한을 구현하려 한다면, 이러한 BFF가 이를 수행하기에 이상적인 위치가 될 것이다. 이러한 제한은 클라이언트 하이재킹의 결과를 완화하는 데 추가로 도움이 될 수 있다.

6.1.4.2. 완화된 공격 시나리오

아래에 나열된 다른 공격 시나리오들은 BFF 애플리케이션 아키텍처에 의해 효과적으로 완화된다:

BFF는 브라우저 기반 애플리케이션에 어떤 토큰도 노출하지 않음으로써 앞의 두 공격 시나리오에 대응한다. 공격자가 애플리케이션을 완전히 제어하더라도, 훔칠 토큰이 전혀 없다.

공격자가 조용한 흐름을 실행하여 새 접근 토큰(그리고 선택적으로 갱신 토큰)을 얻는 세 번째 시나리오는 BFF를 기밀 클라이언트로 만들면 완화된다. 공격자가 권한 부여 코드를 얻는 데 성공하더라도, 클라이언트 자격 증명이 없기 때문에 이 코드를 교환할 수 없다. 또한 PKCE를 사용하면 권한 부여 코드에 대한 다른 공격을 방지한다.

갱신 토큰과 접근 토큰은 BFF가 관리하며 브라우저에 노출되지 않으므로, 잠재적 공격의 다음 두 결과는 관련이 없어지게 된다:

  • 탈취된 갱신 토큰 악용(5.2.1절 참조)

  • 탈취된 접근 토큰 악용(5.2.2절 참조)

6.1.4.3. 요약

BFF의 아키텍처는 브라우저 전용 애플리케이션보다 훨씬 더 복잡하다. 서버 측 BFF 구성 요소를 배포하고 운영해야 한다. 또한 이 패턴은 애플리케이션과 리소스 서버 사이의 모든 상호 작용이 BFF를 통해 프록시되도록 요구한다. 배포 패턴에 따라 이 프록시 동작은 서버 측 구성 요소에 상당한 부담을 추가할 수 있다. BFF가 리소스 서버로 동작하는 경우 추가 참고 사항은 6.2.2.6절을 참조한다.

그러나 BFF 아키텍처 패턴의 특성상, 강력한 보안 보장을 제공한다. BFF를 사용하면 OAuth를 사용함으로써 애플리케이션의 공격 표면이 증가하지 않도록 보장할 수도 있다. 유일하게 가능한 공격 패턴은 사용자의 브라우저에서 클라이언트 애플리케이션을 하이재킹하는 것이며, 이는 웹 애플리케이션에 내재한 문제이다.

이 아키텍처는 비즈니스 애플리케이션, 민감한 애플리케이션 및 개인 데이터를 처리하는 애플리케이션에 강력히 권장된다.

6.2. 토큰 중개 백엔드

이 절은 기밀 클라이언트([RFC6749]의 2.1절에 정의됨)로서 토큰을 얻기 위한 OAuth 책임을 처리하기 위해 백엔드 구성 요소에 의존하는 브라우저 기반 애플리케이션의 아키텍처를 설명한다. 그런 다음 백엔드 구성 요소는 애플리케이션이 리소스 서버와 직접 상호 작용할 수 있도록 접근 토큰을 제공한다.

토큰 중개 백엔드 패턴은 BFF 패턴 (6.1절 참조)보다 가볍다. 이는 애플리케이션과 리소스 서버 사이의 모든 요청과 응답을 프록시할 필요가 없기 때문이다. 보안 관점에서 토큰 중개 백엔드는 BFF보다 덜 안전하지만, 브라우저에서 직접 실행되는 OAuth 클라이언트 애플리케이션에 비해 여전히 상당한 이점을 제공한다.

공격자가 애플리케이션 내에서 악성 코드를 실행할 수 있다면, 이 애플리케이션 아키텍처는 공격자가 갱신 토큰을 악용하는 것 (단일 실행 토큰 탈취(5.1.1절) 및 지속적 토큰 탈취(5.1.2절))이나 새 토큰 집합을 얻는 것(새 토큰의 획득 및 추출(5.1.3절))을 방지할 수 있다. 그러나 접근 토큰이 애플리케이션에 직접 노출되므로, 공격자는 클라이언트 측 저장소에서 토큰을 훔치거나(단일 실행 토큰 탈취(5.1.1절) 및 지속적 토큰 탈취(5.1.2절)), 토큰 중개 백엔드에서 새 토큰을 요청할 수 있다(사용자의 브라우저를 통한 요청 프록시(5.1.4절)). HttpOnly 쿠키를 사용하면 공격자가 세션 상태에 직접 접근하지 못하게 하여, 접근 토큰 탈취에서 세션 하이재킹으로 확대되는 것을 방지한다는 점에 유의한다.

6.2.1. 애플리케이션 아키텍처

Authorization Token Resource Endpoint Endpoint Server (F) Token-Mediating Backend (J) (D) (B,I) (C) (E) (G) (A,H) Static Web Host Browser
그림 2: OAuth 2.0 토큰 중개 백엔드 패턴

이 아키텍처에서는 브라우저 기반 코드(예: JavaScript 또는 WASM)가 먼저 정적 웹 호스트에서 브라우저로 로드되고(A), 그다음 애플리케이션이 브라우저에서 실행된다. 애플리케이션은 활성 세션이 있는지 토큰 중개 백엔드에 확인한다(B). 활성 세션이 발견되면, 애플리케이션은 해당 접근 토큰을 받고, 인증된 상태를 재개하며, J 단계로 건너뛴다.

활성 세션이 발견되지 않으면, 애플리케이션은 PKCE 확장(6.2.3.1절에 설명됨)을 사용하는 Authorization Code 흐름을 시작하기 위해 토큰 중개 백엔드로의 내비게이션을 트리거한다(C). 이에 대해 토큰 중개 백엔드는 브라우저를 권한 부여 엔드포인트로 리디렉션하여 응답한다(D). 사용자가 다시 리디렉션되면, 브라우저는 권한 부여 코드를 토큰 중개 백엔드에 전달하고(E), 토큰 중개 백엔드는 자신의 클라이언트 자격 증명과 PKCE 코드 검증자를 사용하여 토큰 엔드포인트에서 이를 토큰으로 교환할 수 있다(F).

토큰 중개 백엔드는 획득한 토큰을 사용자의 세션과 연결하고(6.2.2.4절 참조), 이 세션을 추적하기 위해 응답에 쿠키를 설정한다(G). 브라우저에 대한 이 응답은 애플리케이션의 다시 로드도 트리거한다(H). 이 애플리케이션이 다시 로드되면, 기존 세션이 있는지 토큰 중개 백엔드에 확인하여(I), 애플리케이션이 인증된 상태를 재개하고 토큰 중개 백엔드에서 접근 토큰을 얻을 수 있게 한다.

브라우저의 애플리케이션은 I 단계에서 얻은 접근 토큰을 사용하여 리소스 서버로 직접 요청을 보낼 수 있다(J).

6.2.2. 구현 세부 사항

6.2.2.1. 세션 및 OAuth 엔드포인트

토큰 중개 백엔드의 엔드포인트 구현 대부분은 BFF에 대해 설명한 것과 유사하다.

  • "check session" 엔드포인트(위 그림의 B 및 I 단계)는 브라우저 기반 애플리케이션이 호출하는 API 엔드포인트이다. 요청에는 사용 가능한 경우 세션 정보가 포함되어, 백엔드가 활성 세션이 있는지 확인할 수 있게 한다. 응답은 세션이 활성 상태인지 여부를 브라우저 기반 애플리케이션에 표시해야 한다. 활성 세션이 발견되면, 백엔드는 응답에 접근 토큰을 포함한다. 또한 백엔드는 인증된 사용자에 대한 신원 정보와 같은 다른 정보를 포함할 수 있다.

  • Authorization Code 흐름을 시작하는 엔드포인트 (C 단계)는 BFF 아키텍처에 대해 설명한 엔드포인트와 동일하다. 자세한 내용은 6.1.2.1절을 참조한다.

  • 권한 부여 코드를 수신하는 엔드포인트 (E 단계)는 BFF 아키텍처에 대해 설명한 엔드포인트와 동일하다. 자세한 내용은 6.1.2.1절을 참조한다.

  • logout을 지원하는 엔드포인트는 BFF 아키텍처에 대해 설명한 엔드포인트와 동일하다. 자세한 내용은 6.1.2.1절을 참조한다.

6.2.2.2. 갱신 토큰

[RFC9700]의 4.14절에 설명된 것처럼 갱신 토큰을 사용할 때, 토큰 중개 백엔드는 F 단계에서 갱신 토큰을 획득하고 이를 사용자의 세션과 연결한다.

리소스 서버가 접근 토큰을 거부하면, 애플리케이션은 토큰 중개 백엔드에 연락하여 새 접근 토큰을 요청할 수 있다. 토큰 중개 백엔드는 이 요청과 연결된 쿠키에 의존하여 사용자의 갱신 토큰을 조회하고, 갱신 토큰을 사용하여 토큰 요청을 한다. 이러한 단계는 그림에 표시되어 있지 않다. 이 Refresh Token 요청은 기밀 클라이언트인 백엔드에서 이루어지므로 클라이언트 인증이 필요하다는 점에 유의한다.

갱신 토큰이 만료되면, 완전히 새로운 Authorization Code 권한 부여를 시작하지 않고는 유효한 접근 토큰을 얻을 방법이 없다. 따라서 그러한 정보를 사전에 알고 있다면 쿠키 기반 세션의 수명을 갱신 토큰의 최대 수명과 같게 구성하는 것이 타당하다. 또한 토큰 중개 백엔드가 활성 세션의 갱신 토큰이 더 이상 유효하지 않음을 알게 되면, 세션을 무효화하는 것이 타당하다.

6.2.2.3. 접근 토큰 범위

접근하는 리소스 서버와 권한 부여 서버의 범위 구성에 따라, 애플리케이션은 서로 다른 범위 구성을 가진 접근 토큰을 요청하기를 원할 수 있다. 이 동작은 애플리케이션이 최소 범위의 접근 토큰을 사용하는 모범 사례를 따를 수 있게 한다.

애플리케이션은 활성 세션을 확인할 때(단계 A/I) 원하는 범위를 토큰 중개 백엔드에 알릴 수 있다. 이전에 획득한 접근 토큰이 원하는 범위 기준에 들어맞는지 결정하는 것은 토큰 중개 백엔드의 책임이다.

이 접근 토큰 캐싱 메커니즘이 토큰 중개 백엔드에서 무분별하게 적용되면 범위 상승 위험을 유발할 수 있다는 점에 유의해야 한다. 캐시된 접근 토큰이 프런트엔드가 요청한 범위의 상위 집합을 포함하는 경우, 토큰 중개 백엔드는 이를 프런트엔드에 반환하지 않는 것이 좋다(SHOULD NOT). 대신 갱신 토큰을 사용하여 권한 부여 서버에서 더 작은 범위 집합을 가진 접근 토큰을 요청하는 것이 좋다(SHOULD). 이러한 접근 토큰 downscoping 메커니즘의 지원은 권한 부여 서버의 재량에 따른다는 점에 유의한다.

토큰 중개 백엔드는 특정 리소스 서버에 대한 접근 토큰을 얻기 위해 [RFC8707]에 의존할 때, downscoping과 유사한 메커니즘을 사용할 수 있다.

BFF와 유사하게, 토큰 중개 백엔드는 사용자의 세션을 추적하기 위해 브라우저 쿠키에 의존한다. BFF와 동일한 구현 지침 및 보안 고려 사항이 적용되며, 이는 6.1.2.3절에서 논의된다.

6.2.2.5. OAuth와 OpenID Connect 결합

BFF와 유사하게, 토큰 중개 백엔드는 OAuth와 OpenID Connect를 단일 흐름으로 결합하도록 선택할 수 있다. 자세한 내용은 6.1.2.4절을 참조한다.

6.2.2.6. 실용적 배포 시나리오

정적 JavaScript 또는 WASM 코드를 제공하는 것은 권한 부여 서버와의 상호 작용을 처리하는 것과 별도의 책임이다. 위에 제시된 그림에서 토큰 중개 백엔드와 정적 웹 호스트는 두 개의 별도 엔티티로 표시된다. 실제 배포 시나리오에서 이러한 구성 요소는 단일 서비스(즉, 토큰 중개 백엔드가 정적 코드를 제공), 두 개의 별도 서비스(즉, CDN과 토큰 중개 백엔드), 또는 단일 서비스 내 두 구성 요소(즉, 클라우드 플랫폼의 정적 호스팅과 서버리스 함수)로 배포될 수 있다. 이러한 배포 차이는 이 패턴에서 설명한 관계에 영향을 주지 않지만, cross-origin 통신을 가능하게 하기 위해 CORS를 적절히 구성해야 하는 필요성과 같은 다른 실무적 사항에는 영향을 줄 수 있다.

6.2.3. 보안 고려 사항

6.2.3.1. Authorization Code 권한 부여

토큰 중개 백엔드를 사용하는 주요 이점은 백엔드가 기밀 클라이언트로 동작할 수 있는 능력이다. 따라서 토큰 중개 백엔드는 기밀 클라이언트로 동작해야 한다(MUST). 또한 토큰 중개 백엔드는 접근 토큰 요청을 시작하기 위해 [RFC9700]의 2.1.1절에 설명된 OAuth 2.0 Authorization Code 권한 부여를 사용해야 한다(MUST).

6.2.3.3. 교차 사이트 요청 위조 보호

브라우저 기반 애플리케이션과 토큰 중개 백엔드 사이의 상호 작용은 인증 및 권한 부여를 위해 쿠키에 의존한다. BFF와 마찬가지로, 토큰 중개 백엔드는 Cross-Site Request Forgery (CSRF) 공격을 고려해야 한다.

6.1.3.3절은 CSRF 공격에 대한 다양한 완화 전략의 미묘한 차이를 개괄한다. 특히 토큰 중개 백엔드의 경우, 이러한 CSRF 방어는 애플리케이션이 접근 토큰을 얻을 수 있는 엔드포인트 또는 엔드포인트들에만 적용된다.

6.2.3.4. 고급 OAuth 보안

토큰 중개 백엔드는 서버 측 구성 요소로 실행되는 기밀 클라이언트이다. 토큰 중개 백엔드는 키 기반 클라이언트 인증과 같은 기밀 클라이언트를 위한 보안 모범 사례를 채택할 수 있다.

6.2.4. 위협 분석

이 절은 5절의 공격 시나리오와 결과를 다시 살펴보고, 잠재적인 추가 방어책을 논의한다.

6.2.4.1. 공격 시나리오 및 결과

공격자가 애플리케이션의 실행 컨텍스트에서 악성 코드를 실행할 수 있다면, 다음 공격 시나리오가 관련된다:

  • 접근 토큰에 대한 단일 실행 토큰 탈취(5.1.1절)

  • 접근 토큰에 대한 지속적 토큰 탈취(5.1.2절)

  • 사용자의 브라우저를 통한 요청 프록시(5.1.4절)

이러한 공격 시나리오는 다음 결과로 이어진다는 점에 유의한다:

접근 토큰을 브라우저 기반 애플리케이션에 노출하는 것은 토큰 중개 백엔드 아키텍처 패턴의 핵심 아이디어이다. 그 결과 접근 토큰은 악성 브라우저 기반 코드에 의한 토큰 탈취에 취약해진다.

6.2.4.2. 완화된 공격 시나리오

아래에 나열된 다른 공격 시나리오들은 토큰 중개 백엔드에 의해 효과적으로 완화된다:

  • 갱신 토큰에 대한 단일 실행 토큰 탈취(5.1.1절)

  • 갱신 토큰에 대한 지속적 토큰 탈취(5.1.2절)

  • 새 토큰의 획득 및 추출(5.1.3절)

토큰 중개 백엔드는 갱신 토큰을 브라우저 기반 애플리케이션에 노출하지 않음으로써 앞의 두 공격 시나리오에 대응한다. 공격자가 애플리케이션을 완전히 제어하더라도, 훔칠 갱신 토큰이 전혀 없다.

공격자가 조용한 흐름을 실행하여 새 접근 토큰(그리고 선택적으로 갱신 토큰)을 얻는 세 번째 시나리오는 토큰 중개 백엔드를 기밀 클라이언트로 만들면 완화된다. 공격자가 권한 부여 코드를 얻는 데 성공하더라도, 클라이언트 자격 증명이 없기 때문에 이 코드를 교환할 수 없다. 또한 PKCE를 사용하면 권한 부여 코드에 대한 다른 공격을 방지한다.

토큰 중개 백엔드의 특성 때문에, 잠재적 공격의 다음 결과는 관련이 없어지게 된다:

  • 탈취된 갱신 토큰 악용(5.2.1절 참조)

6.2.4.3. 추가 방어책

이 아키텍처는 본질적으로 접근 토큰을 노출하지만, 애플리케이션의 보안 태세를 높이는 데 도움이 될 수 있는 추가 방어책이 몇 가지 있다.

6.2.4.3.1. 안전한 토큰 저장

토큰 중개 백엔드 패턴의 특성을 고려하면, 브라우저에 영속적 토큰 저장이 필요하지 않다. 필요할 때 애플리케이션은 쿠키 기반 세션을 사용하여 토큰 중개 백엔드에서 언제든 접근 토큰을 얻을 수 있다. 8절은 브라우저의 다양한 저장 메커니즘의 보안 속성에 대해 더 자세한 정보를 제공한다.

접근 토큰이 악성 브라우저 기반 코드의 접근 범위 밖에 저장되어 있더라도, 악성 코드는 여전히 합법적인 애플리케이션을 모방하고 토큰 중개 백엔드로 요청을 보내 최신 접근 토큰을 얻을 수 있다는 점에 유의한다.

6.2.4.3.2. 송신자 제한 토큰 사용

이 아키텍처에서 송신자 제한 접근 토큰을 사용하는 것은 간단하지 않다. 토큰 중개 백엔드는 권한 부여 코드 또는 갱신 토큰을 접근 토큰으로 교환할 책임이 있지만, 애플리케이션이 접근 토큰을 사용한다. DPoP [RFC9449]와 같은 메커니즘을 사용하려면 두 당사자에 걸쳐 책임을 분할해야 하며, 이는 명세에서 정의된 시나리오가 아니다. 이러한 시나리오에서 DPoP를 사용하는 것은 이 문서의 범위를 벗어난다.

6.2.4.4. 요약

토큰 중개 백엔드의 아키텍처는 브라우저 전용 애플리케이션보다 더 복잡하지만, 프록시 BFF를 실행하는 것보다는 덜 복잡하다. 복잡성과 유사하게, 토큰 중개 백엔드가 제공하는 보안 속성은 BFF 사용과 브라우저 전용 애플리케이션 실행 사이 어딘가에 위치한다.

토큰 중개 백엔드는 공격자에게 사용자를 대신한 장기 접근을 부여하는 일반적인 시나리오를 해결한다. 그러나 접근 토큰 탈취라는 결과 때문에, 공격자는 여전히 리소스 서버에 직접 접근할 수 있는 능력을 가진다.

토큰 중개 백엔드 아키텍처를 고려할 때, 6.1절에서 논의한 전체 BFF를 채택하는 것이 가능한 대안인지 평가하는 것이 강력히 권장된다. 사용 사례나 시스템 요구 사항이 프록시 BFF 사용을 방해하는 경우에만, 전체 BFF보다 토큰 중개 백엔드를 고려해야 한다.

6.3. 브라우저 기반 OAuth 2.0 클라이언트

이 절은 OAuth 클라이언트로 동작하며, 브라우저에서 모든 OAuth 책임을 처리하는 브라우저 기반 애플리케이션의 아키텍처를 설명한다. 그 결과 브라우저 기반 애플리케이션은 백엔드 구성 요소의 개입 없이 권한 부여 서버에서 토큰을 얻는다.

공격자가 브라우저에서 악성 코드를 실행할 수 있다면, 이 애플리케이션 아키텍처는 앞서 논의한 모든 공격 시나리오(5.1절)에 취약하다. 본질적으로 공격자는 권한 부여 서버에서 접근 토큰과 갱신 토큰을 얻을 수 있으며, 잠재적으로 사용자를 대신해 보호된 리소스에 장기 접근할 수 있다.

6.3.1. 애플리케이션 아키텍처

Authorization Resource Server Server (B) (C) (D) (E) (A) Static Web Host Browser
그림 3: 브라우저 기반 OAuth 2.0 클라이언트 패턴

이 아키텍처에서는 코드가 먼저 정적 웹 호스트에서 브라우저로 로드되고(A), 그다음 애플리케이션이 브라우저에서 실행된다. 이 시나리오에서 브라우저 기반 애플리케이션은 권한 부여 서버에 인증하기 위한 클라이언트 자격 증명을 보유하지 않는 공개 클라이언트로 간주된다.

애플리케이션은 PKCE 확장(6.3.2.1절에 설명됨)을 사용하는 Authorization Code 흐름을 시작하여 권한 부여 코드(B)를 얻는다. 애플리케이션은 브라우저 API(예: [Fetch])를 사용하여 토큰 엔드포인트(C)로 POST 요청을 보내 권한 부여 코드를 토큰으로 교환한다.

그런 다음 애플리케이션은 8절에 설명된 적절한 브라우저 API를 사용하여 접근 토큰과 선택적 갱신 토큰을 가능한 한 안전하게 저장할 책임을 진다.

브라우저의 애플리케이션이 리소스 서버로 요청을 보내려 할 때, 리소스 서버와 직접 상호 작용할 수 있다. 애플리케이션은 요청에 접근 토큰을 포함하고(D), 리소스 서버의 응답을 받는다(E).

6.3.2. 구현 세부 사항

공개 클라이언트([RFC6749]의 2.1절)이고 [RFC6749]의 4.1절에 설명된 Authorization Code 권한 부여 유형을 사용하는 브라우저 기반 애플리케이션은 이 절에 설명된 다음 추가 요구 사항도 따라야 한다(MUST).

6.3.2.1. Authorization Code 권한 부여

공개 클라이언트인 브라우저 기반 애플리케이션은 접근 토큰을 얻을 때 Proof Key for Code Exchange (PKCE [RFC7636]) 확장을 구현해야 하며(MUST), 권한 부여 서버는 이러한 클라이언트를 위해 PKCE를 지원하고 강제해야 한다(MUST).

PKCE 확장은 권한 부여 코드가 가로채여 악성 클라이언트에 의해 접근 토큰으로 교환되는 공격을 방지한다. 이는 권한 부여 코드를 교환하는 클라이언트 인스턴스가 흐름을 시작한 동일한 인스턴스인지 권한 부여 서버가 확인할 수 있는 방법을 제공함으로써 이루어진다.

6.3.2.2. 교차 사이트 요청 위조 보호

브라우저 기반 애플리케이션은 redirect URI에 대한 CSRF 공격을 방지해야 한다(MUST). 이는 아래 중 하나로 달성할 수 있다:

  • 이 클라이언트에 대해 PKCE를 요구하도록 권한 부여 서버를 구성하기

  • CSRF 토큰을 전달하기 위해 OAuth state 매개변수에 고유 값을 사용하고 검증하기

  • 애플리케이션이 OpenID Connect도 사용하는 경우, [OpenID]에 설명된 대로 OpenID Connect nonce 매개변수를 사용하고 검증하기

Authorization Code 흐름을 위한 적절한 CSRF 방어를 선택하는 데 대한 추가 세부 사항은 [RFC9700]의 2.1절을 참조한다.

6.3.2.3. 갱신 토큰

브라우저 기반 클라이언트의 경우, 애플리케이션이 명시적으로 DPoP [RFC9449]를 사용하지 않는 한, 갱신 토큰은 일반적으로 bearer token이다. 그 결과, 유출된 갱신 토큰의 위험은 유출된 접근 토큰보다 더 크다. 공격자가 훔친 갱신 토큰을 사용하여 권한 부여 서버에 탐지되지 않을 가능성이 있는 상태로 새 접근 토큰을 계속 얻을 수 있기 때문이다.

권한 부여 서버는 브라우저 기반 애플리케이션에 갱신 토큰을 발급할지 여부를 선택할 수 있다. 그러나 서드파티 쿠키 차단 메커니즘의 영향을 고려하면, 갱신 토큰 사용은 훨씬 더 매력적이 되었다. [RFC9700][RFC6749]의 권고 사항 위에 갱신 토큰에 관한 몇 가지 추가 요구 사항을 설명한다. 이 BCP를 준수하는 애플리케이션과 권한 부여 서버는 브라우저 기반 애플리케이션에 갱신 토큰이 발급되는 경우, 갱신 토큰에 관한 [RFC9700]의 권고 사항도 따라야 한다(MUST).

특히 권한 부여 서버는 다음을 수행해야 한다:

  • 각 사용 시 갱신 토큰을 회전시키거나, [RFC9700]의 4.14.2절에 설명된 송신자 제한 갱신 토큰을 사용해야 한다(MUST)

  • 갱신 토큰에 최대 수명을 설정하거나, 갱신 토큰이 일정 시간 동안 사용되지 않은 경우 만료되도록 해야 한다(MUST)

  • 회전된 갱신 토큰을 발급할 때, 갱신 토큰에 사전 설정된 만료 시간이 있는 경우, 새 갱신 토큰의 수명을 초기 갱신 토큰의 수명을 넘어 연장해서는 안 된다(MUST NOT)

전체 갱신 토큰 수명을 초기 갱신 토큰의 수명으로 제한하면, 훔친 갱신 토큰이 무기한 사용될 수 없도록 보장한다.

예를 들면 다음과 같다:

  • 사용자가 애플리케이션을 승인하여, 10분 동안 지속되는 접근 토큰과 8시간 동안 지속되는 갱신 토큰이 발급된다

  • 10분 후 초기 접근 토큰이 만료되므로, 애플리케이션은 갱신 토큰을 사용하여 새 접근 토큰을 얻는다

  • 권한 부여 서버는 10분 동안 지속되는 새 접근 토큰과 7시간 50분 동안 지속되는 새 갱신 토큰을 반환한다

  • 이는 초기 권한 부여 시점부터 8시간이 지날 때까지 계속된다

  • 이 시점에서, 애플리케이션이 8시간 후에 갱신 토큰을 사용하려고 하면 요청이 실패하고, 애플리케이션은 사용자의 인증 또는 이전에 설정된 세션에 의존하는 Authorization Code 흐름을 다시 시작해야 한다

권한 부여 서버는 갱신 토큰의 수명을 권한 부여 서버와의 사용자의 인증된 세션에 연결하는 것이 좋다(SHOULD). 이렇게 하면 사용자가 로그아웃할 때, 브라우저 기반 애플리케이션에 이전에 발급된 갱신 토큰이 무효화되어 단일 로그아웃 시나리오를 모방한다. 권한 부여 서버는 다른 공개 클라이언트와 비교하여 브라우저 기반 애플리케이션에 대해 갱신 토큰 발급, 수명 및 만료에 관한 서로 다른 정책을 설정할 수 있다(MAY).

6.3.3. 보안 고려 사항

6.3.3.1. 클라이언트 인증

브라우저 기반 애플리케이션의 소스 코드는 최종 사용자의 브라우저로 전달되므로, 프로비저닝된 비밀을 포함하기에 적합하지 않다. 그 결과 브라우저 기반 애플리케이션은 일반적으로 [RFC6749]의 2.1절에 정의된 공개 클라이언트로 배포된다.

여러 사용자에게 배포되는 앱의 일부로 정적으로 포함된 비밀은 기밀 비밀로 취급되어서는 안 된다. 한 사용자가 자신의 사본을 검사하여 공유 비밀을 알 수 있기 때문이다. 이 이유와 [RFC6819]의 5.3.1절에 명시된 이유 때문에, 권한 부여 서버는 공유 비밀을 사용하는 브라우저 기반 애플리케이션의 클라이언트 인증을 요구해서는 안 된다(MUST NOT). 이는 이미 client_id 매개변수로 제공되는 클라이언트 식별 이상의 가치를 제공하지 않기 때문이다.

SPA 클라이언트에 정적으로 포함된 공유 비밀을 여전히 요구하는 권한 부여 서버는 클라이언트를 공개 클라이언트로 취급해야 하며(MUST), 그 비밀을 클라이언트 신원의 증명으로 받아들여서는 안 된다. 추가 조치가 없다면 이러한 클라이언트는 클라이언트 가장(아래 6.3.3.2절 참조)에 취약하다.

6.3.3.2. 클라이언트 가장

[RFC6749]의 10.2절에 명시된 것처럼, 권한 부여 서버는 클라이언트 애플리케이션의 신원을 보장할 수 있는 경우를 제외하고, 사용자 동의 또는 상호 작용 없이 권한 부여 요청을 자동으로 처리하지 않는 것이 좋다(SHOULD NOT).

권한 부여 서버가 redirect URI를 고정된 절대 HTTPS URI 집합으로 제한하여 와일드카드 도메인, 와일드카드 경로 또는 와일드카드 query string 구성 요소의 사용을 방지하는 경우, 등록된 절대 HTTPS URI의 정확한 일치는 client_id에 대한 이전 요청이 이미 승인된 경우 권한 부여 요청을 자동으로 처리할지 결정하기 위한 클라이언트의 신원 증명으로 권한 부여 서버에 의해 받아들여질 수 있다(MAY).

6.3.3.2.1. Authorization Code 리디렉션

클라이언트는 하나 이상의 redirect URI를 권한 부여 서버에 등록해야 하며(MUST), 권한 부여 요청에서는 정확히 등록된 redirect URI만 사용해야 한다.

권한 부여 서버는 [RFC9700]의 4.1.1절에 설명된 대로 등록된 redirect URI와 정확히 일치할 것을 요구해야 한다(MUST). 이는 권한 부여 코드를 대상으로 하는 공격을 방지하는 데 도움이 된다.

6.3.3.3. 브라우저 내 통신 흐름의 보안

브라우저 기반 애플리케이션에서는 기본 창을 리디렉션하는 대신 팝업이나 iframe과 같은 보조 창에서 OAuth 흐름을 실행하는 것이 일반적이다. 이러한 흐름에서 브라우저 기반 앱은 예를 들어 페이지 새로고침을 피하거나 프레임 기반 흐름을 조용히 실행하기 위해 기본 창의 제어를 유지한다.

브라우저 기반 앱과 권한 부여 서버가 서로 다른 프레임에서 호출되는 경우, top-level 리디렉션 대신 postMessage API(a.k.a. [WebMessaging])와 같은 브라우저 내 통신 기법을 사용해야 한다. 메시지의 기밀성과 진정성을 보장하기 위해, postMessage의 송신자 origin과 수신자 origin은 postMessage API가 본질적으로 제공하는 메커니즘([WebMessaging]의 9.3.2절)을 사용하여 모두 검증해야 한다(MUST).

[RFC9700]의 4.18절은 브라우저 내 통신 흐름의 보안과 이러한 공격을 방어하기 위해 브라우저 기반 애플리케이션 및 권한 부여 서버가 적용해야 하는(MUST) 대응책에 대한 추가 세부 사항을 제공한다.

6.3.3.4. Cross-Origin 요청

이 시나리오에서 애플리케이션은 브라우저 API를 사용하여 권한 부여 서버와 리소스 서버로 요청을 보낸다. OAuth 2.0의 특성상 이러한 요청은 일반적으로 cross-origin이며, 브라우저가 강제하는 cross-origin 통신 제한의 대상이 된다. 권한 부여 서버와 리소스 서버는 애플리케이션이 필요한 cross-origin 요청을 할 수 있도록 필요한 CORS 헤더([Fetch]에 정의됨)를 보내야 한다(MUST). 브라우저 기반 OAuth 클라이언트가 권한 부여 서버 또는 리소스 서버와 동일한 출처에서 실행되는 이례적인 시나리오에서는, 필요한 상호 작용을 가능하게 하기 위해 CORS 정책이 필요하지 않다는 점에 유의한다.

권한 부여 서버의 경우, CORS 구성은 브라우저 기반 애플리케이션이 권한 부여 코드를 토큰으로 교환하는 토큰 엔드포인트와 관련이 있다. 또한 권한 부여 서버가 discovery metadata URL, JSON Web Key Sets, dynamic client registration, revocation, introspection 또는 user info 엔드포인트와 같은 추가 엔드포인트를 애플리케이션에 제공하는 경우, 이러한 엔드포인트도 브라우저 기반 애플리케이션에서 접근될 수 있다. 따라서 권한 부여 서버는 이러한 엔드포인트에서 CORS를 지원할 책임이 있다.

이 명세는 구체적인 CORS 정책 구현을 결정하기 위한 지침을 포함하지 않는다. 이는 와일드카드 origin 또는 더 제한적인 구성으로 이루어질 수 있다. CORS에는 서로 다른 보안 속성을 가진 두 가지 동작 모드가 있다는 점에 유의한다. 첫 번째 모드는 이전에 simple requests로 알려진 CORS-safelisted 요청에 적용되며, 브라우저는 요청을 보내고 CORS 응답 헤더를 사용하여 응답을 클라이언트 측 실행 컨텍스트에 노출할 수 있는지 결정한다. 사용자 지정 요청 헤더가 있는 요청과 같은 non-CORS-safelisted 요청의 경우, 브라우저는 먼저 preflight를 사용하여 CORS 정책을 확인한다. 브라우저는 서버가 preflight 응답에서 승인을 보낼 때에만 실제 요청을 보낸다.

권한 부여 서버의 특정 구성 때문에, preflight에 대한 CORS 응답이 실제 요청에 대한 CORS 응답과 다를 수 있다는 점에 유의한다. preflight 동안 권한 부여 서버는 제공된 origin만 검증할 수 있지만, 실제 요청 동안에는 권한 부여 서버가 클라이언트 ID와 같은 전체 요청 데이터를 가진다. 따라서 권한 부여 서버는 preflight 중에는 알려진 origin을 승인할 수 있지만, 실제 요청에서는 origin을 이 특정 클라이언트의 사전 등록된 origin 목록과 비교한 뒤 거부할 수 있다.

6.3.4. 위협 분석

이 절은 5절의 공격 시나리오와 결과를 다시 살펴보고, 잠재적인 추가 방어책을 논의한다.

6.3.4.1. 공격 시나리오 및 결과

공격자가 애플리케이션의 실행 컨텍스트에서 악성 코드를 실행할 수 있다면, 다음 공격 시나리오가 관련된다:

가장 위험한 공격 시나리오는 새 토큰의 획득 및 추출이다. 이 공격 시나리오에서 공격자는 권한 부여 서버와만 상호 작용하므로, 클라이언트의 OAuth 기능에 대한 실제 구현 세부 사항은 관련이 없게 된다. 합법적인 클라이언트 애플리케이션이 토큰을 공격자로부터 완전히 격리할 방법을 찾더라도, 공격자는 여전히 권한 부여 서버에서 토큰을 얻을 수 있다.

이러한 공격 시나리오는 다음 결과로 이어진다는 점에 유의한다:

6.3.4.2. 추가 방어책

이 아키텍처는 본질적으로 악성 브라우저 기반 코드에 취약하지만, 애플리케이션의 보안 태세를 높이는 데 도움이 될 수 있는 추가 방어책이 몇 가지 있다. 이러한 방어책 중 어느 것도 공격자가 토큰을 얻기 위해 새 흐름을 실행할 수 있게 하는 근본 문제를 해결하거나 수정하지 않는다는 점에 유의한다.

6.3.4.2.1. 안전한 토큰 저장

토큰을 직접 처리할 때, 애플리케이션은 접근 토큰과 갱신 토큰을 저장하기 위해 서로 다른 저장 메커니즘을 선택할 수 있다. Local Storage [WebStorage]와 같은 보편적으로 접근 가능한 저장 영역은 Web Worker [WebWorker]와 같은 더 격리된 저장 영역보다 악성 JavaScript에서 접근하기 더 쉽다. 8절은 서로 다른 저장 메커니즘과 그 절충점을 더 자세히 논의한다.

실용적인 구현 패턴은 Web Worker [WebWorker]를 사용하여 갱신 토큰을 격리하고, 리소스 서버로 요청하는 접근 토큰을 애플리케이션에 제공할 수 있다. 이는 공격자가 애플리케이션의 갱신 토큰을 사용하여 새 토큰을 얻는 것을 방지한다.

그러나 토큰을 공격자로부터 완전히 격리하는 토큰 저장 메커니즘조차도, 공격자가 새 토큰 집합을 얻기 위해 새 흐름을 실행하는 것을 방지하지는 못한다(5.1.3절 참조).

6.3.4.2.2. 송신자 제한 토큰 사용

브라우저 기반 OAuth 클라이언트는 DPoP [RFC9449]를 구현하여 bearer 접근 토큰과 bearer 갱신 토큰에서 송신자 제한 토큰으로 전환할 수 있다. 이러한 구현에서 DPoP 증명에 서명하는 데 사용되는 개인 키는 브라우저가 처리한다(추출할 수 없는 [CryptoKeyPair][W3C.IndexedDB]를 사용해 저장됨). 그 결과 DPoP 사용은 XSS 공격자가 애플리케이션의 토큰을 유출하는 시나리오(5.1.1절5.1.2절 참조)를 효과적으로 방지한다.

DPoP 사용은 공격자가 새 접근 토큰 (그리고 선택적으로 갱신 토큰)을 얻기 위해 새 흐름을 실행하는 것을 방지하지 않는다는 점에 유의한다(5.1.3절). DPoP가 필수인 경우에도, 공격자는 자신이 제어하는 키 쌍에 새 토큰 집합을 바인딩할 수 있으며, 이를 통해 송신자 제한 토큰을 유출하고 공격자가 제어하는 키를 사용해 필요한 DPoP 증명을 계산함으로써 사용할 수 있다.

6.3.4.2.3. 권한 부여 서버에 대한 접근 제한

공격자가 새 접근 토큰과 (선택적으로 갱신 토큰)을 얻는 시나리오(5.1.3절)는 브라우저 내부에서 권한 부여 서버와 직접 상호 작용할 수 있는 능력에 의존한다. 이론적으로, 공격자가 권한 부여 서버와 조용히 상호 작용하지 못하도록 하는 방어는 가장 위험한 공격 시나리오를 해결할 수 있다. 그러나 실제로 이러한 방어는 효과적이지 않거나 실용적이지 않다.

완전성을 위해 이 BCP는 아래에 몇 가지 옵션을 나열한다. 이러한 방어 중 어느 것도 실질적으로 사용 가능한 보안 이점을 제공하지 않으므로 권장되지 않는다는 점에 유의한다.

권한 부여 서버는 iframe 내부에서 발생하는 권한 부여 요청을 차단할 수 있다. 이는 5.1.3절의 정확한 시나리오는 방지하지만, 공격 시나리오의 약간의 변형에는 작동하지 않는다. 예를 들어, 공격자는 팝업 창이나 pop-under 창에서 조용한 흐름을 시작할 수 있다. 또한 브라우저 전용 OAuth 클라이언트는 일반적으로 사용자의 인증 상태를 부트스트랩하기 위해 숨겨진 iframe 기반 흐름에 의존하므로, 이 접근 방식은 사용자 경험에 상당한 영향을 미칠 것이다.

권한 부여 서버는 모든 Authorization Code 흐름에서 사용자 동의를 필수로 만들도록 선택할 수 있다 ([RFC6749]의 10.2절에 설명됨). 이로써 권한 부여 코드를 발급하기 전에 사용자 상호 작용이 요구된다. 이 접근 방식은 공격자가 조용한 흐름을 실행하여 새 토큰 집합을 얻는 것을 더 어렵게 만들 수 있다. 그러나 지속적으로 동의를 요구함으로써 사용자 경험에도 상당한 영향을 미친다. 그 결과 이 접근 방식은 "동의 피로"를 초래하여, 사용자가 공격자가 시작한 흐름과 관련되어 있을 때도 동의를 무심코 승인할 가능성이 높아진다.

6.3.4.3. 요약

요약하면, 브라우저 기반 OAuth 클라이언트 애플리케이션의 아키텍처는 단순하지만, 애플리케이션의 공격 표면을 크게 증가시키는 결과를 낳는다. 공격자는 클라이언트를 하이재킹할 수 있을 뿐만 아니라, 브라우저 기반 애플리케이션에서 완전한 기능을 가진 토큰 집합을 추출할 수도 있다.

이 아키텍처는 비즈니스 애플리케이션, 민감한 애플리케이션 및 개인 데이터를 처리하는 애플리케이션에는 권장되지 않는다.

7. 非推奨および廃止されたアーキテクチャパターン

クライアントアプリケーションとバックエンドアプリケーションは、 脅威、攻撃者モデル、および現代的なアプリケーションセキュリティに関する一般的な理解とともに、 過去 20 年で大きく進化してきました。その結果、業界で一般に受け入れられていた以前の推奨事項や OAuth Working Group によって公開された推奨事項は、もはや推奨されないことが多く、 提案された解決策も期待されるセキュリティ要件を満たすには不十分であることがよくあります。

本節では、現代のブラウザベースの OAuth アプリケーションでの使用が 推奨されない、いくつかの代替アーキテクチャパターンについて説明します。本節では、 関連する場合に攻撃シナリオと影響を調査する脅威分析とともに、各パターンについて説明します。

7.1. 単一ドメインの ブラウザベースアプリケーション(OAuth を使用しない)

単純なアプリケーションが、セッション管理の概念を置き換えるために OAuth を使用することで、不必要に複雑にされることがあまりにも多くあります。 典型的な例は、サーバーサイド MVC アプリケーションの現代的な形態であり、 これは現在、サーバーサイド API に支えられたブラウザベースのフロントエンドで構成されます。

このようなアプリケーションでは、ユーザー認証を専用プロバイダーに 委ねるために OpenID connect を使用すると、アプリケーションのアーキテクチャと開発を 大幅に単純化できます。しかし、フロントエンドとバックエンドの間のアクセスを管理するために OAuth を使用することは、多くの場合不要です。アクセストークンを使用する代わりに、 アプリケーションは従来の cookie ベースのセッション状態に依存して、ユーザーの認証状態を 追跡できます。セッション cookie を保護するためのセキュリティガイドラインは、Section 6.1.3.2 で 説明されています。

OAuth を使用しないという助言は本書では場違いに見えるかもしれませんが、 OAuth はもともと API へのサードパーティまたはフェデレーションアクセスのために作成されたため、 単一の共通ドメインデプロイでは最良の解決策ではない可能性があることに注意することが重要です。 とはいえ、共通ドメインアーキテクチャであっても OAuth を使用することには、 いくつかの利点がまだあります。

  • 将来、たとえば後からシステムに新しいドメインを 追加する場合などに、より大きな柔軟性を可能にします。OAuth がすでに導入されていれば、 新しいドメインを追加しても追加の再アーキテクチャは不要です。

  • 統合のために独自コードを書くのではなく、既存の ライブラリサポートを活用できます。

  • ログインおよび多要素認証のサポート、 アカウント管理、およびリカバリーをアプリケーションロジックの一部にするのではなく、 OAuth サーバーに集中させます。

  • ユーザーの認証とリソース提供の間で責務を分割します

ファーストパーティの同一ドメインシナリオでブラウザベースの アプリケーションに OAuth を使用すると、これらの利点が得られ、上で説明した いずれのアーキテクチャパターンによっても実現できます。

7.1.1. 脅威分析

OAuth を使用しないため、このアーキテクチャパターンは 次の攻撃シナリオにのみ脆弱です。ユーザーのブラウザを介したリクエストのプロキシ (Section 5.1.4)。その結果、 このパターンは次の影響をもたらす可能性があります。クライアントの乗っ取り(Section 5.2.3

7.2. OAuth Implicit Grant

OAuth 2.0 Implicit grant type(Section 4.2 of [RFC6749] で定義)は、 認可コード交換ステップなしに、認可サーバーが認可レスポンス(front channel)で アクセストークンを発行することによって機能します。この場合、アクセストークンは redirect URI の fragment 部分で返されるため、攻撃者にアクセストークンを傍受して 盗む複数の機会を与えます。

Implicit grant type のセキュリティ特性により、これはもはや 推奨されるベストプラクティスではありません。このフローの使用を効果的に防ぐために、 認可サーバーは認可レスポンスでアクセストークンを発行してはならず(MUST NOT)、 トークンエンドポイントからのみアクセストークンを発行しなければなりません(MUST)。 ブラウザベースのクライアントはアクセストークンを取得するために Authorization Code grant type を使用しなければならず(MUST)、Implicit grant type を使用してはなりません(MUST NOT)。

7.2.1. 歴史的注記

歴史的に、Implicit grant type はブラウザベースの アプリケーションに利点を提供していました。JavaScript はページの再読み込みを トリガーすることなく、URL の fragment 部分を常に任意に読み取り、操作できたためです。 これは、アプリが取得した後に URL からアクセストークンを削除するために必要でした。 さらに、CORS がブラウザに広く普及するまで、Implicit grant type はブラウザまたは サーバーで CORS サポートを必要としない代替フローを提供していました。

現代のブラウザには現在、 [HTML] の "Session history and navigation" で説明される Session History API があり、 ページの再読み込みをトリガーすることなく URL の path および query string component を変更する機構を提供しています。さらに、CORS は広くサポートされ、 多くの目的で single-page application によってよく使用されています。これは、 現代のブラウザベースのアプリケーションが、PKCE 付きの OAuth 2.0 Authorization Code grant type を使用できることを意味します。Session History API により、ページの再読み込みを トリガーせずに query string から認可コードを削除する能力があり、トークンエンドポイントでの CORS サポートにより、認可サーバーが別ドメイン上にある場合でもアプリがトークンを 取得できるためです。

7.2.2. 脅威分析

本節で説明するアーキテクチャパターンは、 次の攻撃シナリオに脆弱です。

その結果、このパターンは次の影響をもたらす可能性があります。

7.2.3. Implicit Grant に対するさらなる攻撃

すでに説明した攻撃シナリオと影響に加えて、Implicit grant type の廃止をさらに裏付ける追加の攻撃がいくつかあります。[RFC6819] および [RFC9700] の Section 4.1.2 で説明されている Implicit grant type に対する多くの攻撃には、 十分な緩和戦略がありません。以下の節では、Implicit grant type を使い続ける限り 緩和できない具体的な攻撃について説明します。

7.2.3.1. Redirect URI の操作

攻撃者が認可レスポンスを自身の制御下にある URI へ 送信させることができる場合、 アクセストークンを含む認可レスポンスへ直接アクセスできます。 この攻撃を実行するいくつかの方法は、[RFC9700] で詳しく 説明されています。

7.2.3.2. ブラウザ履歴における アクセストークン漏えい

攻撃者はブラウザの履歴からアクセストークンを 取得できる可能性があります。 [RFC6819] によって推奨される対策は、 トークンに短い有効期限を使用すること、およびブラウザがレスポンスを キャッシュすべきでないことを示すことに限られます。 これらはいずれもこの攻撃を完全には防止せず、潜在的な被害を軽減するだけです。

さらに、多くのブラウザは現在、ブラウザ履歴を クラウドサービスや複数のデバイスにも同期しており、URL からアクセストークンを 抽出するためのさらに広い攻撃面を提供しています。

これは [RFC9700] の Section 4.3.2 で、より詳しく説明されています。

7.2.3.3. スクリプトの操作

攻撃者は、たとえば企業ネットワークによって ブラウザの HTTPS 接続が傍受されている場合など、さまざまな手段を通じて ページを変更したり、ブラウザへスクリプトを注入したりできる可能性があります。 TLS 層への攻撃は通常、防止のための基本的なセキュリティ推奨事項の範囲外ですが、 ブラウザベースのアプリケーションの場合、それらははるかに実行しやすくなります。 注入されたスクリプトにより、攻撃者はページ上のすべてにアクセスできるようになります。

アプリケーションがアクセストークンを取得する既知の 標準的な方法を使用する場合、ページ上で悪意あるスクリプトが実行されるリスクは 増幅される可能性があります。すなわち、攻撃者は常に window.location 変数を見てアクセストークンを見つけることができます。この脅威プロファイルは、 Authorization Code フローによって取得されたアクセストークンがどこに、 またはどのように保存され得るかを知ったうえで、個別のアプリケーションを 特に標的にする攻撃者とは異なります。

7.2.3.4. サードパーティ スクリプトへのアクセストークン漏えい

ブラウザベースのアプリケーションでは、 分析ツール、クラッシュレポート、さらにはソーシャルメディアの "like" ボタンのようなものなど、サードパーティスクリプトを使用することは比較的一般的です。 このような状況では、アプリケーションの作者は、アプリケーション内で実行される コード全体を完全には把握できない可能性があります。アクセストークンが fragment で 返される場合、それはページ上の任意のサードパーティスクリプトから見えます。

7.2.4. Implicit Grant の欠点

推奨される Authorization Code grant type を使用する場合と 比較して、Implicit grant type が不利である追加の理由はいくつかあります。

  • OAuth 2.0 は、特定のアクセストークンがその クライアント向けであったことをクライアントが検証する機構を提供していません。 そのため、悪意ある当事者が何らかの別の手段で取得したアクセストークンを クライアントに渡した場合、誤用や偽装攻撃につながる可能性があります。

  • front-channel リダイレクトでアクセストークンを 返すと、このリダイレクトが失敗または傍受される方法が多くあるため、 認可サーバーはアクセストークンが実際にアプリケーションへ到達することを 保証できません。

  • Implicit grant type をサポートするには、 追加のコード、より多くの保守、および関連するセキュリティ上の考慮事項の理解が 必要です。認可サーバーを Authorization Code grant type のみに制限すると、 実装の攻撃面を減らせます。

  • ブラウザベースのアプリケーションが native app に ラップされる場合、[RFC8252] もいずれにせよ PKCE 付きの Authorization Code grant type の使用を要求します。

7.3. Resource Owner Password Grant

Resource Owner Password Credentials Grant は、 [RFC9700] の Section 2.4 で説明されているように、使用してはなりません(MUST NOT)。代わりに、 Authorization Code grant type を使用してユーザーを認可サーバーへリダイレクトすることで、 認可サーバーは、フィッシングされにくい安全な認証オプションをユーザーに提示し、 シングルサインオンセッションを活用し、またはサードパーティ ID プロバイダーを 使用する機会を得られます。対照的に、Resource Owner Password Credentials Grant はこれらのための組み込み機構を提供せず、代わりにカスタムプロトコルで 拡張する必要があります。

このベストプラクティスに適合するために、OAuth または OpenID Connect を使用するブラウザベースのアプリケーションは、本書で説明する リダイレクトベースのフロー(例: OAuth Authorization Code grant type)を 使用しなければなりません(MUST)。

7.4. Service Worker での OAuth フローの処理

攻撃者が既存のトークンを抽出したり、新しいトークンセットを 取得したりする能力を制限しようとして、Service Worker ([W3C.service-workers])を 使用するパターンが過去に提案されました。このパターンでは、アプリケーションが 読み込まれた際の最初の動作として Service Worker を登録します。Service Worker は、 トークンを取得するための Authorization Code フローを実行し、リソースサーバーへの 送信リクエストを適切なアクセストークンで拡張する責任を負います。さらに、 Service Worker は、クライアントアプリケーションのコードが認可サーバーのエンドポイントを 直接呼び出すことをブロックします。この制限は、攻撃シナリオ「新しいトークンの取得および抽出」 (Section 5.1.3)を標的とすることを 目的としています。

以下に含まれるシーケンス図は、クライアント、Service Worker、 認可サーバー、およびリソースサーバーの間の相互作用を示しています。

Service Resource Authorization User Application Worker Server Server browse /authorize redirect w/ authorization code < - - - - - - - - - - - - - - - - - token request w/ auth code /token < - - - - - - - - - - - - - - - - - resource request resource request w/ access token User Application Service Resource Authorization Worker Server Server
図 4: OAuth 2.0 Service Worker パターン

なお、このパターンは、ブラウザ内で実行されるアプリケーションに トークンを決して公開しません。Service Worker は分離された実行環境で実行されるため、 共有メモリはなく、クライアントアプリケーションが Service Worker の実行に影響を与える方法は ありません。

7.4.1. 脅威分析

本節で説明するアーキテクチャパターンは、 次の攻撃シナリオに脆弱です。

その結果、このパターンは次の影響をもたらす可能性があります。

7.4.1.1. Service Worker への攻撃

Service Worker を使用することによる一見有望な セキュリティ上の利点は、そのセキュリティ上の制限についてより詳細な議論を 必要とします。関連する攻撃シナリオ(Section 5.1)から アプリケーションを完全に保護するために、Service Worker は 2 つのセキュリティ要件を 満たす必要があります。

  1. 攻撃者がトークンを流出させることを防ぐ

  2. 攻撃者が新しいトークンセットを 取得することを防ぐ

登録されると、Service Worker は Authorization Code フローを実行し、トークンを取得します。Service Worker は自身の分離された 実行環境内でトークンを追跡するため、潜在的に悪意あるコードを含むいかなる アプリケーションコードからもそれらに手が届きません。その結果、Service Worker は トークン流出を防ぐという最初の要件を満たします。これは、Section 5.1 で説明した 最初の 2 つの攻撃シナリオを本質的に無力化します。

2 つ目のセキュリティ要件を満たすためには、 Service Worker は、正当なアプリケーションを制御する攻撃者が新しい Authorization Code grant を実行できないことを保証できなければなりません。 これは Section 5.1.3 で 議論される攻撃です。Service Workers の性質上、登録された Service Worker は、 そのような新しいフローを開始するすべての送信リクエストを、frame や新しい window で 発生する場合であってもブロックできます。

しかし、アプリケーション内で実行されている悪意あるコードは、 この Service Worker の登録を解除できます。Service Worker の登録解除は アプリケーションに大きな機能的影響を与える可能性があるため、ブラウザが軽く扱う 操作ではありません。したがって、登録解除された Service Worker はそのように マークされますが、現在実行中のすべてのインスタンスは、対応する browsing context が 終了するまで(例: タブやウィンドウを閉じるまで)アクティブなままです。 そのため、攻撃者が Service Worker の登録を解除しても、それはアクティブなままであり、 攻撃者が認可サーバーに到達することを防止できます。

Service Worker の登録解除の結果の 1 つは、 新しい browsing context が開かれたときに、それが存在しないことです。 そのため、攻撃者がまず Service Worker の登録を解除し、その後 frame で新しい フローを開始すると、その frame の browsing context に関連付けられた Service Worker は存在しません。その結果、攻撃者は自身の新しい Authorization Code grant を実行し、frame の URL から認可コードを抽出し、それをトークンと 交換できるようになります。本質的に、Service Worker は 2 つ目のセキュリティ要件を 満たせず、攻撃者が新しいトークンセットを取得するシナリオ(Section 5.1.3)に対して脆弱なままとなります。

これらの欠点に加えて、Service Worker の登録と 維持のかなりの複雑さを考慮すると、このパターンは推奨されません。

最後に、Service Worker の使用自体は アプリケーションの攻撃面を増加させないことに注意してください。実際には、 Service Workers は、送信リクエストに OAuth アクセストークンを含めるサポートを 既存の legacy application に後付けするためによく使用されます。これらのシナリオにおける Service Worker は、アプリケーションのセキュリティ特性を変えるものではなく、 アプリケーションの開発と保守を単に簡素化するだけです。

8. ブラウザにおけるトークンストレージ

ブラウザベースのアプリケーションが OAuth アクセストークンまたは リフレッシュトークンを直接扱う場合、それらのトークンを一時的または永続的に保存する責任を負います。 その結果、アプリケーションはトークンをどのように管理するか(例: インメモリか永続ストレージか)、 またメインアプリケーションコードからトークンをさらに分離するためにどの手順を取るかを 決定する必要があります。本節では、いくつかの異なるストレージ機構とその性質について説明します。 これらの推奨事項は OAuth トークンの固有の性質を考慮しており、その一部は一般的なブラウザ セキュリティ推奨事項と重なる可能性があります。

ブラウザベースのトークンストレージ解決策のセキュリティ特性を議論する場合、 攻撃者がブラウザベースのアプリケーションを侵害したときの能力を理解することが重要です。 以前の議論と同様に、2 つの主要な攻撃シナリオを考慮に入れるべきです。

  1. 攻撃者がストレージからトークンを取得する

  2. 攻撃者が provider(例: 認可サーバーまたは トークン仲介バックエンド)からトークンを取得する

攻撃者のコードは正当なアプリケーションのコードと区別できなくなるため、 攻撃者は常に、正当なアプリケーションコードとまったく同じ方法で provider からトークンを 要求できます。その結果、完全に分離されたトークンストレージ解決策であっても、 攻撃者が provider からトークンを要求するという 2 つ目の脅威の危険性に対処することはできません。

とはいえ、ブラウザベースのストレージ解決策の異なるセキュリティ特性は、 攻撃者がストレージから既存のトークンを取得する能力に影響します。

8.1. Cookies

ブラウザ cookie は、ストレージ機構であると同時に トランスポート機構でもあります。ブラウザは対応するリクエストヘッダーおよび レスポンスヘッダーを通じてその両方を自動的にサポートします。その結果、cookie は ブラウザに保存され、cookie の domain、path、またはその他の性質に一致する場合、 送信リクエストに cookie が自動的に含まれます。

cookie に対するヘッダーベースの制御に加えて、ブラウザは cookie を取得および設定する JavaScript Cookie API も提供します。この Cookie API は、 ブラウザにデータを保存する簡単な方法として誤解されることがよくあります。このようなシナリオでは、 JavaScript コードは、後で API 呼び出しの Authorization ヘッダーに含めるために取得する意図で、 トークンを cookie に保存します。しかし、cookie はブラウザベースのアプリケーションの ドメインに関連付けられるため、ブラウザはこのドメインで動作するサーバーへリクエストを行うときにも、 トークンを含む cookie を送信します。そのようなリクエストの一例は、以前のアプリケーション訪問後に ブラウザがアプリケーションを読み込む場合です(Section 6.3 の図のステップ A)。

JavaScript ベースのストレージとして cookie を使用することによる これらの意図しない副作用のため、この慣行は推奨されません(NOT RECOMMENDED)。

なお、この慣行は、BFF における cookie の使用 (Section 6.1.3.2 で説明)とは異なります。そこでは cookie は JavaScript からアクセスできず、 バックエンドへ送信されることを意図しています。

8.2. Service Worker における トークンストレージ

Service Worker([W3C.service-workers])は、トークンを追跡するための 完全に分離された環境を提供します。これらのトークンはクライアントアプリケーションから アクセスできず、流出から効果的に保護されます。これらのトークンのセキュリティを保証するために、 Service Worker はこれらのトークンをアプリケーションと共有できません。その結果、 アプリケーションがトークンを使用して操作を実行したい場合は常に、Service Worker に この操作を実行して結果を返すよう依頼する必要があります。

アプリケーションの実行コンテキストからトークンを分離することを 目指す場合、Service Worker はメインウィンドウと共有されるいかなる永続ストレージ API にも トークンを保存してはなりません(MUST NOT)。たとえば、現在、IndexedDB storage は browsing context と Service Worker の間で共有されているため、Service Worker が メインウィンドウからアクセス不能であるべきデータを永続化する場所としては適していません。 その結果、Service Worker は現在、分離された永続ストレージ領域へアクセスできません。

前に説明したように、Service Worker の使用は、攻撃者が 新しいトークンセットを取得することを防止しません。同様に、アプリケーションが 認可サーバーからトークンを取得して、さらなる管理のためにそれらを Service Worker に 渡す責任を負う場合、攻撃者は正当なアプリケーションと同じ操作を実行して これらのトークンを取得できます。

8.3. Web Worker における トークンストレージ

アプリケーションは Web Worker [WebWorker] を使用できます。これは Service Worker に依存する 前述のものとほぼ同一のシナリオをもたらします。Service Worker と Web Worker の違いは、 アクセスレベルとその実行時の性質です。Service Workers は送信リクエストを傍受して 変更できますが、Web Workers はバックグラウンドタスクを実行するための手段にすぎません。 Web Workers は一時的であり browsing context が閉じられると消滅しますが、 Service Workers はブラウザに登録される永続的なサービスです。

Web Worker を使用するセキュリティ特性は、Service Workers を 使用する場合と同一です。トークンがアプリケーションに公開されると、それらは脆弱になります。 トークンを使用する必要がある場合、それらに依存する操作は Web Worker によって 実行されなければなりません。

リフレッシュトークンを分離する一般的な方法の 1 つは、 Web Workers を使用することです。このようなシナリオでは、アプリケーションは Web Worker から Authorization Code フローを開始します。リダイレクトからの認可コードは Web Worker に転送され、その後 Web Worker がそれをトークンと交換します。Web Worker は リフレッシュトークンをメモリに保持し、アクセストークンをメインアプリケーションへ送信します。 メインアプリケーションは必要に応じてアクセストークンを使用します。アプリケーションが リフレッシュトークンフローを実行する必要がある場合、Web Worker にそうするよう依頼し、 その後アプリケーションは新しいアクセストークンを取得します。

このシナリオでは、アプリケーション自身のリフレッシュトークンは 流出から効果的に保護されますが、アクセストークンはそうではありません。さらに、 攻撃者が新しい Authorization Code フローを実行して自身のトークンを取得することを 防ぐものはありません Section 5.1.3

8.4. インメモリトークン ストレージ

別の選択肢は、永続ストレージを使用せずにトークンをメモリに 保持することです。そうすることで、トークンの露出は現在の実行コンテキストのみに制限されますが、 ページ読み込みの間でトークンを永続化できないという欠点があります。

JavaScript 実行環境では、closure 変数を使用してトークンを 直接アクセスから効果的に保護することにより、インメモリトークンストレージのセキュリティを さらに高めることができます。closures を使用すると、トークンは closure 内の事前定義された 関数、たとえばリソースサーバーへリクエストを行う関数からのみアクセス可能になります。

closures は単純で分離された環境ではうまく機能しますが、 ブラウザの実行環境のような複雑な環境では安全にするのが困難です。たとえば、closure は 自身の操作を実行するために、toString 関数やネットワーク API など、 さまざまな外部関数に依存します。prototype poisoning を使用すると、攻撃者はこれらの関数を 悪意あるバージョンに置き換え、closure の将来の操作がこれらの悪意あるバージョンを 使用するようにできます。悪意ある関数内で、攻撃者は関数の引数にアクセスでき、 これにより closure 内から攻撃者へトークンが露出する可能性があります。

8.5. 永続的トークン ストレージ

本稿執筆時点でブラウザで現在利用可能な永続ストレージ API は、 localStorage([WebStorage])、 sessionStorage([WebStorage])、 および [W3C.IndexedDB] です。

localStorage はページの再読み込みをまたいで永続化され、 すべてのタブ間でも共有されます。このストレージは origin 全体からアクセス可能であり、 より長期に永続化されます。localStorage は、悪意ある JavaScript からの不正アクセスに対する 保護を提供しません。攻撃者は同じ origin 内でコードを実行しているため、localStorage の内容を 読み取ることができるからです。さらに、localStorage は同期 API であり、操作が完了するまで 他の JavaScript をブロックします。

sessionStorage は localStorage と似ていますが、sessionStorage の 有効期間はブラウザタブの有効期間に結び付いている点が異なります。さらに、sessionStorage は 同じ origin のページを開いている複数のタブ間で共有されないため、sessionStorage 内の トークンの露出はわずかに減ります。

IndexedDB は localStorage と同様の永続ストレージ機構ですが、 複数のタブ間だけでなく browsing context と Service Workers の間でも共有されます。 さらに、IndexedDB は非同期 API であり、同期的な localStorage API よりも好まれます。

なお、これらのパターン間の主な違いはデータの露出ですが、 攻撃者がアプリケーションの実行環境で悪意あるコードを実行できる場合、 これらの選択肢のいずれもトークン流出を完全に緩和できないことに注意してください。

8.6. ブラウザストレージ API の ファイルシステム上の考慮事項

いずれの場合も、本稿執筆時点では、ブラウザストレージが 保存時に暗号化される保証はありません。この振る舞いは、ディスク上のファイルを読み取る能力を 持つ攻撃者にトークンを露出させる可能性があります。このような攻撃はブラウザベースの アプリケーションの範囲を大きく超える能力に依存していますが、この話題は現代の アプリケーションに対する重要な攻撃ベクトルを浮き彫りにします。高価値トークンや セッション cookie を取得するためにユーザーのマシンを巡回してブラウザプロファイルを探す マルウェアがますます多く作成されており、その結果、アカウント乗っ取り攻撃が発生します。

ブラウザベースのアプリケーションはこのような攻撃を緩和できませんが、 アプリケーションは暗号化を使用してデータの機密性を保証することにより、このような攻撃の 影響を緩和できます。[W3C.WebCryptoAPI] は、JavaScript コードが secret key を 生成する機構と、その鍵をエクスポート不可にするオプションを提供します。その後、 JavaScript アプリケーションはこの API を使用して、保存前にトークンを暗号化および 復号できます。しかし、[W3C.WebCryptoAPI] 仕様は、その鍵がブラウザコードにエクスポートできないことのみを保証し、オペレーティングシステムでの 鍵自体の基盤ストレージにはいかなる要件も課しません。そのため、エクスポート不可の鍵は、 基盤となるファイルシステムからの流出に対する保護手段として依存できません。

ファイルシステムからのトークン流出に対して保護するためには、 暗号鍵をリモートサーバーなど、ファイルシステム以外の場所に保存する必要があります。 これは純粋なブラウザベースのアプリに新たな複雑さを導入するため、本書の範囲外です。

9. セキュリティ上の考慮事項

9.1. トークンの権限の 低減

OAuth の世界における一般的なセキュリティベストプラクティスは、 アクセストークンに関連付けられる権限を最小化することです。このベストプラクティスは、 本仕様で説明するすべてのアーキテクチャに適用できます。具体的には、次の考慮事項が アクセストークンの権限を低減するのに役立ちます。

  • アクセストークンの有効期間を短くし、アクセストークンの 更新にはリフレッシュトークンに依存する

  • アクセストークンに関連付けられるスコープまたは権限を 減らす

  • [RFC8707] を使用して、アクセストークンを 単一のリソースに制限する

OpenID Connect が使用される場合、ID Token 内の claims を通じた 機微な情報の開示を避けることが重要です。認可サーバーは、クライアントによって使用されない ID token claims を含めるべきではありません(SHOULD NOT)。

9.2. 送信者制約付き トークン

本書全体で説明したように、送信者制約付きトークンの使用は、 ブラウザのみの OAuth クライアントのセキュリティ上の制限を解決しません。しかし、 トークン仲介バックエンド(Section 6.2)またはブラウザのみの OAuth クライアント (Section 6.3)によって提供される セキュリティレベルが対象のユースケースに十分である場合、送信者制約付きトークンを使用して、 アクセストークンとリフレッシュトークンの両方のセキュリティを強化できます。 ブラウザベースのアプリケーションから利用可能な方法で送信者制約付きトークンを実装する 1 つの方法は DPoP [RFC9449] です。

送信者制約付きトークンを使用する場合、OAuth クライアントは トークンを使用するために秘密鍵の保有を証明しなければならず、そのためトークン単体では 使用できません。送信者制約付きトークンが盗まれた場合、攻撃者はそのトークンを直接使用できず、 秘密鍵も盗む必要があります。本質的には、送信者制約付きトークンを使用することは、 トークンを安全に保存する課題を、秘密鍵を安全に保存する課題へ移すものだと言えます。 理想的には、アプリケーションは [W3C.WebCryptoAPI] で生成するような エクスポート不可の秘密鍵を使用すべきです。エクスポート不可の秘密鍵によって保護された 暗号化されていないトークンがブラウザストレージ内にある場合、XSS 攻撃は鍵を抽出できないため、 そのトークンは攻撃者によって使用できません。

アプリケーションがエクスポート不可の鍵を生成する API を 使用できない場合、アプリケーションは自身の実行コンテキストから秘密鍵を分離するための 対策を取るべきです。そのための技術は、Section 8 で 説明した安全なトークンストレージ機構の使用と似ています。

エクスポート不可の鍵は JavaScript コンテキスト内からの流出から 保護されますが、基盤となる秘密鍵がファイルシステムから流出することは依然として 潜在的な攻撃ベクトルです。本稿執筆時点では、[W3C.WebCryptoAPI] によって、 エクスポート不可の鍵が実際に Trusted Platform Module(TPM)によって保護されること、 またはディスク上に暗号化された形式で保存されることは保証されていません。攻撃者が、 たとえばマルウェアを通じてユーザーのマシンのファイルシステムにアクセスできる場合、 基盤となるファイルシステムからエクスポート不可の鍵が流出することは依然として可能かもしれません。 これは潜在的な攻撃ベクトルをセッション乗っ取り攻撃と実質的に同等にします。

9.3. 認可サーバー Mix-Up の緩和

認可サーバー mix-up 攻撃は、 少なくとも 2 つの認可サーバーをサポートするすべてのクライアントにとって重大な脅威です。 [RFC9700] の Section 4.4 は、mix-up 攻撃および上記の対策について追加の詳細を提供します。

9.4. Origins を使用した アプリケーションの分離

Web の多くのセキュリティ機構は、triple <scheme, hostname, port> として定義される origins に依存しています。 たとえば、ブラウザは異なる origins を持つ browsing contexts を自動的に分離し、 リソースを特定の origins に制限し、送信される cross-origin リクエストに CORS 制限を 適用します。

したがって、単一の origin に複数のアプリケーションを デプロイすることを避けることがベストプラクティスと見なされます。単一の origin に 1 つのアプリケーションのみをデプロイするアーキテクチャは、これらのブラウザ制限を活用して アプリケーションのセキュリティを高めることができます。さらに、アプリケーションごとに 単一の origin を持つことで、CORS、CSP などのセキュリティ対策を構成およびデプロイしやすくなります。

10. IANA に関する考慮事項

本書は IANA のいかなる措置も必要としません。

11. 参考文献

11.1. 規範的参考文献

[Fetch]
whatwg, "Fetch", , <https://fetch.spec.whatwg.org/>.
[I-D.ietf-httpbis-rfc6265bis]
Bingler, S., West, M., and J. Wilander, "Cookies: HTTP State Management Mechanism", Work in Progress, Internet-Draft, draft-ietf-httpbis-rfc6265bis-22, , <https://datatracker.ietf.org/doc/html/draft-ietf-httpbis-rfc6265bis-22>.
[RFC2119]
Bradner, S., "Key words for use in RFCs to Indicate Requirement Levels", BCP 14, RFC 2119, DOI 10.17487/RFC2119, , <https://www.rfc-editor.org/info/rfc2119>.
[RFC6749]
Hardt, D., Ed., "The OAuth 2.0 Authorization Framework", RFC 6749, DOI 10.17487/RFC6749, , <https://www.rfc-editor.org/info/rfc6749>.
[RFC6750]
Jones, M. and D. Hardt, "The OAuth 2.0 Authorization Framework: Bearer Token Usage", RFC 6750, DOI 10.17487/RFC6750, , <https://www.rfc-editor.org/info/rfc6750>.
[RFC7636]
Sakimura, N., Ed., Bradley, J., and N. Agarwal, "Proof Key for Code Exchange by OAuth Public Clients", RFC 7636, DOI 10.17487/RFC7636, , <https://www.rfc-editor.org/info/rfc7636>.
[RFC8174]
Leiba, B., "Ambiguity of Uppercase vs Lowercase in RFC 2119 Key Words", BCP 14, RFC 8174, DOI 10.17487/RFC8174, , <https://www.rfc-editor.org/info/rfc8174>.
[RFC8252]
Denniss, W. and J. Bradley, "OAuth 2.0 for Native Apps", BCP 212, RFC 8252, DOI 10.17487/RFC8252, , <https://www.rfc-editor.org/info/rfc8252>.
[RFC8707]
Campbell, B., Bradley, J., and H. Tschofenig, "Resource Indicators for OAuth 2.0", RFC 8707, DOI 10.17487/RFC8707, , <https://www.rfc-editor.org/info/rfc8707>.
[RFC9449]
Fett, D., Campbell, B., Bradley, J., Lodderstedt, T., Jones, M., and D. Waite, "OAuth 2.0 Demonstrating Proof of Possession (DPoP)", RFC 9449, DOI 10.17487/RFC9449, , <https://www.rfc-editor.org/info/rfc9449>.
[RFC9700]
Lodderstedt, T., Bradley, J., Labunets, A., and D. Fett, "Best Current Practice for OAuth 2.0 Security", BCP 240, RFC 9700, DOI 10.17487/RFC9700, , <https://www.rfc-editor.org/info/rfc9700>.
[W3C.service-workers]
"Service Workers", W3C CR service-workers, W3C service-workers, <https://www.w3.org/TR/service-workers/>.
[WebMessaging]
whatwg, "HTML - Cross-document messaging", , <https://html.spec.whatwg.org/#web-messaging>.

11.2. 参考情報文献

[CryptoKeyPair]
Contributors, M., "CryptoKeyPair", n.d., <https://developer.mozilla.org/en-US/docs/Web/API/CryptoKeyPair>.
[HTML]
whatwg, "HTML", , <https://html.spec.whatwg.org/>.
[OpenID]
Sakimura, N., Bradley, J., Jones, M., de Medeiros, B., and C. Mortimore, "OpenID Connect Core 1.0 incorporating errata set 2", , <https://openid.net/specs/openid-connect-core-1_0-errata2.html>.
[OWASPCheatSheet]
"OWASP Cheat Sheet", n.d., <https://cheatsheetseries.owasp.org/>.
[RFC6819]
Lodderstedt, T., Ed., McGloin, M., and P. Hunt, "OAuth 2.0 Threat Model and Security Considerations", RFC 6819, DOI 10.17487/RFC6819, , <https://www.rfc-editor.org/info/rfc6819>.
[SessionFixation]
"Session Fixation", n.d., <https://owasp.org/www-community/attacks/Session_fixation>.
[Site]
Contributors, M., "Site", n.d., <https://developer.mozilla.org/en-US/docs/Glossary/Site>.
[W3C.CSP3]
"Content Security Policy Level 3", W3C WD CSP3, W3C CSP3, <https://www.w3.org/TR/CSP3/>.
[W3C.IndexedDB]
"Indexed Database API", W3C REC IndexedDB, W3C IndexedDB, <https://www.w3.org/TR/IndexedDB/>.
[W3C.SRI]
"Subresource Integrity", W3C REC SRI, W3C SRI, <https://www.w3.org/TR/SRI/>.
[W3C.wasm-core-2]
"WebAssembly Core Specification", W3C CR wasm-core-2, W3C wasm-core-2, <https://www.w3.org/TR/wasm-core-2/>.
[W3C.WebCryptoAPI]
"Web Cryptography API", W3C REC WebCryptoAPI, W3C WebCryptoAPI, <https://www.w3.org/TR/WebCryptoAPI/>.
[WebStorage]
whatwg, "HTML Living Standard - Web Storage", , <https://html.spec.whatwg.org/#webstorage>.
[WebWorker]
whatwg, "HTML Living Standard - Web workers", , <https://html.spec.whatwg.org/#toc-workers>.

Appendix A. 文書履歴

[[ 最終仕様から削除される予定 ]]

-26

-25

-24

-23

-22

-21

-20

-19

-18

-17

-16

-15

-14

-13

-12

-11

-10

-09

-08

-07

-06

-05

-04

-03

-02

-01

Appendix B. 謝辞

著者らは、William Denniss と John Bradley の作業に感謝します。 彼らの native applications 向けの推奨事項は、browser-based applications の多くの ベストプラクティスに影響を与えました。また著者らは、Hannes Tschofenig と Torsten Lodderstedt、この BCP が最初に提案された Internet Identity Workshop 27 session の参加者、ならびに最終仕様を形作り構成することになったアイデア、 フィードバック、文言に貢献した次の個人にも感謝します。

Andy Barlow, Andy Newton, Annabelle Backman, Brian Campbell, Brock Allen, Christian Mainka, Damien Bowden, Daniel Fett, Deb Cooley, Elar Lang, Emmanuel Gautier, Eric Vyncke, Erik Kline, Eva Sarafianou, Filip Skokan, George Fletcher, Hannes Tschofenig, Janak Amarasena, John Bradley, Joseph Heenan, Justin Richer, Karl McGuinness, Karsten Meyer zu Selhausen, Leo Tohill, Louis Jannett, Marc Blanchet, Martin Thomson, Matthew Bocci, Mike Bishop, Mike Jones, Mohamed Boucadair, Orie Steele, Qin Wu, Rifaat Shekh-Yusef, Roman Danyliw, Sean Kelleher, Thomas Broyer, Thomas Fossati, Tomek Stojecki, Torsten Lodderstedt, Vittorio Bertocci, Watson Ladd, William Duncan, and Yannick Majoros.

著者の連絡先

Aaron Parecki
Okta
Philippe De Ryck
Pragmatic Web Security
David Waite
Ping Identity