OAuth 2.0 for Native Apps

Last updated 5 months ago

RFC 8252 - OAuth 2.0 for Native Apps の和訳例

はじめに

本和訳は個人で作成・公開している、あくまで例であり、意訳や間違いが含まれておりますことをご了承ください。

コメントや誤り指摘等は、Twitter @sami_mkw_ までいただけますと幸いですm(_ _)m

OAuth 2.0 for Native Apps

https://tools.ietf.org/html/rfc8252

要旨 (Abstract)

ネイティブアプリからの OAuth 2.0 認可リクエストは,外部ユーザーエージェントを介してのみ行うことができ,主にユーザのブラウザが使用される.本仕様では,ネイティブアプリと認可サーバがセキュリティと使いやすさを両立させたベストプラクティスな実装はどのようにすれば可能であるかについて詳しく説明している.

Status of This Memo

This memo documents an Internet Best Current Practice.

This document is a product of the Internet Engineering Task Force (IETF). It represents the consensus of the IETF community. It has received public review and has been approved for publication by the Internet Engineering Steering Group (IESG). Further information on BCPs is available in Section 2 of RFC 7841.

Information about the current status of this document, any errata, and how to provide feedback on it may be obtained at https://www.rfc-editor.org/info/rfc8252.

Copyright (c) 2017 IETF Trust and the persons identified as the document authors. All rights reserved.

This document is subject to BCP 78 and the IETF Trust's Legal Provisions Relating to IETF Documents (https://trustee.ietf.org/license-info) in effect on the date of publication of this document. Please review these documents carefully, as they describe your rights and restrictions with respect to this document. Code Components extracted from this document must include Simplified BSD License text as described in Section 4.e of the Trust Legal Provisions and are provided without warranty as described in the Simplified BSD License.

1. Introduction

OAuth 2.0 認可フレームワーク[RFC 6749] の 第9章には,ネイティブアプリが認可エンドポイントとインタラクションをとるためのアプローチが2つ記されている.組込ユーザエージェントを使用する方法と外部ユーザエージェントを使用する方法である.

現在のベストプラクティスでは,ネイティブアプリがOAuthにて使用するブラウザのような外部ユーザエージェントのみが必要となる.このような外部ユーザエージェントを使ってネイティブアプリがどのように認可フローを実装することができるのか,また,認可サーバがこのようなフローをどのようにサポートするかについて,本仕様に記述している.

本プラクティスは,これを実装するオープンソースライブラリ [AppAuth] からとって "AppAuthパターン" としても知られている.

2. Notational Conventions

The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in BCP 14 [RFC2119] [RFC8174] when, and only when, they appear in all capitals, as shown here.

3. 用語

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

ネイティブアプリ (native app)

  • ブラウザでのみで動作するウェブアプリとは異なり,ユーザ自身のデバイスにインストールするアプリケーション. 本仕様では,ウェブベースの技術を使用して実装されているもののネイティブアプリとして配布されているいわゆる「ハイブリッドアプリ ( hybrid apps)」は,ネイティブアプリと同等と見なしている.

アプリ (app)

  • 特にことわりのない限り,ネイティブアプリ (native app) を指す.

OAuth

  • OAuth 2.0 認可フレームワーク[RFC6749] で定義されている認可プロトコル.

外部ユーザエージェント (external user-agen)

  • Cookieのストレージにアクセスできなかったりページのコンテンツを確認したり変更したりすることができないアプリなど.ネイティブアプリとは別のエンティティまたはセキュリティドメインである認可リクエストを処理することができるユーザエージェント.

組込ユーザエージェント (embedded user-agent)

  • 認可リクエストを生成するネイティブアプリによってホストされ,アプリの一部を形成する,あるいはアプリがアクセスすることのできるCookieストレージにアクセス可能等同じセキュリティドメインを共有しており,ページのコンテンツを確認したり変更したりすることができるアプリなど.

ブラウザ

  • "http" や "https" のURIスキームを処理する際に OSが立ち上げるデフォルトのアプリ.

アプリ内ブラウザタブ (in-app browser tab)

  • ブラウザの完全なセキュリティプロパティと認証状態を保持する, ホストアプリ内に表示されるブラウザのインスタンス.プラットフォームによって呼び方が異なる.いくつか詳細を付録Bに記しているので参照のこと.

web-view

  • アプリに埋め込まれたWebブラウザのUIコンポーネントで,アプリ制御の下Webページをレンダリングするもの.

アプリ間通信 (inter-app communication)

  • デバイス上の2つのアプリ間の通信.

登録済 "https"スキームURI (claimed "https" scheme URI)

  • 一部のプラットフォームでは,ドメイン名の所有権を証明することで,"https"スキームURIでアプリを開くことができる.このようなURIはブラウザの代わりにアプリで開かれる.

プライベートURIスキーム (private-use URI scheme)

  • 本書では,アプリによって定義され,OSに登録されているURIスキームの意で使用([RFC7595]の3.8節の要件に従う).このようなスキームへのURIリクエストを処理するため,登録されたアプリが起動される.

逆ドメイン名表記 (reverse domain name notation)

  • ドメイン名システムに基づく命名規則だが,ドメインコンポーネントが逆転した命名規則.例えば,"app.example.com" は "com.example.app" となる.

4. Overview

ネイティブアプリでユーザを認可するには,組込ユーザエージェント( web-viewで実装されたものなど)ではなく,外部ユーザエージェント(通常はブラウザ)でOAuth認可リクエストを実行するのが現在のベストプラクティスである.

以前は,組込ユーザエージェント(通常はウェブビューで実装されたもの)を使ってネイティブアプリからOAuth認可リクエストを送付するのが一般的であった.しかし,このアプローチには多くの欠点が存在する.ホストアプリがユーザのクレデンシャルとCookie情報をコピーできるだけでなく,ユーザは各アプリケーションのスクラッチから必要に応じて認証を行わなければならない.OAuthに組込ユーザエージェントを使用する際の欠点についての詳細な分析は,8.12節参照.

ネイティブアプリの認可リクエストにブラウザを使用するのはより安全で,ユーザの認証状態を活用できる.ブラウザの既存認証セッションを使用できるということは,新しいアプリを使用するたびに認可サーバーで認証する必要がなくなり,シングル・サインオンが可能になる.( 認可サーバのポリシーによって認証が必要とされる場合を除く)

OAuth 認可リクエスト/レスポンスはすでにURIで定義されており,これには アプリ間通信に使えるURIも含まれている.よって,ネイティブアプリとブラウザ間で認可フローをサポートすることも,OAuthプロトコル自体を変更することなく実現することができる.すべてのクライアントが Confidential Web クライアントであると想定して実装されている一部の OAuthサーバにおいては,public ネイティブアプリクライアントという存在ならびに本仕様をサポートするために使用されるリダイレクトURIの種類を追加する必要がある.

4.1. ブラウザを使ったネイティブアプリの認可フロー

図1: 外部ユーザエージェントによるネイティブアプリの認可

図1は,ユーザ認可におけるネイティブアプリとブラウザ間のインタラクションを示す.

(1) クライアントアプリは,認可リクエストでブラウザタブを開く.

(2) 認可エンドポイントは,認可リクエストを受け,ユーザを認証し,認可を取得する. ユーザ認証は,他の認証システムへの委譲も可.

(3) 認可サーバは、リダイレクトURIに認可コードを発行する.

(4) クライアントは,リダイレクトURIから認可コードを受取る.

(5) クライアントアプリはトークンエンドポイントに認可コードを提示する.

(6) トークンエンドポイントは,認可コードを検証し,要求されたトークンを発行する.

5. アプリケーション間URI通信の使用

Web上のOAuth 2.0 [RFC 6749]が,認可リクエストが送信されることから始まり要求元のWebサイトに認可レスポンスが返るのと同様,ネイティブアプリがURIを使ってデバイスのブラウザで認可リクエストを送信し,要求元ネイティブアプリにレスポンスが返却される.

Web上のOAuthと同じ方法を採用することで,Webのコンテキストで得られていた,シングルサインオンの利便性や個別の認証コンテキストでのセキュリティといった利点をネイティブアプリでも同様に活用できる.同じ方法の再利用は実装の複雑さを軽減し, 特定のプラットフォーム特有ではない標準ベースのWebフローに依存することで相互運用性も向上させる.

本仕様に準拠するため,ネイティブアプリはOAuth 認可リクエストの実行に外部ユーザエージェントを使用しなければならない (MUST).これは、ブラウザ(詳細は6章参照)で認可リクエストを開き,認可レスポンスを元のネイティブアプリに戻すのは,リダイレクトURIを使用することによって実現される( 7章で定義).

6. Appネイティブアプリから認可リクエスト開始

ユーザ認可が必要なネイティブアプリでは,ネイティブアプリで受信可能なリダイレクトURIを使用し,認可リクエストURIを生成する.OAuth 2.0 [RFC6749] 4.1節 に記載の認可コードグラントタイプのシナリオを利用する.

ネイティブアプリで利用する認可リクエストのリダイレクトURIは,ウェブベースの認可リクエストのリダイレクトURIと同ような動きをする.認可レスポンスをOAuthクライアントサーバに返すのではなく,リダイレクトURI経由でアプリを起動しレスポンスを返す.さまざまなプラットフォームのネイティブアプリにレスポンスを返すリダイレクトURIの詳細については,第7章に記している.アプリがURIを受取り,そのパラメータを確認できるようなリダイレクトURIであれば利用可能である.

Public ネイティブアプリクライアントは,OAuthの拡張仕様であるPKCE (Proof Key for Code Exchange [RFC7636]) を実装しなければならない (MUST).また,認可サーバはそのようなクライアントのためにPKCEをサポートしなければならない (MUST).詳細の理由は8.1節を参照.

アプリは,認可リクエストURIを生成した後,プラットフォーム固有のAPIを使用して外部ユーザエージェントを開く.通常,使用される外部ユーザエージェントはデフォルトのブラウザ,つまりシステム上 "http" と "https" スキームURIを処理するように設定されたアプリである.しかし,これとは別のブラウザ選択基準や他のカテゴリの外部ユーザエージェントが使用される場合もある(MAY).

本仕様では,推奨する(RECOMMENDED)ネイティブアプリの外部ユーザエージェントとしてブラウザに焦点を当てている.ユーザ認可のために特別に設計され,ブラウザのように認可リクエストとレスポンスを処理できる外部ユーザエージェントも使用することができる(MAY).認可サーバーによって提供されるネイティブアプリなど他の外部ユーザエージェントについても,同様にリダイレクトURIを活用するなどで本仕様の基準を満たすが,それについては本仕様の範囲外である.

「アプリ内ブラウザタブ」として知られるブラウザ機能がサポートされているプラットフォームも存在する.これを使うと,アプリを切り替えることなくアプリ内にブラウザのタブを表示できる上,認証状態やセキュリティのコンテキストなども共有することができる.サポートされているプラ​​ットフォームにおいては,ユーザビリティ上の理由から,認可リクエストに「アプリ内ブラウザタブ」の使用を推奨する(RECOMMENDED).

7. ネイティブアプリで認可レスポンスを受取る

ネイティブアプリがブラウザから認可レスポンスを受取る際に使用できるリダイレクトURIオプションはいくつか存在するが,プラットフォームによって可用性とユーザエクスペリエンスが異なる.

本仕様を完全にサポートするためには,認可サーバーは少なくとも以下の節で説明する3種類のリダイレクトURIオプションをネイティブアプリに提供する必要がある(MUST). ネイティブアプリは,プラットフォーム固有実装の詳細を考慮して,最適なオプションを使用してよい(MAY).

7.1. プライベートURIスキーム

多くのモバイル/デスクトップのプラットフォームでは,アプリに "com.example.app"のようなプライベートURIスキーム(「カスタムURLスキーム」と呼ばれる場合もある)を登録させることで,URIを介したアプリ間通信をサポートしている.ブラウザや別のアプリがプライベートURIスキームを読込もううとすると,そのURIを登録したアプリが起動してリクエストを処理する.

標準の認可リクエストではブラウザを起動するが,プライベートURIスキームを使用してOAuth 2.0 認可リクエストを実行するには,リダイレクトURIとしてOSに登録したプライベートURIスキームを使う.

アプリに関連付けるURIスキームを選択する際には,アプリの管理下にあるドメイン名に基づくURIスキームを使用しなければならない(MUST).また,[RFC7595] 3.8節で推奨されているように逆ドメイン名表記を使用しなければならない(MUST).

例えば,ドメイン名「app.example.com」を制御するアプリは,スキームとして「com.example.app」を使用することができる.一部の認可サーバーは,ドメイン名に基づいたクライアント識別子,例えば "client1234.usercontent.example.net" を発行している.これも,同様に逆ドメイン名表記のスキームとして使用できる.しかしながら,"myapp" のようなスキームは,ドメイン名に基づいていないため,本要件を満たさない.

同じ発行元の複数のアプリ存在する場合は,各スキームが同一発行元内で一意になるよう注意する必要がある.逆ドメイン名表記に基づくアプリ識別子を使用するプラットフォームにおいては,これらの識別子をOAuth用のプライベートURIスキームとして再利用することで問題を回避できる.

[RFC3986] 3.2節 の要件に従うと,プライベートURIスキームの命名権限がないため,スキームの後にはスラッシュ("/")が1つしか表示されない.プライベートURIスキームを利用したリダイレクトURIの完全な例は次のとおり.

com.example.app:/oauth2redirect/example-provider

認可サーバはリクエストの処理を完了すると,通常どおりクライアントのリダイレクトURIに返却する.リダイレクトURIにはプライベートURIスキームが使用されているため,OSはネイティブアプリを起動しURIを起動パラメータとして渡す.最後に,ネイティブアプリは認可レスポンスを受け,通常通りの処理を行う.

7.2. 登録済 "https"スキームURI

いくつかのOSでは,アプリが制御するドメインの範囲内で,登録済 "https"スキーム[RFC7230]URIを利用することができる.ブラウザで登録済みのURIへの要求を処理する場合,ブラウザにページを読込むのではなく,起動パラメータとして提供されたURIを使用してネイティブアプリが起動する.

そのようなURIは,ネイティブアプリにてリダイレクトURIとして使用できる.認可サーバからは,通常のWebベースのクライアントのリダイレクトURIと区別することができない.下記に例を記す.

https://app.example.com/oauth2redirect/example-provider

リダイレクトURIだけでは,Public ネイティブアプリクライアントと Confidential ウェブクライアントを区別することができない.このため,8.4節に記したように,サーバはクライアント登録時にクライアントタイプを記録しておき,クライアントタイプに応じた動きをできるようにしておく必要がある(REQUIRED).

登録済"https"スキームURIは,他の方法と比較して、ネイティブアプリのアイデンティティがOSによって認可サーバに保証されるという点でいくつか利点がある.このため,ネイティブアプリは,可能な限り,他の方法よりも本手段を使用するべきである(SHOULD).

7.3. ループバック

通常はデスクトップOSにて,ネイティブアプリは,特別な権限を必要とせずにループバック上のポートを開くことができ,ループバックを使用して OAuth リダイレクトを受取るることができる.。

ループバックのリダイレクトURIは "http" スキームを使用し,ループバックIPと,クライアントが開いているポートで構築される.

 つまり,IPv4では "http://127.0.0.1:{port}/{path}" ,IPv6では "http://[::1]:{port}/{path}" となる.ランダムに割当てられたポートを利用するIPv4ループバックのリダイレクトURLの例は下記.

 http://127.0.0.1:51004/oauth2redirect/example-provider

ランダムに割り当てられたポート を利用するIPv6ループバック のリダイレクトURLの例は下記.

 http://[::1]:61023/oauth2redirect/example-provider

認可サーバは,ループバックのリダイレクトURIでのリクエストに時にポートを指定できるようにしなければならない(MUST).リクエスト時にOSから一時的なポート番号を付与されるクライアントに対応するため,いかなるポート番号にも対応しなければならない(MUST).

クライアントは,デバイスが特定のバージョンのインターネットプロトコルをサポートしていると想定してはならない(SHOULD NOT).クライアントがIPv4とIPv6の両方を使用してループバックにバインドしようと試み,使用可能なものを採用することを推奨する(RECOMMENDED).

8. セキュリティに関する考察

8.1. 認可コードの保護

第7章で説明されているリダイレクトURIオプションは,同じデバイス上のネイティブアプリまたはアプリ自身のWebサイトだけが認可コードを受け取ることができるという利点を共有し,攻撃を制限する.しかし,同じデバイス上で実行されている別のネイティブアプリによる認可コード横取り攻撃が発生し得る.

リダイレクトURIにプライベートURIスキームを使用する場合は,複数のアプリが同じスキームを登録することができてしまうため,どのアプリが認可ードを受け取るのか不確定である.PKCE [RFC7636] 1章に,認可コード横取り攻撃を制限する方法の詳細が記載されている.

ループバックのリダイレクトURIは一部のOSにおいて,同じループバックにアクセスする他のアプリの傍受を受ける可能性がある.

登録済"https"スキームの利用は,URI権限の存在により横取り攻撃を受けにくいものの,アプリはPublic クライアントである.さらに、不明なセキュリティプロパティを持つOSのURIディスパッチハンドラを使ってURIが送信されることになる.

この攻撃を軽減するためにPKCE [RFC7636]プロトコルが特別に作成された.これは,OAuth 2.0の proof-of-posessionの拡張仕様であり,横取された認可コードが使用されないよう保護する.そのため,この拡張仕様はクライアントに秘密のverifierを生成させる.最初の認可リクエストにおいてこのverifierのハッシュを渡し,認可コードを補うものとしてverifierを利用する.認可コードを横取したアプリはこのverifierを所有していないため,認可コードは使い物にならなくなる.

第6章では,クライアントとサーバの両方がPublicネイティブアプリのクライアントにPKCEを使用することを要求している.認可サーバは,PKCE [RFC7636]の4.4.1項で定義されているエラーメッセージを返すことで,PKCEを使用しないネイティブアプリからの認可リクエストを拒否すべきである.

8.2. Implicitフロー

OAuth 2.0のImplicitフローは(OAuth 2.0 [RFC6749] 4.2節で定義されている),ブラウザで認可リクエストを実行し,URIベースのアプリ間通信を介して認可レスポンスを受け取るというフローで一般的に機能する.しかしImplicitフローはPKCE [RFC7636](8.1節で必要)によって保護することができないため,ネイティブアプリでのImplicitフローの使用は推奨されない(NOT RECOMMENDED).

Implicitフローを介して得られたアクセストークンも,ユーザの介入なしに更新することはできない.認可コード グラントでは,リフレッシュトークンを発行することができ,アクセストークンのリフレッシュが必要なネイティブアプリにとって,より実用的なオプションである.

8.3. ループバックリダイレクトに関する考慮 事項

ループバックのリダイレクトURIは,「http」スキームを使用する(TLS(Transport Layer Securit)なし).ループバックリダイレクトはHTTPリクエストがデバイスから出ることがないため許容されていることである.

クライアントは認可リクエストを開始するときにのみポートを開き,応答が返されると閉じられるべきである.

クライアントは,他のアクターを避けるためループバックのみを受け入れる必要がある.

localhostを使用するリダイレクトURI(http://localhost:{port}/{path})は,7.3節で記したループバックリダイレクトと同様に機能するが,localhostの使用は推奨されない(NOT RECOMMENDED). localhostではなくIPでURIを指定した方が,ループバック以外からの要求を誤って受け付けることが少なく,また,クライアント側のファイアウォールやユーザデバイス上での誤ったホスト名解決の影響を受けにくいからである.

8.4. ネイティブアプリクライアントの登録

インスタンスごとの Secret を提供するためのダイナミッククライアント登録[RFC7591]のようなメカニズムを使用する場合を除いて,ネイティブアプリは,OAuth 2.0 [RFC6749]の2.1節で定義されているように公開クライアントとして分類される.そのように認可サーバに登録されなければならない(MUST).リクエストを識別して適切な処理を行うめ,認可サーバは,クライアントの詳細情報を登録する際に種別を記録しておかなければならない(MUST).

認可サーバは,クライアントが完全なリダイレクトURI(パスを含む)を登録し,登録されたもののうちのいずれかと正確に一致しないリダイレクトURIを指定する認可リクエストを拒否しなければならない(MUST)が,ループバックリダイレクトは例外であり,ポート以外の完全一致が必要である.

プライベートURIスキームの場合,7.1節にあるとおり,認可サーバはクライアントに逆ドメイン名に基づくスキームを使用させる必要がある(SHOULD).最低でも,ピリオド "." を含まないプライベートURIスキームは拒否されるべきである(SHOULD)

アプリの制御下にあるドメイン名に基づいたURIスキームを要求することは,ドメイン名の衝突が避けられることに加え,複数のアプリが同じプライベートURIスキームを主張する事態が発生した場合の所有権確認に役立つ(いずれかのアプリが悪意ある行動をしている場合など).たとえば,2つのアプリが "com.example.app" を主張した場合,"example.com" の所有者はアプリストア運営者に偽造アプリを削除するよう申し立てることができる.一般的なURIスキームが使用されている場合,このような申立ては困難である.

認可サーバは,アプリパッケージやバンドル名などの他のプラットフォーム固有情報や,対象OS上におけるアプリの識別子IDを確認するために必要なその他の情報を要求することができる(MAY).

8.5. クライアント認証

複数のユーザに配布されるアプリの一部として静的に含まれる Secert は,1人のユーザが自分に配布されたものを調べることで Secret を知ることができてしまうため,ConfidentialクライアントのSecretとして扱うべきではない.このため[RFC6819]の5.3.1項に記載されているように,すでに"client_id"リクエストパラメータによって提供されているクライアント識別子以上の意味はないため,認可サーバがSecretを使用してPublicネイティブアプリのクライアント認証を要求することは推奨されない(NOT RECOMMENDED).

それでもネイティブアプリのために静的に組込まれたSecretを必要とする認可サーバは,OAuth 2.0 [RFC6749]の2.1節で定義されているようにPublicクライアントとして扱わなければならず(MUST),そのSecretをクライアントの身元証明として受け付けてはならない.追加の対策を講じなければ,そのようなクライアントは偽装の対象となる(8.6節参照).

8.6. クライアント実装

OAuth 2.0 [RFC6749] 10.2節に述べられているように,認可サーバはクライアントのアイデンティティが保証されている場合を除き,ユーザの同意や対話なしで自動的に認可リクエストを処理してはならない(SHOULD NOT).これには,ユーザが以前に特定のクライアントIDの認可リクエストを承認した場合も含まれる.クライアントのIDが証明されない限り,リクエストは以前のリクエストが承認されていないかのように処理される必要がある.

登録済"https"スキームのリダイレクトなどの措置は,認可サーバーによってID証明として受け入れられるかもしれない(MAY).一部のOSでは, プラットフォーム固有の別のID機能が提供されている場合があるが,それについても適切に受け入れられる(MAY).

8.7. 外部ユーザエージェント偽装

認可リクエストを開始しているネイティブアプリは,ユーザインタフェースを大幅に制御しており,外部ユーザエージェントの偽装,つまり外部ユーザーエージェントであるかのように組込ユーザエージェントを表示する可能性がある.

すべての善良アプリが外部ユーザエージェントを使用している場合,セキュリティ専門家によって外部ユーザエージェントを偽装している人が悪いと判断される可能性はある.一方,善良アプリであるか悪意あるアプリであるかにかかわらず,アプリが組込ユーザエージェントを使用している場合,何かを偽造する必要はなく,検出するのがより困難である.悪意あるアプリを検出すると,該当アプリの署名をマルウェアスキャンソフトのブラックリストに登録したり,アプリストアで配布されているアプリを削除したり,その他悪意あるアプリの拡大を防ぐ対策が講じられる.

認可サーバは,真の外部ユーザーエージェントのみが使用できる認証要素を要求することによって,直接的に外部ユーザーエージェント対策を施すこともできる.

特にセキュリティを気にしているユーザは, アプリ内ブラウザタブを使用する際に,アプリ内ブラウザタブからフルブラウザでリクエストを開き,リクエストを完了させる.アプリ内ブラウザタブのほとんどがそのような機能を実装している.

8.8. 悪意ある外部ユーザエージェント

悪質アプリがOSの「https」スキームURIのデフォルトハンドラとして自身を設定した場合,デフォルトブラウザを使用するはずの認可リクエストを傍受し,フィッシング詐欺のような悪質行為を行う可能性がある.

この攻撃はOAuthに限定されない.このように設定されてしまった悪質アプリは,ネイティブアプリによるOAuthの使用を超えてユーザに一般的かつ継続的なリスクを与える.多くのOSでは「http」および「https」スキームのデフォルトのハンドラを変更する際に明示的なユーザ操作を要求し,この問題を緩和している.

8.9. クロスアプリケーションリクエスト偽造

[RFC6819] 5.3.5節では,"state"パラメータを使用してCSRF(Cross-Site Request Forgery)攻撃を防ぐためにクライアントのリクエストとレスポンスをリンクすることを推奨している.

アプリ間通信(いわゆる「クロスアプリリクエスト偽造」)に対するCSRFと同種の攻撃を緩和するため, 高エントロピーの安全な乱数を生成し認可リクエストの "state" パラメータに含むことが推奨されている.保留中の認可リクエストと対になる "state" の値が存在しない場合,レスポンスの受領を拒否する.

8.10. 認可サーバのMix-Up

同じアプリで使用される,別の認可サーバを攻撃する、侵された悪意ある認可サーバから保護するため,アプリは認可サーバごとに一意のリダイレクトURIを設定する必要がある(REQUIRED).たとえば、認可サーバによってパスを変えるなどである.かつ, 受信したリダイレクトURIが送付した認可リクエスト中のリダイレクトURIと一致しない場合,認可レスポンスは拒否される.

ネイティブアプリは,認可リクエストで使用されたリダイレクトURIを認可セッションデータ("state " および他の関連データとともに)に保存しておかなければならず(MUST),認可レスポンスを受信したURIがそれと完全一致していることを確認しなければならない(MUST).

8.4節の要件,特に,認可サーバーが,登録されたものと一致しないURIを含むリクエストを拒否することも,そのような攻撃を防ぐために必要である.

8.11. ブラウザ以外の外部ユーザエージェント

本仕様では,特定のタイプの外部ユーザエージェント,ユーザのブラウザを推奨している.他の外部ユーザエージェントでも 安全かつ有効なOAuthを実行可能であるかもしれない.しかし,本書はそれらのパターンには触れない.

8.12. 組込ユーザエージェント

OAuth 2.0 [RFC6749]の9章には,ネイティブアプリが認可エンドポイントと対話するための2つの方法が記載されている.本仕様では,ネイティブアプリは,組込ユーザエージェントを使用して認可リクエストを実行してはならない(MUST NOT).認可エンドポイントは組込ユーザエージェントからの認可リクエストを検出し,ブロックしても良い(MAY).本件に関するセキュリティ事項の詳細についてここで説明する.

組込ユーザエージェントは,ネイティブアプリを認可するための代替手段である.組込ユーザエージェントは,組込ユーザエージェントをホストするアプリはアプリ向けのOAuth 認可だけでなくユーザの完全な認証クレデンシャルにアクセスできてしまうため,第三者が認可サーバへのリクエストに使用するのは安全ではない.

典型的な組込ユーザエージェントの Web-View 実装では,ホストアプリはログインフォームに入力されたすべてのキーストロークを記録してユーザ名とパスワードを取得する.そして,ユーザの同意を飛ばしてそれらをフォームで自動的に送り得られたセッションCookieをコピーして認証されたユーザとして振舞うために利用する.

認可サーバと同じ団体に属する信頼できるアプリによって使用される場合においても,組込ユーザーエージェントは,必要以上に強力なクレデンシャルにアクセスすることによって,必要最小限の原則に反し,攻撃的な側面を潜在的に増加させてしまう.

ブラウザに備わっている通常のアドレスバーや証明書の有効性を目視確認できる機能を使用せず,組込ユーザエージェントにクレデンシャルを入力するよう促すことは,ユーザが正当なサイトにサインインしているかどうか判断できなくしている.たとえ正当なサイトであったとしても,最初にサイトを検証することなくクレデンシャルを入力させることができるのである.

セキュリティ上の問題の他,組込ユーザエージェントは他のアプリケーションやブラウザと認証状態を共有しないため,認可リクエストが発生する度にログインする必要が生じてしまう.これは非常にいけてないユーザエクスペリエンスである.

9. IANA Considerations

This document does not require any IANA actions.

Section 7.1 specifies how private-use URI schemes are used for inter-app communication in OAuth protocol flows. This document requires in Section 7.1 that such schemes are based on domain names owned or assigned to the app, as recommended in Section 3.8 of [RFC7595]. Per Section 6 of [RFC7595], registration of domain-based URI schemes with IANA is not required.

10. References

10.1. Normative References

See original -> https://tools.ietf.org/html/rfc8252#section-10.1

10.2. Informative References

See original -> https://tools.ietf.org/html/rfc8252#section-10.2

Appendix A. サーバチェックリスト

ネイティブアプリをサポートするOAuthサーバーは,下記に対応しなければならない.

  1. プライベートURIスキームがURIをリダイレクトURIとしてサポートすること.これは,モバイルOSをサポートするために必要である.詳細は7.1節参照.

  2. Public ネイティブアプリクライアントで使用するリダイレクトURIとして「https」スキームをサポートすること.これは,先進的なモバイルOSのアプリにおいて使われる,登録済"https"スキームをサポートするために必要である.詳細は7.2節参照を参照.

  3. ループバックのリダイレクトURIをサポートすること.これは,デスクトップOSをサポートするために必要である.詳細は7.3節参照.

  4. ネイティブアプリクライアントがSecretを保持できるとは想定されていない.Secretが同じネイティブアプリに含まれて配布され,複数インストールされているような場合,confidentialとして扱われるべきではない.詳細は8.5節参照.

  5. PKCE [RFC7636]をサポートすること.アプリ間通信経由でPublicクライアントに送信される認可コードを守るために必要である.詳細は8.1節参照.

Appendix B. プラットフォーム固有の実装

ここでは主に,さまざまな環境で一般的に利用できる手法を参照し,一般的な方法でのベストプラクティスを定義している.仕様範囲外である本章では,さまざまなOSにおける実装のベストプラクティスに関する詳細を記す.

ここでの実装の詳細は,公開時点では正しいものの時代とともに変化する可能性があると考えられる.本書のほかの部分で定義されている事項がそのような変化によって無効にされるようなことなく,それらの事項は優先されることが望まれる.

B.1. iOS

アプリは,アプリ内ブラウザタブを実装する "SFSafariViewController" クラスまたはその後継である "SFAuthenticationSession" クラスを介して,ユーザがアプリを離れることなくブラウザで認可リクエストを開始することができる.Safariを使えばアプリ内ブラウザタブ機能なしでも,古いバージョンのiOSでのリクエストを処理でき,有用である.

認可レスポンスを受取るには,プライベートURIスキーム(カスタムURLスキーム)と登録済"https"スキームURI(ユニバーサルリンク)のいずれも可能である.

アプリは,アプリのプロパティリストファイル "Info.plist"の "CFBundleURLTypes" キーを使用してプライベートURIスキームを,ドメインにホストされた entitlementsファイルと associationファイルのユニバーサルリンク機能を使用して登録済"https"スキームURIを,それぞれ登録する.

iOS 9以上では,OSによって所有権が証明されるので登録済"https"スキームURIの方が好ましい.

完全なオープンソースのサンプルは、iOS用とmacOS用のAppAuthライブラリ [AppAuth.iOSmacOS]に含まれている.

B.2. Android

アプリ内ブラウザタブを実装するAndroidカスタムタブ機能を使うことで,ユーザがアプリを離れることなくブラウザから認可リクエストを開始できる.カスタムタブをサポートするブラウザがない場合は,ユーザのデフォルトブラウザを使用してリクエストを処理することもできる.

Androidブラウザのベンダは,"CustomTabsService"クラスの実装を提供することによってカスタムタブプロトコルをサポートし,最適なアプリ内ブラウザタブのユーザエクスペリエンスを提供すべきである.Chromeは,カスタムタブを実装するブラウザの1つである.

認可レスポンスを受取るにあたっては,プライベートURIスキームが,Android暗黙的インテントを通じて広くサポートされている. Android6.0以上であれば,Android App経由で登録済"https"スキームを利用することもできる.どちらのタイプのリダイレクトURIも,アプリのマニフェストに登録されている.

完全なオープンソースのサンプルは、Android用のAppAuthライブラリ[AppAuth.Android]に含まれている.

B.3. Windows

従来のアプリ,UWP(Universal Windows Platform)アプリ共に,ユーザのブラウザで許可リクエストを実行できる.ループバックでのリッスンはデフォルトのファイアウォールルールによって許可されているため,通常,従来のアプリで認可レスポンスを受取るにはループバックを使用する.同じソケットに他のアプリをバインドしないように,ループバックソケットを作成する際 "SO_EXCLUSIVEADDRUSE"オプションを設定すべきである(SHOULD).

UWPアプリは,アプリをフォアグラウンドへ持ち込むプライベートURIスキームを使用してブラウザから認可レスポンスを受取ることがでる.プラットフォーム上で"URIアクティベーション"と呼ばれているURIスキームの長さは39文字に制限されており,"." を含むので短い逆ドメイン名表記が可能である(7.1節参照).

UWPアプリは,認可フロー用に設計された外部ユーザエージェントであるシングルサインオン(SSO)モードで,Web認証ブローカーAPIを代わりに使用することもできる.クッキーはブローカーの呼出し元で共有されるがブラウザとは共有されないため,ブラウザにアクティブなセッションがあっても再度ログインする必要がある.しかし,ブローカーで作成されたセッションは,ブローカーを使用する後続のアプリで使用することができる.ユーザがブラウザに行ったパスワードマネージャの設定などのパーソナライズは,ブローカーでは使用できない.外部ユーザエージェントとして使用するには,SSOモードで使わなければならない(MUST).

Web認証ブローカをSSOモードで使用するには,リダイレクトURIの形式が"msapp:// {appSID}"でなければならない."{appSID}"はアプリのセキュリティ識別子(SID)であり,"GetCurrentApplicationCallbackUri"メソッドを呼び出すことによってアプリ登録情報の中から確認することができる.このように,WindowsではリダイレクトURIの権限が強制され,一致するSIDを持つアプリだけが応答を受取ることができる一方,同じ権限のない他のプラットフォームのアプリから要求することもできる.したがって,セキュリティを考慮してプライベートURIスキームと同様に扱われるべきである.

これらのパターンを示すオープンソースのサンプルはこちら[SamplesForWindows].

B.4. macOS

アプリは,ブラウザのURIを開くAPIを使用して,ユーザのデフォルトブラウザで認可リクエストを開始することができる.

リクエストを開始したアプリにユーザが戻ってくるため,macOS上で認可レスポンスを受取るのは,プライベートURIスキームが適した選択肢である.これらは "CFBundleURLSchemes" キーを使用してアプリのバンドル情報プロパティリストに登録される.ループバックもまた実行可能である.ループバックでのリッスンは,ファイアウォールのデフォルトルールで許可されている.

完全なオープンソースのサンプルは、iOS用とmacOS用のAppAuthライブラリ [AppAuth.iOSmacOS]に含まれている.

B.5. Linux

ユーザのデフォルトブラウザで認可リクエストを開くには,"xdg-open"などのようなディストリビューション固有のコマンドが必要である.

Linux上のアプリで認可レスポンスを受取るのに推奨されるのはループバックリダイレクトである. Appsは,他のアプリが同じソケットにバインドされないように,"SO_REUSEPORT" ならびに "SO_REUSEADDR" ソケットオプションを設定するべきではない(SHOULD NOT).

謝辞

GoogleにおけるネイティブアプリでプライベートURIの活用は,7.1節の基本を形成した.設計に携わった Marius Scurtescu ならびに Ben Wiley Sittler の功績に,深謝の意を表する.

また,以下の各個人がアイデア出し,フィードバック,説明方法などに貢献し, 最終的な仕様の完成にいたることができたこと,心から感謝する.

Andy Zmolek, Steven E. Wright, Brian Campbell, Nat Sakimura, Eric Sachs, Paul Madsen, Iain McGinniss, Rahul Ravikumar, Breno de Medeiros, Hannes Tschofenig, Ashish Jain, Erik Wahlstrom, Bill Fisher, Sudhi Umarji, Michael B. Jones, Vittorio Bertocci, Dick Hardt, David Waite, Ignacio Fiorentino, Kathleen Moriarty, and Elwyn Devies.

Authors' Addresses

  • William Denniss

    • Google

    • 1600 Amphitheatre Pkwy Mountain View, CA 94043 United States of America

    • Email: rfc8252@wdenniss.com

    • URI: http://wdenniss.com/appauth

  • John Bradley

    • Ping Identity

    • Phone: +1 202-630-5272

    • Email: rfc8252@ve7jtb.com

    • URI: http://www.thread-safe.com/p/appauth.html