OIDC Client Initiated Backchannel Authentication Flow (CIBA)とは - 詳細もとい感想編

ritouです。

前に概要編を書きました。

ritou.hatenablog.com

この続き、具体的なリクエスト/レスポンスについてはこの記事に書いてあるじゃん。 もうこれ読めばいいのでは? スヤァ...としばらく過ごしてました。

qiita.com

そして先日、OpenID TechNightというイベントのLTでCIBAのお話があり、前半の内容と関連するとして概要編のリンクを載せてもらいました。

speakerdeck.com

Qiitaの記事でパラメータの説明などは詳しく書いてあるので似たようなこと書くのやめて、開発者視点から見た感想にしようと思い重い腰を上げました。

で、仕様はこちらです。

openid.net

寝かせておいたらCore 1.0 draft-02になってる!

概要編とのつながりを大事にして、まずは3つのモードの実装面の違いを見ていきましょう。

1. Poll mode

f:id:ritou:20190214014808p:plain

特徴としては

Poll : Client は OP の Token Endpoint をポーリングして応答を受け取る

と言うことで、OPとしては「ADでユーザーの同意もらうわ。終わったらトークンあげるから、定期的に連絡して。」てなばかりに Clientがポーリング(=インターバル取りつつリクエストしまくる)する感じです。

OPが実装すること

  • Backchannel Authentication Endpoint : CIBA 用の最初のリクエストを受けるエンドポイント
  • Authentication Device (AD) 上でのユーザー認証(検証?)/認可処理
  • Token Endpoint における CIBA 用 GrantType のサポート

最初の2つはCIBAのキモなので他のモードでも必要です。

それ以外に必要なのは Token Endpoint の拡張だけなので、OP側の実装はシンプルです。 が、Client / End User の数が増えると Token Endpoint にリクエストが集中する可能性があるので負荷を考慮する必要がありますね。 エラー処理下手くそなClientとか出されると辛いかもしれません。

Clientが実装すること

  • Backchannel Authentication Endpoint へのリクエス
  • Token Endpoint へのリクエスト(ポーリング)

基本的にリクエストを送るだけなので、既存の OAuth / OIDC の仕組みと大きくは変わらない気もします。 OP側の負荷に繋がるため、特に Token Endpoint に送られるリクエストのエラーハンドリングはちゃんとしないといけません。

2. Ping mode

f:id:ritou:20190214022248p:plain

特徴としては

Ping : 事前に Client が登録しておいた Callback URI に対して OP が認証の識別子と共に通知用のリクエストを送る。 Client は Token Endpoint からトークンを取得する。

と言うことで、OPとしては「ユーザーとのやりとりが終わったら連絡するー。そしたらトークン取りに来て。」みたいな感じです。

OPが実装すること

  • Backchannel Authentication Endpoint : CIBA 用の最初のリクエストを受けるエンドポイント
  • Authentication Device (AD) 上でのユーザー認証(検証?)/認可処理
  • Client Notification Endpoint への通知
  • Token Endpoint における CIBA 用 GrantType のサポート

Poll モードとの違いはOPからの通知のところですね。

OPからClientへ向けたリクエストってのは既存の OAuth 2.0 / OIDC にはない処理ですが、OP側はHTTPのリクエストを送るだけなのでそれほど難しくはなさそうです。

そして、Client がこの通知をちゃんと待っていられたら、Token Endpoint へのリクエストは必要最低限に抑えられます。

Clientが実装すること

  • Backchannel Authentication Endpoint へのリクエス
  • Client Notification Endpoint にて通知を受ける
  • Token Endpoint へのリクエス

当然、通知を受ける実装が必要となります。 この辺りは、Client側の開発スタイルにちょっと影響を与えるかもしれません。

既存の OAuth / OIDC において、http://localhost:4000/oidc/callback みたいなURLを redirect_uri などに設定、ローカルで立ち上げたWebサーバーとリダイレクトして...ってやってるところも多いのではないでしょうか? リダイレクトで繋ぐことはできても、OPからローカルのサーバーに通知を送るが困難なケースがあるでしょう。

最終的に Token Endpoint にリクエストを送るので、ローカルな環境ではこの部分の回避策を取りつつ Poll モードのように実装して、ちゃんとした動作確認はステージングやサンドボックス的な環境を用意して...みたいな話になるかもしれません。

3. Push mode

f:id:ritou:20190214022704p:plain

特徴としては

Push : 事前に Client が登録しておいた Callback URI に対して OP がトークンを含むリクエストを送る。

と言うことでOPとしては「終わったらこっちからToken送るわ。待ってて。」みたいな感じです。

OPが実装すること

  • Backchannel Authentication Endpoint : CIBA 用の最初のリクエストを受けるエンドポイント
  • Authentication Device (AD) 上でのユーザー認証(検証?)/認可処理
  • Client Notification Endpoint へのレスポンスの送信

Ping モードとの違いは TokenResponse も Client に送っちゃうところです。 となると、既存の OAuth 2.0 / OIDC のエンドポイントと言うか処理と完全に分離できそうですね。 CIBA導入による既存のシステムへの影響も"それなりに"抑えられるかもしれません。

Clientが実装すること

  • Backchannel Authentication Endpoint へのリクエス
  • Client Notification Endpoint にてユーザーとのやりとりの結果を受ける

Ping モードで出て来たローカル開発時の懸念、この Push モードだと詰みそうですね。 OP / Client 共に、どのモードをサポートするかの検討時に覚えておくと良さそうです。

何たらこんしだれーしょんを読もう

RFCIETFのDraftで仕様を読むとき、パラメータやフローの説明はもちろん大事ですが、設計や実装まで行う場合は Security / Privacy Consideration をしっかり読んでおくのが良いでしょう。

ということで、ここからは仕様の後半に記載されている内容を取り上げます。

ヒント

Qiitaの記事でも言及がありますが、ユーザー識別のために3つの識別子が利用できます。

  • login_hint_token : エンドユーザーを識別する情報を含むトーク
  • id_token_hint : OPが過去に発行したID Tokenも指定できる
  • login_hint : メアドや電話番号、ユーザーIDなどOPがユーザーを識別するためのエンドユーザーに関するヒント

SecurityConsiderationでは次のような記述があります。

The login_hint_token SHOULD be digitally signed by the issuer. This ensures authenticity of the data and reduces the threat of an injection attack. The signature allows the OP to authenticate and authorize the sender of the hint and prevent collecting of user identifiers by rogue Clients.

login_hint_token は発行者によってデジタル署名をつけるべき。データの信頼性が保証され、インジェクション攻撃の脅威が軽減される。この署名により、OPはヒント送信者を認証でき、不正なClientからの識別子の収集を防ぐことができると。 個人的にちょっと前から気にしているスクリーニング対策としてはこれが良さそうですね。

An id_token_hint cannot be validated using standard JWT processing rules because the token is being used in a context (sent from the Client back to the OP) that is different than that for which it was originally issued (typically a short lived token issued by the OP intended to convey claims about the authentication of an end-user to the Client).

過去にOPによって払い出されたID Tokenを使うってことは、有効期限を検証する本来のJWTの検証とは異なる使い方になります。 iss, audを検証するのはもちろんですが、署名検証となるとキーローテーションに関係してくるのでOPは過去に有効だった鍵の情報も保持したりする必要があります。 ってことで、id_token_hintを受け入れるのはあんまり筋が...ってなりますね。

Given these restrictions, implementers may consider not verifying the signature at all and only accepting ID Tokens with pairwise subject identifiers as hints.

ID Tokenの署名検証しないでPPIDをヒントとしてやりとりしたら良いじゃんとか言いだしています。うーむ。

ちなみに、このヒントについて、Privacy Considerationにも記載があります。 メアドや電話番号のような識別子を利用する場合はプライバシーに明らかに影響があるので、プライバシー要件が求められる場合は代替として以下のような識別子が利用できますねというあたりです。

  • PPIDを含むID Token(また出てきた)
  • ADからCDに転送された使い捨てID : 例えばCDであるPOS端末がADである手元のスマホに表示されているQRコードを読み取って決済開始!とかを想像するとどっかで聞いたことある気がします。
  • ディスカバリーサービス : 外のサービスで暗号化/復号みたいな

この辺りはCDというかClientが提供したいサービスの特性によってキメながら実装していく感じになりそうですね。

backchannel_client_notification_endpoint の扱い

  • OP は Client の管理下にあることを確認すべき
  • Push モードで Client が OP からトークンレスポンスを受け取った時、access_token, refresh_token, auth_req_id のハッシュの値をちゃんと検証する

OPがちゃんと実装してもClientの検証がぬるかったら大変なことになりますね。

ここまで仕様を見た感じの感想

  • CIBAの仕様で定義されている部分は実際に提供されるサービスの一部分(の裏側)に過ぎない
  • OP/Client間でどのモードを使うか、識別子の扱いなどキメが必要となる
  • モードによってはClientの開発環境のあたりで困るかも

というあたりでしょう。これに加えてOPはADのあたりもがっつり作らないといけない。しんどそうですね。

FAPI絡まなくても、既存のOIDCの仕組みが適用できないと思われていたところに使える面白い仕組みだと思うので、実サービスに組み込むには

  • ユースケース考えよう。オレオレ乱立を標準化するとメリット大きいものとは?
  • ユースケース毎にヒントのあたりをどうするかなど、ベストプラクティスを考えよう

みたいな取り組みができると良いのではないかと思いました。 OP実装の裏側にいる Authlete の人たちだけが頑張ってる場合じゃないですね。我々も頑張りましょう!(我々とは)

ではまた。