0x00 背景
一 Web Pentester の立場から、毎回 OAuth 連携の案件が来る時に、どこが診断する必要なのか、どこが idP の SDK 使っているから診断不要なのかを見極める必要があり、このような背景において、OAuth2.0 をもう一回復習して、心得を共有したいと思い始めました。(0x01~0x08)。復習しているうちに、OAuth の idP 両社の脆弱性を見つけ、50万円賞金もらって終わりと思ったらいつの間に両社経営統合されました。この話を読みたい方は 0x09 から読んでください。
この文章を読む前提は二つあります:
- OAuth2.0 の各種認証 Flow (すくなくとも Implicit Grant, Code Grant, Code Grant with PKCE) を大まかに理解していること。
- この文章図解:OAuth 2.0に潜む「5つの脆弱性」と解決法に書いてある攻撃手法1~4を大まかに理解していること(攻撃手法5は今回の範囲外)。
これを前提に、以下の六つの質問に対して議論してみます。この六つの質問の答えが全部わかる人は 0x09 に進めてください。
- Code Grant では code が漏洩した場合に悪用できるか
- Web Message Response Mode では Covert Redirect 脆弱性は発生しうるか
- Web Message Response Mode では state パラメータは必須なのか
- Code Grant with PKCE では state パラメータが必須なのか
- WebView を利用する Implicit Grant は Token Interception される恐れはあるのか
- WebView を利用する Implicit Grant は何が良くないのか
0x01 Code Grant では code が漏洩した場合に悪用できるか
まず一番簡単だが、一番誤解が多い質問から説明します。
Code Grant では、code が何かしらの理由で攻撃者にもれた場合に (Auth Server が redirect 先を制限してない、Referer/URL で漏洩、Appの場合悪意 App Schema による漏洩等)、攻撃者がこの code を使って token と交換できるでしょうか。多くの方が「state パラメータがついていれば交換できない」という誤解を持っています。
しかし、state パラメータは code と紐づいてなく、攻撃者は code を入手したら、被害者の state を使わずに、自分が事前に用意した state と被害者の code で正規な URL を組み立てることができます。この URL を使えば被害者のアイデンティティーで認証を完結することができます。
0x02 Web Message Response Mode では Covert Redirect 脆弱性は発生しうるか
まず Web Message Response Mode とは何がを説明します。これは普段 OAuth ではあんまり聞きなれない単語かもしれませんが、2015年に HTML5 が普及してから導入された Mode です。これはあくまで実装の話で、OAuth の 新しい Flow ではありません。Web Message Response Mode は Implicit Grant とも、Code Grant とも組み合わせて使えます。簡単にイメージを説明すると、今まで各 Flow を紹介する際に、idP が token また code を Client に返す時に、redirect を使って Client に token また code を URL 経由で渡していると説明したが、これは実は Redirect Response Mode と言います。この Mode に対して、Web Message Response Mode という Mode があります。 Web Message Response Mode では、redirect を使わずに、HTML5 の postMessage を利用しています。Client のサイトから OAuth 認証を実行する時に、idP サイトに遷移せずに、Pop-up Window が開かれ、その新しい Window で OAuth の認証をします。認証が完了したら、postMessage API を使って、親 Window (Client のサイト) に token または code を渡します。もっと詳しい説明はこちらの IETF に記述されています:https://tools.ietf.org/html/draft-sakimura-oauth-wmrm-00。
インタネット上では Redirect Response Mode の紹介が多いが、正直 Implicit Grant で Redirect Response Mode を使う idP は最近あんまり見かけず、例えば LINE はそもそも response_type=token をサポートしないし、Facebook と Google が提供している Login Widget (Javascript の SDK) は Web Message Response Mode を使ってます。
では、Web Message Response Mode を使っていると、かつて炎上していた Covert Redirect (この文章はわかりやすい:https://weblog.bulknews.net/covert-redirect-vulnerability-with-oauth-2-2c1f3083b1b4) という脆弱性はなくなるでしょうか?
答えは YES, Covert Redirect という脆弱性は無くなります。理由も自明ですが、Redirect という手順がなくなったからです。その代わりに postMessage が利用され、Open Redirector があっても OAuth への影響はないでしょう。
ここで少し余談ですが、なぜ LINE が Implicit Grant をサポートしないかというと、筆者の推測だと、OAuth Security Best Practice に書書かれているように、Implicit Grant に脆弱性がとても埋め込みやすい (token 漏洩しやすい、client の正規性確認できないなど) ので、おすすめしない Flow になっています。
0x03 Web Message Response Mode では state パラメータは必須なのか
0x02 で議論していた各 idP が提供している Web Message Response Mode の Javascript SDK を使う場合には、Client の実装不備による OAuth で良く発生する CSRF 脆弱性にも耐性があるでしょうか?
答えは YES, Web Message Response Mode を取り込んだ Javascript SDK を使うと、state パラメータはなくても CSRF はありえないでしょう。なぜかというと、idP が SDK をちゃんと実装していれば、message イベントが来る時に、postMessage の origin をチェックしているでしょう。この origin のチェックによって、非 idP の domain からの postMessage は一切拒絶されるので、CSRF の余地がありません。
ちなみに、Yahoo の Javascript SDK は親切に state パラメータを生成し、チェックしてくれていますが、Google と Facebook の Javascript SDK はいずれも state パラメータを使っていません。
0x04 Code Grant with PKCE では state パラメータが必須なのか
Appの場合、悪意に登録された App Schema による Code Interception攻撃を防ぐために、Code Flow with PKCE という手法が採用されます。多くの idP が提供している SDK が、PKCE を実装する時に state パラメータも必須になっているが、実際に state パラメータがなくても(Clientの実装忘れ等)、CSRF に耐性あるでしょうか?
答えは YES, state パラメータがなくても、PKCE は CSRFに耐性があります。この答えにたどり着くまで少し考えが必要ですが、PKCE を使う場合に、code_challenge と code は idP サーバで紐づいていて、攻撃者は code_verifier が知らない限り、 自分の code を他人に使用させることはできません。
0x05 WebView を利用する Implicit Grant は Code / Token Interception される恐れはあるのか
WebView を利用して、OAuth の認証 SDK を提供している idP がすくなくありません。むしろ WebView の中で OAuth 認証をさせるのはもう各 idP のデファクトスタンダードになっていると言えます。 Code / Token Interception という問題は Native App の OAuth 認証時に、外部ブラウザを使う時に発生し得る問題ですが、WebView を使う場合にも Code / Token Interception 攻撃発生し得るかみてみます。
Code / Token Interception が発生するタイミングは、OAuth の認証が完了し、 Client App に遷移して戻る時です。この際に違うクライアントに遷移してしまったら Code / Token Interception が発生します。ただし、Native App 用の WebView を使った SDK は、殆どの idP はその WebView の shouldOverrideUrlLoading メソッドを上書きし、認証完了後の Redirect を App 内に閉じるようにしています (e.g. Facebookの場合:https://github.com/facebook/facebook-android-sdk/blob/4.x-branch/facebook-common/src/main/java/com/facebook/internal/WebDialog.java#L578)。このような実装であれば、外部 App への誤遷移によって、 code / token が外部 App に漏れることはないでしょう。
しかし、他の idP も調べたら脆弱な実装は見つかりました。例えばヤフーの YConnect を使う場合に、ヤフーのライブラリーは WebView を改造することなく、認証成功後に Redirect する時に、App 本体から Export しているカスタムスキーマを利用して、WebView から App 本体に遷移させます。この状況は何が不味いかというと、WebView からカスタムスキーマをオープンする時に、必ずしも該当 WebView を開いた App が優先的に開かれる保証はないです。要するに、他の Evil-App も同じカスタムスキーマを登録したら、正規 App の WebView から Evil-App を開く可能性があります。これは Code / Token Interception に繋がります。
0x06 WebView を利用する Implicit Grant は何が良くないのか
前述の事例から見ると、WebView を利用した Native App はどんな脆弱性も作り込めなく、最強な作り方では?と思ってしまう方も居ると思いますが、しかし、このデファクトスタンダードは本当にいいのか考えましょう。
RFC8252の8.12節で説明された通りに、WebView を使うとそもそも OAuth の意味が無くなります。OAuth は信用できない第三者に ID / PW を提供しないで身分を認証するプロトコルであり、第三者 App の中の WebView (WebView に偽装するものも含め) に直接 ID / PW を入れるのはどう考えても OAuth 本来の役目が成り立たないでしょう。
ここで LINE を褒めてあげたいんで、LINE の場合は WebView 方式の SDK を提供せずに、ちゃんと外部ブラウザ方式で認証をしています。
0x07 まとめ表
Flow 別の Client の (SDK使わず) 実装により、脆弱性を埋め込む可能性
Y -- Clientの実装により、脆弱性を埋め込む可能性がある
N -- Clientの実装と関係なく、脆弱になることはない
脆弱性 | Implicit Grant | Code Grant | Code Grant with PKCE |
---|---|---|---|
Token Replace | Y | N | N |
Covert Redirect | Y | N | N |
CSRF | Y | Y | N |
Token Interception | Y | - | - |
Code Interception | - | Y | N |
この表から見ると、やはり Code Grant with PKCE は一番安全だなと感じますよね。
今回調べた四社 idP のサポートしている Flow と 提供している SDK
Identity Provider | Implicit Grant | Code Grant | Code Grant with PKCE |
---|---|---|---|
LINE | サポートしない | Client 各自で実装 | Native SDK |
Yahoo! Japan | Javascript SDK, Web Message Response Mode | Javascript SDK, バックエンドはClient 各自で実装 | サポートしない |
Javascript SDK, Web Message Response Mode | Client 各自で実装 | Client 各自で実装 | |
Javascript SDK, Web Message Response Mode | Client 各自で実装 | サポートしない |
今回調べた四社 idP が提供している SDK を使う場合に脆弱性を埋め込む可能性
Native SDK | Client の実装により脆弱を埋め込む可能性 | |
---|---|---|
LINE | PKCE | ない |
Yahoo | Implicit / Hybrid | 外部ブラウザを使う実装は Code Interception と Token Interception に脆弱;WebView を使う実装もカスタムスキーマ Export しているので脆弱になる;Stateパラメータはデベロッパー自ら生成するので、デベロッパーによってCSRF脆弱性が生じうる |
Implicit Grant | Google Sign-in 使うと Implicit Grant になるが、WebView をカスタマイズしているので Token Interception 攻撃されない。PKCE使おうとしたら自前でクエリを組み立てる必要がある。 | |
Implicit Grant | WebView をカスタマイズしているので Token Interception 攻撃されない |
Javascript SDK | Client の実装により脆弱を埋め込む可能性 | |
---|---|---|
LINE | ない | Client の実装による |
Yahoo | Implict Grant | Web Message Response Mode + state なので、Covert Redirect と CSRF 攻撃されない |
Implicit Grant | Web Message Response Mode なので、Covert Redirect と CSRF攻撃されない | |
Implicit Grant | Web Message Response Mode なので、Covert Redirect と CSRF 攻撃されない |
0x08 結論
結論は意外と簡単にまとめられます。idP が提供している SDK を利用している場合に、Client の実装に関わらず脆弱になる可能性はほとんどないと言えます。ただし、idP の提供している SDK に脆弱性があったり、一部のパラメータ生成がデベロッパーに任せたりしたら話は違いますが。。。
例として、次の二段落で idP 側の脆弱性について紹介します。
0x09 今回見つけた脆弱性(LINE社)
まず今回5000ドルの報奨金をいただいたLINEのOAuthの脆弱性に付いて紹介します。とてもシンプルな脆弱性で、一言でいうと、PKCEの実装にcode_verifierとcodeの紐づけをAuth Serverでチェックしていないというところがダメです。
なぜこんな簡単な脆弱性は今まで見つかってないのかというと、おそらくこの PKCE 機能はドキュメントされていないからではないかと推測しています。LINE の line-sdk-android を実際に動かして通信みないと、LINE の OAuth が PKCE 対応していること自体に気づけないし、さらに、パラメータの名前は標準的な code_verifier と code_challenge ではなく、otp と otpId と名付けされて、一目ですぐ PKCE だと気づきにくいでしょう。(同社の情報によると、実装当時はまだ PKCE の標準が定めていないから code_verifier などの標準単語使わなかったわけだそうです。)
実際にこの脆弱性を利用するために、被害者アプリとおなじ package name の悪意アプリをインストールする必要があることです。悪用するには少しハードルがあると言えます。さらに、PKCE が実装されている Identity Provider 自体も少なく、Facebook でもそもそも PKCE 対応していないし、PKCE 対応しようとするだけで偉いと思います。ただし、ちゃんと実装しましょうね。
0x0A 今回見つけた脆弱性(ヤフー社)
次の例は Yahoo の OAuth にあります。0x05にすでに少し触れてまして、簡単に説明すると、ヤフーの OAuth SDK は超手抜き実装で Callback 用のカスタムスキーマを Export されていて、WebView で認証しても、外部ブラウザで認証しても Code Interception, Token Intercetion ができてしまいます。外部ブラウザーを使う OAuth 認証の Code Interception と Token Interception は基本 PKCE でしか防げないので、単に PKCE 未実装だけだと脆弱性と言えるか微妙ですが、少なくとも WebView を使った認証フローは PKCE 無しでも Code Interception と Token Interception されない実装はできるはずです。Facebook も PKCE 未対応ですが、Facebook の SDK では WebView の shouldOverrideUrlLoading メソットをオーバライドすることで、Callback 時に外部アプリに遷移出来ないようにされています。一方でヤフーの手抜き実装だと WebView をカスタマイズしてなく、Callback の URL スキーマが来た時に OS の機能に頼ってどのアプリを立ち上げるのを任せている状態で脆弱です。
これの修正としてはまずカスタマイズスキーマ(Android の場合)を android-app:// スキーマに入れ替わって、その後根本的な対策 PKCE 実装を追加されたらしいです。
0x0B OIDC の Certification サービスについて
もう一つ気になることがります。OpenID Foundation は OpenID Connect Certification というプログラムがあって、この組織の特定の要件を満たすと、会社のサイトに認定されてるよ的なロゴを貼ることができます。要するにオンラインショッピングする時によく見かける SSL Site Seal Logo のようなもんです。ヤフー社のはこちらに貼られていますhttps://developer.yahoo.co.jp/yconnect/v2/。このロゴを見ると、すごい「セキュアだ!」と安心感が出るかもしれませんが、よくよくここの認定に関するドキュメントを読んだらhttps://openid.net/wordpress-content/uploads/2018/06/OpenID-Connect-Conformance-Profiles.pdf、セキュリティ上の要件は一つも書かれていません。結局 OIDC の Site Seal Logo があっても、どの程度の安全性をクリアしているのかを表明するものではありません。何を言いたいかというと、OIDC といえば認証認可という安全性は極力求められている分野のはずですが、OpenID Foundation で発行した Certification には安全性レベルの定義はないのはやや気持ち悪いです。
0x0C 余談
今回特に LINE と Yahoo で見つけた脆弱性の話しましたが、両社の対応スピード感等に大きな差が感じました。LINE には7月12日に脆弱性報告し、2週間後に修正され、一ヶ月後に賞金を講座に振り込まれました。Yahoo はバグバウンティプログラムが存在しないので、8月5日にIPA経由で報告したんですが、一通目の返信は報告してからおおよそ三週間後でした。11月12日に Android 版 SDK の work around がリリーされ、12月19日にやっと PKCE がリリースされました。ちなみに、11月18日に LINE とヤフーが経営統合され、ヤフーのセキュリティ事情も LINE と統一されたら嬉しいですよね。そして先日 YJTC でこのような発表安全・安心に向けたYahoo! ID連携の改善とネイティブアプリのID連携の実装があり、スライドを読んだら「なるほど PKCE はなかっただけでなく、PPID も対応してなかったですね」と思いました。LINE の場合は PKCE はあったし、PPID もずっと前から対応してた気がします。まあある意味では両社のセキュリティレベルも統一されつつあると言えるでしょうかね。めでたし。
(完)
0x0D その他の参考情報
NULL