8. Security Considerations (セキュリティに関する考慮事項)
8.1. Protecting the Authorization Code (認可コードの保護)
第7節で文書化されたリダイレクトURIオプションは、同じデバイス上のネイティブアプリまたはアプリ自身のウェブサイトのみが認可コード (Authorization Code) を受信できるという利点を共有しており、攻撃対象領域を制限します。しかし、同じデバイス上で実行されている別のネイティブアプリによるコード傍受が可能な場合があります。
リダイレクトURIにプライベート使用URIスキーム (Private-Use URI Scheme) を使用する場合の制限は、通常、複数のアプリが同じスキームを登録できることであり、どのアプリが認可コードを受信するかが不確定になります。PKCE [RFC7636] の第1節では、この制限がコード傍受攻撃の実行にどのように使用されるかを詳述しています。
ループバックIPベースのリダイレクトURIは、一部のオペレーティングシステムで同じループバックインターフェースにアクセスする他のアプリによる傍受の影響を受けやすい場合があります。
アプリが主張する "https" スキームリダイレクトは、URI権限の存在によりURI傍受の影響を受けにくくなっていますが、アプリは依然としてパブリッククライアント (Public Client) です。さらに、URIはセキュリティプロパティが不明なオペレーティングシステムのURIディスパッチハンドラーを使用して送信されます。
PKCE [RFC7636] プロトコルは、この攻撃を緩和するために特別に作成されました。これは、認可コードが傍受された場合に使用されないように保護するOAuth 2.0の所有証明拡張 (Proof-of-Possession Extension) です。保護を提供するために、この拡張ではクライアントが秘密検証子 (Secret Verifier) を生成します。初期認可リクエストでこの検証子のハッシュを渡し、認可コードを引き換える際にハッシュ化されていない検証子を提示しなければなりません (MUST)。認可コードを傍受したアプリは、この秘密を所有していないため、コードは役に立ちません。
第6節では、クライアントとサーバーの両方がパブリックネイティブアプリクライアントにPKCEを使用することを必須 (MUST) としています。認可サーバー (Authorization Server) は、PKCEを使用しないネイティブアプリからの認可リクエストを、PKCE [RFC7636] の第4.4.1節で定義されているエラーメッセージを返すことで拒否すべきです (SHOULD)。
8.2. OAuth Implicit Grant Authorization Flow (OAuth暗黙的許可認可フロー)
OAuth 2.0の暗黙的許可認可フロー (Implicit Grant Authorization Flow) (OAuth 2.0 [RFC6749] の第4.2節で定義) は、一般的にブラウザで認可リクエストを実行し、URIベースのアプリ間通信を介して認可レスポンスを受信する慣行と連携します。しかし、暗黙的フローはPKCE [RFC7636] によって保護できないため (第8.1節で必須)、ネイティブアプリでの暗黙的フローの使用は推奨されません (NOT RECOMMENDED)。
暗黙的フローを介して付与されたアクセストークン (Access Token) も、ユーザーの操作なしでは更新できないため、リフレッシュトークン (Refresh Token) を発行できる認可コード許可フロー (Authorization Code Grant Flow) の方が、アクセストークンの更新を必要とするネイティブアプリ認可にとってより実用的な選択肢となります。
8.3. Loopback Redirect Considerations (ループバックリダイレクトに関する考慮事項)
ループバックインターフェースリダイレクトURIは "http" スキーム (つまり、トランスポート層セキュリティ (TLS) なし) を使用します。HTTPリクエストがデバイスを離れることがないため、ループバックインターフェースリダイレクトURIではこれは許容されます。
クライアントは、認可リクエストを開始するときにのみネットワークポートを開き、レスポンスが返されたら閉じるべきです (should)。
クライアントは、他のネットワークアクターによる干渉を避けるために、ループバックネットワークインターフェースのみでリッスンすべきです (should)。
localhost を使用するリダイレクトURI (つまり、http://localhost:{port}/{path}) は、第7.3節で説明されているループバックIPリダイレクトと同様に機能しますが、localhost の使用は推奨されません (NOT RECOMMENDED)。localhost ではなくループバックIPリテラルでリダイレクトURIを指定することで、ループバックインターフェース以外のネットワークインターフェースで誤ってリッスンすることを回避できます。また、クライアント側のファイアウォールやユーザーのデバイス上の誤設定されたホスト名解決の影響も受けにくくなります。
8.4. Registration of Native App Clients (ネイティブアプリクライアントの登録)
動的クライアント登録 (Dynamic Client Registration) [RFC7591] のようなメカニズムを使用してインスタンスごとの秘密をプロビジョニングする場合を除き、ネイティブアプリはOAuth 2.0 [RFC6749] の第2.1節で定義されているパブリッククライアントとして分類されます。それらは認可サーバーにそのように登録されなければなりません (MUST)。認可サーバーは、リクエストを適切に識別して処理するために、クライアント登録の詳細にクライアントタイプを記録しなければなりません (MUST)。
認可サーバーは、クライアントが完全なリダイレクトURI (パスコンポーネントを含む) を登録することを必須 (MUST) とし、登録されたものと完全に一致しないリダイレクトURIを指定する認可リクエストを拒否しなければなりません (MUST)。例外はループバックリダイレクトで、ポートURIコンポーネントを除いて完全一致が必要です。
プライベート使用URIスキームベースのリダイレクトの場合、認可サーバーは、クライアントが逆ドメイン名ベースのスキームを使用するという第7.1節の要件を強制すべきです (SHOULD)。少なくとも、ピリオド文字 (".") を含まないプライベート使用URIスキームは拒否されるべきです (SHOULD)。
衝突耐性プロパティに加えて、アプリの制御下にあるドメイン名に基づくURIスキームを要求することは、2つのアプリが同じプライベート使用URIスキームを主張する紛争の場合 (一方のアプリが悪意を持って行動している場合) に所有権を証明するのに役立ちます。たとえば、2つのアプリが "com.example.app" を主張した場合、"example.com" の所有者はアプリストア運営者に偽造アプリの削除を請願できます。一般的なURIスキームが使用された場合、そのような請願は証明が困難です。
認可サーバーは、アプリパッケージまたはバンドル名、またはそのような機能をサポートするオペレーティングシステム上で呼び出し元アプリのIDを検証するのに役立つ可能性のある他の情報など、他のプラットフォーム固有の情報の含有を要求してもよいです (MAY)。
8.5. Client Authentication (クライアント認証)
複数のユーザーに配布されるアプリの一部として静的に含まれる秘密は、1人のユーザーがそのコピーを検査して共有秘密を知る可能性があるため、機密秘密として扱うべきではありません。この理由、および [RFC6819] の第5.3.1節で述べられている理由により、認可サーバーがパブリックネイティブアプリクライアントの共有秘密を使用したクライアント認証を要求することは推奨されません (NOT RECOMMENDED)。これは、"client_id" リクエストパラメータによってすでに提供されているクライアント識別以上の価値をほとんど提供しないためです。
それでもネイティブアプリクライアントに静的に含まれる共有秘密を要求する認可サーバーは、クライアントをパブリッククライアントとして扱わなければならず (MUST) (OAuth 2.0 [RFC6749] の第2.1節で定義)、秘密をクライアントのIDの証明として受け入れてはなりません。追加の対策がない場合、そのようなクライアントはクライアントなりすまし (第8.6節を参照) の対象となります。
8.6. Client Impersonation (クライアントなりすまし)
OAuth 2.0 [RFC6749] の第10.2節で述べられているように、認可サーバーは、クライアントのIDが保証できる場合を除き、ユーザーの同意または操作なしに認可リクエストを自動的に処理すべきではありません (SHOULD NOT)。これには、ユーザーが以前に特定のクライアントIDの認可リクエストを承認した場合が含まれます。クライアントのIDが証明できない限り、リクエストは以前のリクエストが承認されていないかのように処理されるべきです (SHOULD)。
主張された "https" スキームリダイレクトなどの対策は、認可サーバーによってID証明として受け入れられてもよいです (MAY)。一部のオペレーティングシステムは、適切な場合に受け入れられてもよい (MAY) 代替のプラットフォーム固有のID機能を提供する場合があります。
8.7. Fake External User-Agents (偽の外部ユーザーエージェント)
認可リクエストを開始するネイティブアプリは、ユーザーインターフェースを大幅に制御でき、偽の外部ユーザーエージェント、つまり外部ユーザーエージェントのように見せかけた埋め込みユーザーエージェント (Embedded User-Agent) を潜在的に提示できます。
すべての善良なアクターが外部ユーザーエージェントを使用している場合の利点は、セキュリティ専門家が悪意のあるアクターを検出できることです。外部ユーザーエージェントを偽装している者は明らかに悪意があるためです。一方、善良なアクターと悪意のあるアクターの両方が埋め込みユーザーエージェントを使用している場合、悪意のあるアクターは何も偽装する必要がなく、検出が困難になります。悪意のあるアプリが検出されると、この知識を使用してマルウェアスキャンソフトウェアでアプリの署名をブラックリストに登録したり、(アプリストアによって配布されるアプリの場合) 削除アクションを実行したり、悪意のあるアプリの影響と拡散を減らすための他の手順を実行したりすることが可能になる場合があります。
認可サーバーは、真の外部ユーザーエージェントのみが利用できる認証要素を要求することにより、偽の外部ユーザーエージェントから直接保護することもできます。
アプリ内ブラウザタブ (In-App Browser Tab) を使用する際のセキュリティに特に懸念があるユーザーは、アプリ内ブラウザタブからフルブラウザでリクエストを開き、そこで認可を完了するという追加の手順を踏むこともできます。アプリ内ブラウザタブパターンのほとんどの実装はそのような機能を提供しているためです。
8.8. Malicious External User-Agents (悪意のある外部ユーザーエージェント)
悪意のあるアプリがオペレーティングシステムで "https" スキームURIのデフォルトハンドラーとして自身を構成できる場合、デフォルトブラウザを使用する認可リクエストを傍受し、ユーザーをフィッシングするなどの悪意のある目的でこの信頼の地位を悪用できます。
この攻撃はOAuthに限定されません。このように構成された悪意のあるアプリは、ネイティブアプリによるOAuth使用を超えて、ユーザーに対する一般的かつ継続的なリスクを提示します。多くのオペレーティングシステムは、"http" および "https" スキームURIのデフォルトハンドラーを変更するために明示的なユーザーアクションを要求することで、この問題を緩和しています。
8.9. Cross-App Request Forgery Protections (クロスアプリリクエストフォージェリ保護)
[RFC6819] の第5.3.5節では、CSRF (クロスサイトリクエストフォージェリ) 攻撃を防ぐために、"state" パラメータを使用してクライアントリクエストとレスポンスをリンクすることを推奨しています。
アプリ間URI通信チャネルを介したCSRFスタイルの攻撃 (いわゆる「クロスアプリリクエストフォージェリ」) を緩和するために、ネイティブアプリが認可リクエストの "state" パラメータに高エントロピーの安全なランダム数を含め、保留中の発信認可リクエストに一致する状態値のない着信認可レスポンスを拒否することが同様に推奨されます (RECOMMENDED)。
8.10. Authorization Server Mix-Up Mitigation (認可サーバー混同緩和)
同じアプリが使用する別の認可サーバーを攻撃する侵害されたまたは悪意のある認可サーバーから保護するために、アプリが使用する各認可サーバーに一意のリダイレクトURIを使用すること (たとえば、パスコンポーネントを変更することによって)、および受信したリダイレクトURIが発信認可リクエストのリダイレクトURIと一致しない場合に認可レスポンスを拒否することが必須 (REQUIRED) です。
ネイティブアプリは、認可リクエストで使用されたリダイレクトURIを認可セッションデータ (つまり、"state" およびその他の関連データとともに) と一緒に保存しなければならず (MUST)、認可レスポンスが受信されたURIがそれと完全に一致することを検証しなければなりません (MUST)。
第8.4節の要件、特に認可サーバーが登録されたものと一致しないURIを持つリクエストを拒否するという要件も、そのような攻撃を防ぐために必要です。
8.11. Non-Browser External User-Agents (非ブラウザ外部ユーザーエージェント)
この最良現行慣行は、特定のタイプの外部ユーザーエージェント、すなわちユーザーのブラウザを推奨しています。他の外部ユーザーエージェントパターンも、安全で使いやすいOAuthにとって実行可能である可能性があります。本文書は、それらのパターンについてコメントしません。
8.12. Embedded User-Agents (埋め込みユーザーエージェント)
OAuth 2.0 [RFC6749] の第9節では、ネイティブアプリが認可エンドポイントと対話するための2つのアプローチを文書化しています。この最良現行慣行は、ネイティブアプリが認可リクエストを実行するために埋め込みユーザーエージェントを使用してはならない (MUST NOT) ことを要求し、認可エンドポイントが埋め込みユーザーエージェントでの認可リクエストを検出してブロックする手順を実行してもよい (MAY) ことを許可しています。これらの要件のセキュリティ考慮事項については、ここで詳述します。
埋め込みユーザーエージェントは、ネイティブアプリを認可するための代替方法です。これらの埋め込みユーザーエージェントは、定義上、認可サーバーに対する第三者による使用には安全ではありません。埋め込みユーザーエージェントをホストするアプリは、アプリに意図されたOAuth認可許可だけでなく、ユーザーの完全な認証資格情報にアクセスできるためです。
埋め込みユーザーエージェントの典型的なウェブビューベースの実装では、ホストアプリケーションはログインフォームに入力されたすべてのキーストロークを記録してユーザー名とパスワードをキャプチャし、フォームを自動的に送信してユーザーの同意をバイパスし、セッションクッキーをコピーしてそれらを使用してユーザーとして認証されたアクションを実行できます。
認可サーバーと同じ当事者に属する信頼できるアプリによって使用される場合でも、埋め込みユーザーエージェントは、必要以上に強力な資格情報にアクセスできることにより、最小特権の原則に違反し、攻撃対象領域を潜在的に増加させます。
ブラウザが持つ通常のアドレスバーや可視的な証明書検証機能なしに埋め込みユーザーエージェントに資格情報を入力するようユーザーに奨励することは、ユーザーが正当なサイトにサインインしているかどうかを知ることを不可能にします。そうであっても、最初にサイトを検証せずに資格情報を入力してもよいとユーザーに教え込むことになります。
セキュリティ上の懸念とは別に、埋め込みユーザーエージェントは他のアプリやブラウザと認証状態を共有しないため、ユーザーはすべての認可リクエストでログインする必要があり、これはしばしば劣ったユーザーエクスペリエンスと見なされます。