メインコンテンツまでスキップ

1. Introduction (はじめに)

OAuth 2.0 [RFC6749] のパブリッククライアント (Public Clients) は、認可コード傍受攻撃 (Authorization Code Interception Attack) に対して脆弱です。

この攻撃では、攻撃者は、トランスポート層セキュリティ (Transport Layer Security, TLS) で保護されていない通信経路(例えば、クライアントのオペレーティングシステム内のアプリケーション間通信)で、認可エンドポイント (Authorization Endpoint) から返される認可コード (Authorization Code) を傍受します。

攻撃者が認可コードへのアクセスを得ると、それを使用してアクセストークン (Access Token) を取得することができます。

図1は、この攻撃をグラフィカルに示しています。ステップ(1)では、スマートフォンなどのエンドデバイス上で実行されているネイティブアプリケーションが、ブラウザ/オペレーティングシステムを介してOAuth 2.0認可リクエストを発行します。この場合、リダイレクションエンドポイントURI (Redirection Endpoint URI) は通常、カスタムURIスキーム (Custom URI Scheme) を使用します。ステップ(1)は、傍受できないセキュアなAPIを通じて行われますが、高度な攻撃シナリオでは観察される可能性があります。次に、リクエストはステップ(2)でOAuth 2.0認可サーバーに転送されます。OAuthはTLSの使用を要求するため、この通信はTLSで保護されており、傍受することはできません。認可サーバーはステップ(3)で認可コードを返します。ステップ(4)では、認可コードは、ステップ(1)で提供されたリダイレクションエンドポイントURIを介してリクエスタに返されます。

悪意のあるアプリケーションが、正規のOAuth 2.0アプリケーションに加えて、カスタムスキームのハンドラとして自身を登録することが可能であることに注意してください。これを行うと、悪意のあるアプリケーションはステップ(4)で認可コードを傍受できるようになります。これにより、攻撃者はステップ(5)とステップ(6)でそれぞれアクセストークンを要求し取得することができます。

+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+
| End Device (e.g., Smartphone) |
| |
| +-------------+ +----------+ | (6) Access Token +----------+
| |Legitimate | | Malicious|<--------------------| |
| |OAuth 2.0 App| | App |-------------------->| |
| +-------------+ +----------+ | (5) Authorization | |
| | ^ ^ | Grant | |
| | \ | | | |
| | \ (4) | | | |
| (1) | \ Authz| | | |
| Authz| \ Code | | | Authz |
| Request| \ | | | Server |
| | \ | | | |
| | \ | | | |
| v \ | | | |
| +----------------------------+ | | |
| | | | (3) Authz Code | |
| | Operating System/ |<--------------------| |
| | Browser |-------------------->| |
| | | | (2) Authz Request | |
| +----------------------------+ | +----------+
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+

図1: 認可コード傍受攻撃

この攻撃が機能するには、以下の前提条件が満たされる必要があります:

  1. 攻撃者がクライアントデバイス上に悪意のあるアプリケーションを登録し、別のアプリケーションでも使用されているカスタムURIスキームを登録することに成功する。オペレーティングシステムは、複数のアプリケーションが同じカスタムURIスキームを登録することを許可しなければならない。

  2. OAuth 2.0認可コード許可 (Authorization Code Grant) が使用される。

  3. 攻撃者がOAuth 2.0 [RFC6749]のclient_idclient_secret(プロビジョニングされている場合)にアクセスできる。すべてのOAuth 2.0ネイティブアプリケーションクライアントインスタンスは同じclient_idを使用する。クライアントバイナリアプリケーション内にプロビジョニングされた秘密は、機密であるとは見なすことができない。

  4. 以下のいずれかの条件が満たされる:

    4a. 攻撃者(インストールされたアプリケーションを介して)は、認可エンドポイントからの応答のみを観察することができる。code_challenge_methodの値がplainの場合、この攻撃のみが軽減される。

    4b. より高度な攻撃シナリオでは、攻撃者は認可エンドポイントへのリクエスト(応答に加えて)を観察することができる。ただし、攻撃者は中間者 (Man-in-the-Middle) として振る舞うことはできない。これは、OSで漏洩したHTTPログ情報によって引き起こされた。これを軽減するには、code_challenge_methodの値をS256または暗号的に安全なcode_challenge_method拡張で定義された値に設定する必要がある (しなければならない)。

これは長い前提条件のリストですが、説明された攻撃は実際の環境で観察されており、OAuth 2.0のデプロイメントで考慮されなければなりません。OAuth 2.0脅威モデル ([RFC6819]のセクション4.4.1) は軽減技術を説明していますが、残念ながら、それらは各クライアントインスタンスの秘密または各クライアントインスタンスのリダイレクトURIに依存しているため、適用できません。

この攻撃を軽減するために、この拡張は「コード検証子 (Code Verifier)」と呼ばれる動的に作成された暗号的にランダムな鍵を利用します。各認可リクエストに対して一意のコード検証子が作成され、その変換された値(「コードチャレンジ (Code Challenge)」と呼ばれる)が認可コードを取得するために認可サーバーに送信されます。次に、取得された認可コードは「コード検証子」とともにトークンエンドポイントに送信され、サーバーはそれを以前に受信したリクエストコードと比較して、クライアントが「コード検証子」の所有証明 (Proof of Possession) を実行できるようにします。これは軽減策として機能します。攻撃者はこの一回限りの鍵を知らないため、TLS経由で送信され傍受できないためです。

1.1 Protocol Flow (プロトコルフロー)

                                             +-------------------+
| Authz Server |
+--------+ | +---------------+ |
| |--(A)- Authorization Request ---->| | |
| | + t(code_verifier), t_m | | Authorization | |
| | | | Endpoint | |
| |<-(B)---- Authorization Code -----| | |
| | | +---------------+ |
| Client | | |
| | | +---------------+ |
| |--(C)-- Access Token Request ---->| | |
| | + code_verifier | | Token | |
| | | | Endpoint | |
| |<-(D)------ Access Token ---------| | |
+--------+ | +---------------+ |
+-------------------+

図2: 抽象的なプロトコルフロー

本仕様書は、図2の抽象形式で示されるように、OAuth 2.0認可およびアクセストークンリクエストに追加パラメータを追加します。

A. クライアントは、「code_verifier」という名前の秘密を作成して記録し、その変換バージョンt(code_verifier)(「code_challenge」と呼ばれる)を導出します。これは、変換方法t_mとともにOAuth 2.0認可リクエストで送信されます。

B. 認可エンドポイントは通常どおり応答しますが、t(code_verifier)と変換方法を記録します。

C. 次に、クライアントは通常どおりアクセストークンリクエストで認可コードを送信しますが、(A)で生成された「code_verifier」秘密を含めます。

D. 認可サーバーは「code_verifier」を変換し、それを(B)のt(code_verifier)と比較します。それらが等しくない場合、アクセスは拒否されます。

(B)で認可コードを傍受する攻撃者は、「code_verifier」秘密を所有していないため、それをアクセストークンと引き換えることができません。