Re: 特定条件下におけるOAuth 2.0の認可応答を奪取されるリスクとその対策について

前回 Google Cross Client Identityで解説いただいたid:ritouが書いていたエントリについて

実はtwitterにてメンションを送ったのだけど、なんとなくカスタムURIスキームという前提とは別かなとおもってツイートを削除してしまったのだけど、反応いただいたのでこのエントリでを書く事にした。(ツイート消してしまって、ごめんなさい)

特定条件下におけるOAuth 2.0の認可応答を奪取されるリスクとその対策について - r-weblife

twitterにて書いた内容としては以下のような内容(たぶんこんな感じだったと思う)

GoogleのInstalled Applicationの仕様のhttp://localhostに任意のポートを指定できるという仕様が大部分解決しているとおもう。URIを占有できるというのが大事

自分的にはカスタムURIスキームが重複するリスクについてはしっていたけれど、以前OAuth2対応についてGoogleでのInstalled Applicationの仕様を調べていたため、この方法で解決していくものとおもっていたのだけれども、世の中的にはまだ解決していなかったらしいという状態。

カスタムURIスキームを使用する問題点

まずカスタムURIスキームとは何かというとURIに任意のアプリケーションを関連づける機構でAndroidiOSなどでOSの機能として提供されている。OAuth2の仕様の話でいくと認可応答の際にリダイレクトでよばれることになり、これで対応するアプリが起動し、Authorization codeなどを取得する事になる。問題点としてはアプリケーション毎にこのカスタムURIスキームが一意になればよいが、アプリケーションが偶然、もしくは悪意をもって重複させたときに認可応答が本来意図しないクライアントに渡る可能性がある問題。

先のエントリでは拡張機能として2つの方法が紹介されている。

GoogleのInstalled Applicationについておさらい

Using OAuth 2.0 for Installed Applications - Google Accounts Authentication and Authorization — Google Developers
AndroidでGoogle OAuth2認証を行う。(Installed Applicationとして登録) - 高温処理済みコースケ

  • GoogleがいうところのInstalled ApplicationとはネイティブアプリケーションでOAuth2をやり取りする為の仕組み
  • redirect_uriは固定でurn:ietf:wg:oauth:2.0:oobもしくはhttp://localhostでポート番号は認可要求時に任意の番号を指定できる。ちなみにパス部分も自由でhttp://localhost:8080/callbackとかを指定できる。

今回はhttp://localhostが対象。

これのよいところは実装時にローカルでウェブサーバーを動かさないといけないけど、ポートをbindする必要があるので、よほど不味い実装でない限り他のアプリケーションに渡る可能性がないというところだ。

ちなみにこの方法はもともとの前提条件であるカスタムURIスキームという条件からはおそらく外れてしまっている。だからツイート消してしまったのだが、ネイティブアプリでのOAuth2実装としてはこの方法仕様が一番よいとおもっている。

OAuth2での仕様について

OAuth2のredirection_uriの仕様を見ると認可サーバーに事前に登録したURIもしくは認可要求次に指定したURIにリダイレクトすることでブラウザからクライアントアプリを起動するとなっているけれど、ここで実際にクライアントが占有できる、もしくは占有したURIを指定していしなければならないとしたほうがよいのだとおもう。

After completing its interaction with the resource owner, the
authorization server directs the resource owner's user-agent back to
the client. The authorization server redirects the user-agent to the
client's redirection endpoint previously established with the
authorization server during the client registration process or when
making the authorization request.

The redirection endpoint URI MUST be an absolute URI as defined by
[RFC3986] Section 4.3. The endpoint URI MAY include an
"application/x-www-form-urlencoded" formatted (per Appendix B) query
component ([RFC3986] Section 3.4), which MUST be retained when adding
additional query parameters. The endpoint URI MUST NOT include a
fragment component. After completing its interaction with the resource owner, the
authorization server directs the resource owner's user-agent back to
the client. The authorization server redirects the user-agent to the
client's redirection endpoint previously established with the
authorization server during the client registration process or when
making the authorization request.

The redirection endpoint URI MUST be an absolute URI as defined by
[RFC3986] Section 4.3. The endpoint URI MAY include an
"application/x-www-form-urlencoded" formatted (per Appendix B) query
component ([RFC3986] Section 3.4), which MUST be retained when adding
additional query parameters. The endpoint URI MUST NOT include a
fragment component.

RFC 6749 - The OAuth 2.0 Authorization Framework

こうすれば認可要求作成直前にバックエンドサーバーに認可応答用の占有リソースを作成し、redirect_uriに指定する事でバックエンドサーバーに認可応答を飛ばして、バックエンドサーバーと任意のプロトコルでAuthorization codeやAccess Tokenを安全にやりとりするとかも範疇に入ってくる。

あとカスタムURIスキームがかぶった場合には、占有できるURIという条件からは外れるため仕様上の問題とはならなくなる。