OIDC CIBAのようなDecoupled AuthZ/AuthNプロトコルでリスクベース判定したくない?

おはようございます。ritouです。

f:id:ritou:20200502011658p:plain

OAuth 2.0 の Device Flow(RFC 8628) や OpenID Connect Client Initiated Backchannel Authentication Flow(いわゆるCIBA)、XYZ/XAuthといった次のOAuth候補みたいなプロトコルでは次のような流れがサポートされています。

  • ClientがIdPに認可リクエストをバックチャンネルで送る
  • IdPがユーザーインタラクション用のURLなどを返して Client がユーザーをそこに誘導したり、専用のアプリに通知を送ったりして認証、リソースアクセス等に同意する

いわゆるベーシックなOIDCの認可コードフローでは "Client が動作する環境" と "IdPとユーザーが対話を行う環境" が同一であることが想定されるわけですが、このような流れにすることで "Client が動作する環境" と "IdPとユーザーが対話を行う環境" が別であるケースもサポートできます。

今回はこれらのプロトコルで IdP がリスクベース認証を入れようと思った時に、必要となるパラメータについてのお話です。

"Client が動作する環境" と "IdPとユーザーが対話を行う環境" が同一の場合

いわゆる認可(認証)リクエストってので

  • WebApp な Client がリダイレクトで IdP にユーザーを送る
  • NativeApp な Client が外部ブラウザを立ち上げて IdP にユーザーを送る

という場合、 IdP が自身のエンドポイントへのアクセスを受けた時点のブラウザやデバイスの情報を収集、分析して追加の認証や再認証を要求したり、認証をスキップさせることができるでしょう。

ブラウザが一瞬開いて...みたいな挙動は古き悪きリワード広告みたいでいけんのか?とは思いますが、とりあえず。

"Client が動作する環境" と "IdPとユーザーが対話を行う環境" が別の場合

それに対して、それぞれの環境が別な場合、プロトコルを単純に実装しただければ簡単ではなさそうです。

オンライン決済にCIBAを適用する例を考えてみましょう。

  1. ブラウザのECサイトになんかのIDを突っ込む
  2. 手元のスマホに「ECサイト名」「金額」とかが通知されて「OK」する
  3. ブラウザも決済完了になって終わり

こんなことができるわけですが、1 と 3 を行うブラウザが Consumption Device (CD), 2 を行うスマホが Authentication Device (AD) となります。 物理的に同じ場所にいても、デバイス的には別です。

例えば、「いつも使ってるブラウザかつお気に入りのECサイトなら2の処理をスキップ」なんてことを実装しようと思うとどうでしょう。 ブラウザ情報をどこかで送る必要があります。それはいつでしょうか? ユーザーインタラクションをコントロールするためには、認可(認証)リクエストをバックチャンネルで送るところに含む必要があるでしょう。 この辺りはOAuth 2.0 Rich Authorization Requestsなんかを使って複雑なデータ表現が可能になります。

tools.ietf.org

では、どんな情報を送ったら良いでしょうか。 そもそもこんなの既にどこかでやられてるのに違いないということで、3D Secure 2.0を参考にしてみましょう。

3D Secure 2.0のリスクベース認証の仕組み

この辺りをざっくりと理解するためにちょうど良いドキュメントがあります。

stripe.com

3D セキュア 2 は、企業がオンラインでのクレジットカード決済を安全に認証できるようにするためのセキュリティ規格です。3D セキュア 2 (3DS2) について詳しくご説明します。

とか書いてますが中身英語です。”Frictionless Authentication” ってとこに書いてあります。

3D Secure 2 allows businesses and their payment provider to send more data elements on each transaction to the cardholder’s bank. This includes payment-specific data like the shipping address, as well as contextual data, such as the customer’s device ID or previous transaction history. If the data is enough for the bank to trust that the real cardholder is making the purchase, the transaction goes through the “frictionless” flow and the authentication is completed without any additional input from the cardholder.

いろんなデータを送っているようです(ざっくり)。

これをOIDCで扱うデータに置き換えてみると

  • Clientはデバイス(またはセッション、あるいはその両方)の情報をAuthNリクエストに追加する
  • IdPは受け取った情報からリスクを判断し、それが低い場合は対話をスキップしても良い

って感じにできそうです。

次はデータの内容ですが、リスクベース認証のために3Dセキュア2.0で送信されるデバイス情報は、EMV® 3-D Secure SDK — Device Informationとして定義されています。

具体的には

というあたりのデータが、仕様に準拠していることを認定されたSDKを使用することで取得、送信されます。

# Device Info for Android (from spec)
{
"DV":"1.0", # DV: Data Version
"DD":{"C001":"Android","C002":"HTC One_M8","C004":"5.0.1","C005":"en- US","C006":"Eastern Standard Time","C007":"06797903-fb61-41ed-94c2-4d2b74e27d18","C009":"John's Android Device",....}, # DD: Device Data
"DPNA":{"C010":"RE01","C011":"RE03"}, # DPNA: Device Parameter Not Available
"SW":["SW01","SW04"] # SW: Security Warning. For information about Security Warning, refer to the EMV 3-D Secure SDK Specification.
}

Webブラウザーベースの場合、3D Secure 2.0の仕様で定義された値のリストがあります。

  • Browser Accept Headers
  • Browser IP Address
  • Browser Java Enabled
  • Browser Language
  • Browser Screen Color Depth
  • Browser Screen Height
  • Browser Screen Width
  • Browser Time Zone
  • Browser User-Agent

ということで、全部含めたら結構な量になりそうですが、このアプローチはOIDCにも適用できそうです。

OIDCの認証リクエストにデバイス情報を追加する拡張案

比較的大きなデバイス情報を送る必要がありそうですが、既にOIDC/OAuth 2.0で使われている方法が適用できるでしょう。

  • JWTにシリアライズした値 (OIDC の “request” パラメータ)
  • JSON もしくは JWT をホストするURI (OIDC の “request_uri” パラメータや OAuth 2.0 の PAR)

あんまりこういう方式をネストしたくはない気もしますが、デバイス情報の場合は

  • “device_info”
  • “device_info_uri

というパラメータを新規に用意することで実現可能となるでしょう。 この時、JWTペイロードまたはJSON本文には、デバイス情報が含まれています。

# JWT's Payload and device_uri response
{
 "platform":"Android",
 "device_model":"HTC One_M8",
 "os_version":"5.0.1",
 ...
 "device_name":"John's Android Device",
 ...
}

CIBAの認証リクエストに含む場合、こんな感じになるでしょう。

POST /bc-authorize HTTP/1.1
   Host: server.example.com
   Content-Type: application/x-www-form-urlencoded

scope=openid%20email%20example-scope&
client_notification_token=8d67dc78-7faa-4d41-aabd-67707b374255&
binding_message=W4SCT&
login_hint_token=eyJraWQiOiJsdGFjZXNidyIsImFsZyI6IkVTMjU2In0.eyJ
zdWJfaWQiOnsic3ViamVjdF90eXBlIjoicGhvbmUiLCJwaG9uZSI6IisxMzMwMjg
xODAwNCJ9fQ.Kk8jcUbHjJAQkRSHyDuFQr3NMEOSJEZc85VfER74tX6J9CuUllr8
9WKUHUR7MA0-mWlptMRRhdgW1ZDt7g1uwQ&
client_assertion_type=urn%3Aietf%3Aparams%3Aoauth%3A
client-assertion-type%3Ajwt-bearer&
client_assertion=eyJraWQiOiJsdGFjZXNidyIsImFsZyI6IkVTMjU2In0.eyJ
pc3MiOiJzNkJoZFJrcXQzIiwic3ViIjoiczZCaGRSa3F0MyIsImF1ZCI6Imh0dHB
zOi8vc2VydmVyLmV4YW1wbGUuY29tIiwianRpIjoiYmRjLVhzX3NmLTNZTW80RlN
6SUoyUSIsImlhdCI6MTUzNzgxOTQ4NiwiZXhwIjoxNTM3ODE5Nzc3fQ.Ybr8mg_3
E2OptOSsA8rnelYO_y1L-yFaF_j1iemM3ntB61_GN3APe5cl_-5a6cvGlP154XAK
7fL-GaZSdnd9kg&
device_info=eyJ....eyJ... # NEW!!!

IdPはClientから認証リクエストを受け取ったデバイス情報を検証し、ユーザーインタラクション自体をスキップするかどうかを判定できます。 CIBA の場合、 "ユーザーインタラクションなしで即トークンを返す" ことが表現できないと思うので、互換性を考えるとBackchannel Authentication Endpointからはトークンを返さず、その後の各モードに合わせたやり方ですぐにトークンを返すような実装になるでしょう

ユーザーの許可について

ここまで紹介したデータはトラッキング目的でも使われそうなものでした。 Clientはデバイス情報を収集する前にユーザーに使用目的を説明し、同意を得る必要があるかもしれません。

まとめ

この記事のまとめとしては

  • OIDCのリダイレクトフローとCD/ADが分離するフローでは、デバイスリスクの判断のタイミングが異なる
  • 3D Secure 2.0では、Clientはデバイスまたはブラウザーの情報をパラメーターとして送信し、リスクの判断に使用する
  • このアプローチをOIDCに導入するために、追加のパラメーターを考えてみた

となります。

ユーザーの手元のスマホだけで世の中を動かすの、未来感はあっても毎回操作が求められるUXはなかなかしんどいので省略できるものはできた方が良いでしょう。 あんまりこれ系のプロトコル自体にリスクベース認証がどうこうってのは定義されていないものですが、既存の仕組みで応用できるものがあったらどんどん取り込んでいく、取り込めるように作れるのが標準化ってやつだと思います。

初学者向けの話とか仕様紹介だけじゃなくたまにはこういう話も良いですね。

ではまた!

CIBA is 何

ritou.hatenablog.com

ritou.hatenablog.com

In English

medium.com