LINEログインの対応から「手元のスマホでログイン」の仕組みであるDecoupled AuthNを理解しよう

f:id:ritou:20201115074615p:plain

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

何の話か

今日はLINEが発表した取組みと今後使われるようになるかも知れない認証方式について紹介します。

linecorp.com

まず使ってみました。流れはこんな感じです。

f:id:ritou:20201115075009p:plain

電話番号を入力し、"スマートフォンでログイン" ボタンを押します。

f:id:ritou:20201115075041p:plain

初回は認証番号を使う必要があります。

f:id:ritou:20201115075113p:plain

スマホ側では初回は認証番号を入力する画面が出て、入れると生体認証やパターンロックなどが要求されます。

2回目以降は、"私ではない" か "ログイン" というボタンが表示され、生体認証やパターンロックなどが要求されてログインできます。

LINEのようにアプリが多くのユーザーの手元のスマートフォンにインストールされて利用されている場合、それを生かさない手はありません。 様々な端末のLINEアプリケーションを "手元のスマホでログイン" してパスワード入力をせずに簡単に利用できるようにする、そのための第一歩が今回の施策であります。

そこで、今回は細かいところで3つの観点から見ていきます。

  • 手元のスマホを使ってログインする "Decoupled Authentication" という仕組み
  • FIDOの生体認証などと組み合わせることによる利便性の向上
  • 決済など外部サービス間で "Decoupled Authentication" を実現するための標準化仕様

"手元のスマホでログイン" = Decoupled Authentication

ログインしたいサービスが動作する端末とログインに利用する端末が分離されている認証方式のことを "Decoupled Authentication" と呼びます。"Decoupled Flow" などと表現を使っているところもあります。 (誰が呼び始めたのか、定義を昔調べた気がしましたが忘れました。)

"手元のスマホでログイン" と言えば、Googleは早い段階から、Android端末を用いたGoogleアカウントのログイン機能を実装していました。

support.google.com

Googleの対応は2種類の用途があります。

  • パスワード認証後、2段階認証としてスマホに通知が行ってOKする = 記憶認証(パスワード) + 所持認証
  • パスワード認証前にメアドを入れた時点でスマホに通知が行ってロック解除してOK = 所持認証 + 記憶 or 生体認証(ロック解除)でパスワードレス!

f:id:ritou:20201021220719p:plain

(OTPの設定をしている場合、前者は2段階目の方法の追加となりますが後者だと2段階認証を解除しつつのこの方法を設定となります。業務で使ってるアカウントの場合は2段階認証必須などのルールとの兼ね合いにお気をつけください。)

パスワードレスな新しい端末だったり、パスワード管理ソフトの設定が済んでない状態で長くて複雑なパスワードを手打ちするのは結構大変です。ブラウザの機能も進化したぶん、一時的に利用する端末にパスワードを覚えさせないような注意も必要かもしれませんが、このパスワードレスの方式であればブラウザがパスワードに関与せずに認証が実現できます。 2段階認証の用途で言っても、PCのブラウザに毎回ワンタイムパスワード用のスマホアプリや受信したSMSを見て手打ちするよりはユーザー体験が良くなるかもしれません。

この方式にも課題はありますが、それは後述します。

金融/決済分野でのユースケース (3-D Secure / Open Banking)

この前、3-D Secureに関する投稿をしましたが、クレカチャージ/決済のための登録時などに使われているクレカ所持者の当人認証でもこのような "Decoupled Authentication" の導入がサポートされていて、3DS Secureの version 2.2 ぐらいから仕様でも関連するパラメータが含まれています。

  • ブラウザで決済、スマホのアプリに認証要求
  • サブスクの決済を登録、月単位でスマホのアプリに認証要求

そして日本でも銀行のAPI提供が話題に上がることが増えてきましたが、英国のOpenBankingの技術仕様でも "Decoupled Approach" として言及があります。

standards.openbanking.org.uk

より強度の高い認証が求められる分野の利便性を向上させるための方法として "Decoupled Authentication" に注目が集まっています。

Decoupled Authentication & FIDO(ファイド)

LINEはFIDOアライアンスに参画し、生体認証による利便性向上、パスワードレスに向けた取組みを以前から進めており、今回の対応もスマートフォンで生体認証などを使うことによる利便性を生かす仕組みです。

最近はFIDOの仕様をサポートしながら生体認証に対応するデバイスも増えてきましたが、全ての端末に指紋やら何やらを登録していくのはなかなか手間でしょう。普段使っていない、他人の所有している端末や新しい端末を利用する場合は "手元のスマホ" を利用する "Decoupled Authentication" を使うことでその利便性を向上させられるかもしれません。

FIDOの仕様策定、普及を促進しているFIDOアライアンスでも "Decoupled Authentication" のユースケースが考えられていて、LINEのようにインターナルなユースケースではなく、異なるサービスが絡んだユースケースがドキュメントにまとめられています。

fidoalliance.org

先ほどのOpenBankingのドキュメントと似たようなP(PaymentやProvider)が出てくるキーワードだらけでもはや呪文にしか見えないかもしれませんが、3-D Secureと同様の決済におけるユースケースに触れられております。

f:id:ritou:20201115075451p:plain

上の図にある通り、"決済機能におけるマーチャント"から"アカウントを管理してるサービスのモバイルアプリ"に決済情報が送られ、生体認証をしつつ内容を許諾するとマーチャント側で決済が成功しています。

そのためには、下の図のように "アカウントを管理してるサービスのWebアプリ" と "アカウントを管理してるサービスのモバイルアプリ" の間で事前の設定が必要ですみたいな図です。

このように、"手元のスマホ" でFIDOの生体認証などを行うことで、"Decoupled Authentication" のユースケースの利便性を向上されることが以前から検討されていて、やっと実装される段階になったという感じです。

異なるサービス間でDecoupled Authenticationを実現する仕組み - OIDC CIBA(シーバ)

ところで、FIDOは生体認証の裏側で行われる公開鍵暗号方式を用いた処理を定義しているものです。先ほどの資料ではいわゆる"チャレンジ"の値を引き回してブラウザ-スマホアプリとの連携をしましょうみたいなことは書いてありますが、上の図のMerchant - ASPSP の間の決済情報のやりとりなどは仕様の対象外です。

3-D Secureでは当然、決済の一連の流れが定義されていますが、それとは別のアプローチで標準化が進められている仕様があります。それが OpenID ファウンデーションで仕様策定が進められている OpenID Connect(OIDC) Client Initiated Backchannel Authentication Flow(CIBA) です。

OIDCとは、簡単にいうと外部サービスが "Google でログイン" を実装するための仕組み であり、CIBAはそのOIDCのフローを "Decoupled Authentication" で実装するための仕様 と言えます。

CIBAについて知りたい方は以下のリンクを参考にしてください。

ritou.hatenablog.com

qiita.com

OIDCやOAuthでは、リソースアクセスの権限要求などに加え、サービス間で決済情報などをやりとりする仕組みがあります。しかし、FIDOで定義されていない "サービス間のやりとり" が定義されているCIBAには "手元のスマホでの認証処理" の具体的な部分(パスワード認証とかFIDOとか)について細かく定義されていません。 守備範囲が違うけど組み合わせて使えるということで、FIDOとOIDCは、”補完関係”にあたる関係です。

f:id:ritou:20201115075512p:plain

CIBAの仕様自体はそれなりに成熟してきた段階にあり、先ほど紹介した英国OpenBankingのガイドラインでもCIBAを利用するOIDCのプロファイルが参照されています。 "Decoupled Authentication" は標準化仕様の組み合わせにより実装できる状態にあると言えるでしょう。

"Decoupled Authentication" の課題 - UX, フィッシング耐性

ここまでで利便性のことをメインに "Decoupled Authentication" を紹介してきましたが、課題もそれなりにあります。

  • UX : 利便性を売りにする以上、ブラウザでのユーザー識別のためのメアド入力を減らしたりスマートフォンで行う動作を最小限にするなどのチューニングが必要でしょう。決済でのユースケースでは購入情報などをどこまで引回すかなど、ベストプラクティスを作っていく必要がありそうです。
  • "中間者攻撃" タイプのフィッシングの脅威 : "本来のFIDO" が対応できてOTP方式で対応できない攻撃として、リアルタイムに正規のサービスの認証機能とやりとりしつつユーザーに認証を要求するフィッシング攻撃があります。 正規のサイト "example.com" が表示するログイン画面をフィッシングサイトである "example.net" がプロキシのようにユーザーに表示して認証処理を要求した場合、ブラウザでFIDOの認証を行うとドメイン(origin)が変わるので認証は完結しません。しかし、"Decoupled Authentication" のスマートフォン上の認証フローでは "正しいFIDOの生体認証" が行われ、そのままフィッシングというかセッションのっとりが成功する可能性があります。 ブラウザを経由しないフローではブラウザを用いた対策はできない。それは当然です。

このあたりの対策、ベストプラクティスが固まった時点でやっと "Decoupled Authentication" が使われ始めるのかもしれません。

まとめ

長くなりましたが、まとめると

  • LINEがスマートフォンを用いて別端末にログインする仕組みを発表したので触ってみた
  • "手元のスマートフォンでログイン" する "Decoupled Authentication" が熱くなってきてる
  • "Decoupled Authentication" と FIDO, OIDC CIBAとの関係を整理した
  • 課題はあるが "Decoupled Authentication" が使われる時代はすぐそこまできている

というところです。今後もDecoupled Authenticationに注目していきましょう。

そういえばアドカレ埋まりました。参加表明をしていただいたみなさん、ありがとうございます。

qiita.com

ではまた。

EMV® 3-D Secure × FIDO で目指す世界とは?

f:id:ritou:20201105022724p:plain

おはようございます。ritouです。 最近寒いです。もうダメ。

なんの話か

今日はこのお話です。

EMVCoとFIDOアライアンスがタッグを組む的な話です。 なんかさっぱりいいねが少ないですが、気になりますね。

読む前に期待してたこと

人間(あるいは猫)はリンク先を確認する前に内容をある程度決めつけちゃう生き物です。そりゃあTwitterも中身見てみろとか言ってくるわけです。

3DSってこういうやつじゃないですか。

https://pointofsale.com/wp-content/uploads/2016/10/3-d_secure_emvco.jpg

(ref. https://pointofsale.com/emvco-launches-emv-3-d-secure-2-0-specification/)

  • (図では3DS Requestorとなってる)MerchantからDSを経由してIssuerに認証要求が送られる
  • (毎回もしくは必要に応じて)Issuerは認証を要求する

なので今回の件、なんとなくこう思っていました。

  • 3DS 2.0からは「必要な時だけ認証を要求してEコマースなどの離脱を防ぐ」みたいな感じだし、きっとその認証にFIDOを使う話なのかなー...
  • そういえば3DSの認証を行うドメインがどうこういう話があったな...FIDO2(WebAuthn)だとドメインというかoriginのあたりも重要になるのでAuthenticatorの登録はこうするとか書かれてるのかなー...
  • 手元のスマホに入ってる公式アプリ + UAF でいよいよ本格的な Decoupled AuthN 時代来るかなー...

f:id:ritou:20201105024925p:plain

で、読んでみました。

書いてあったこと

想像してたのとちょっと違いました。

The ‘Use of FIDO Data in 3DS Messages’ white paper focuses on the newly defined FIDO attestation data set. Using this defined data set, merchants can deliver a structured set of data elements and present the card issuer with a consistent set of values for the same user or device (along with other data they would receive as part of an EMV® 3DS transaction), reducing the need for repeated consumer authentication.

...

“Outlining exactly how the data can be used by card issuers to analyse merchant-initiated FIDO Authentication as part of their risk evaluations, can increase authorisation approval rates, streamline online checkout and reduce fraud,”

資料: https://www.emvco.com/wp-content/uploads/documents/EMVCo_3DS_FIDOData-WPv1.0_20200710.pdf

ということで、

  • FIDOで認証を行うのはMarchantであり、その結果(の一部)もしくはユーザーに紐づく情報を Issuer に送る
  • Issuer はそれを含むユーザー/デバイスのデータを使って認証を要求するかを判断

という感じです。

f:id:ritou:20201105024944p:plain

そっちかい!と思いつつも、3DSはMerchantが決済などをしたい環境、デバイス情報を送りまくってリスクを判別するっていう考えなのでその中にFIDOのデータを使うという考えはなるほどなーという感じもします。

毎回FIDOで認証するわけじゃなく、FIDOのデータも含められるようにするよと。 とはいえ「3DSでの認証スキップの可能性が上がる」ためにMerchantがFIDOでの認証を入れてくれるかってとこが気になります。 まぁ、そこ気にならないぐらいFIDOを普及させれば良いんですね。そうですか。

誰が実装するか?

これ実際どうやって実装されることになるかというと

  1. Merchant自身が元々実装してたのでそれを決済機能に組み合わせて使う
  2. Merchant自身がこのために導入
  3. 3D Secure Merchant Plug-In、SDKがやってくれる未来

の3パターンがありえるかもしれません。2,3は重複するかもしれない。

3DS 2.0でIssuerがリスクベース認証を行うためにたくさんの環境データを利用できるように、3のPluginがSDKを利用して情報を吸い上げる実装があります。 Web用のSDKnならばWebAuthnを呼び出し、結果を保存しておく仕組みやバックエンドから吸い上げる仕組みがあると普及のハードルは下がるかもしれません。

送られるデータ

Merchantから送られるFIDO関連データは次の通りです。

{
  "authTime": "2020-08-08T07:42:17Z",
  "rpId": "https://emvco.com",
  "FIDOAuthenticatorReferences": [
    {
      "publicKey": "BJDLvkKkuXRpn3bWh_hiJQb8lJNd9kTXEmQgEwoHezkNI_VPGd3vrjrWyZTfgxVDl9_Tp ixrVjmEAEmegmfL2WI",
      "aaguid": "0132d110-bf4e-4208-a403-ab4f5f12efe5",
      "uv": true,
      "up": true,
      "usedForThisTransaction": true
    }
  ]
}

WebAuthnとか触った人ならわかりますね。

  • authTime
  • rpId or appId
  • FIDOAuthenticatorReferences
    • publicKey
    • aaguid or Aaid
    • usedForThisTransaction : Merchantの現在のセッションで使われたらtrueがセットされる
    • Up : セキュリティキーやブラウザの所持を確認したか
    • Uv : PINや生体認証をしたか

複数送っても構いません。あるだけ送れという感じです。

まぁ、公開鍵は送っても問題はないしとはいえ、セキュリティキーの緩い型番的な aaguid とかまで...って思ってしまいますが、元々3DSはえぐいデータを送れるような定義になってるのでこういうもんなんでしょう。以前、この3DSのリスクベース判定みたいなのをOIDC CIBAでもやれば...みたいな記事を書きましたので良かったらどうぞ。

ritou.hatenablog.com

Issuerはどうすんの?

先ほど紹介した情報を用いて認証を要求するかしないかを判断します。 ここから先はIssuerの設計/実装に依存する話かと思うので書かれていなそう(別の仕様にあるかも)ですが、この辺りのベストプラクティスもあると良さそうです。

Issuer側でFIDO使わないの?

このあたりは今回の発表とは別で検討されるかもしれません。 FIDOを使ってはいけないということではないので、今後は使うところが出てくることを祈ります。 上にも少し書きましたが、元々3DSの認証で使われるドメインがIssuerのドメインじゃなかったりするパターンもあるので、そのあたりはもう少し整理されないと「微妙に使いにくい組み合わせ」と言われかねません。

まとめ

  • EMV® 3-D Secure × FIDO ということで想像が膨らんだ
  • 書いてある内容は予想と違ってMerchantがFIDOで認証した結果を送るものだった
  • これはこれで興味深いがMerchantの採用モチベーションは上がるだろうか...

うーん、まぁ、ちゃんと実装してくれるIssuer/Marchantが出てくると良いですね。

以上です。

そういえば今年もアドカレやりまっす。

何人か参加表明をいただいております。 満員になったら私の6枠を減らしてもいいので是非ご参加ください。

ではまた。

OIDC CIBAで作る「スマートフォンでログイン」機能

こんばんは、ritouです。

今日は OpenID Connect Client Initiated Backchannel Authentication Flow 通称CIBA のユースケースについて書きます。

CIBA は決済や送金のためのもの?

自分の記事でも、CIBAのユースケースとしてコンビニ決済への導入例を挙げてみたりしました。 そして、CIBAにやたらと詳しい某Authlete社の記事を見ても、送金とか決済などで使えそうな話がプンプンします。

www.authlete.com

www.authlete.com

お金周りはUX改善のメリットとして伝え安いですし、クレカ決済のDecoupled AuthNの実例もあります。 CIBAもFAPIとの絡みがあるのでこの辺りを例示しがちではありますが、今回はそんな流れに逆張りとばかりにシンプルなユースケースに注目します。

スマートフォンでログイン」の要件とCIBAの機能

例えば Google アカウントにログインする際、Androidバイスなどを用いた次のような認証方式が利用可能です。

  • パスワードの代わりにスマートフォンで使用する <- パスワードレス!?
  • 2 段階認証プロセスを有効にした場合に、パスワードに加えて使用する <- 2段階認証!?

support.google.com

Googleは次のようなメリットを挙げています。

f:id:ritou:20201020034338p:plain

  • SMSで受信した認証コードを盗まれるなどのリスクを回避
  • リッチなUI
  • 拒否機能あり

SMSやOTPを使うよりは安心感が出そうですが、なかなか実装の敷居が高そうな機能です。言い換えると、これを簡単に実装できそうだとしたら面白くないですか?

このような機能を実現するための要件としては

  • ユーザーと端末が紐づいている : ユーザーとADの関係
  • 端末にプッシュなどでの通知ができる : CIBA の AuthN Request を受けた OP が ADにプッシュ通知を送って...
  • 必要ならば通知先の端末でユーザー認証 : CIBAではブラックボックスになっているがこの辺はよしなにやるべき内容
  • 環境などリッチな情報を表示して許可を求める : AuthN Requestに情報を載せてやれば良い
  • ユーザーが拒否したら認証フローを終わらせられる : ADでユーザーが拒否したらエラーが返る

ということで、今回はこの「スマートフォンでログイン」をCIBAを使って実装するとどうなるか?っていう話をします。

GOAL

パスワードレス

Google の 「スマートフォンでログイン」のUXを見てみましょう。 まずはメールアドレスなどを入れてユーザーを特定します。

f:id:ritou:20201021215500p:plain

ここで設定が済んでいると、スマートフォンでログインのフローに入ります。 スマートフォン見てみろやと。許可しろやと。そして下に書いてるのと同じ数字をタップしろやと。

f:id:ritou:20201021220705p:plain

ここで、手元のスマートフォンに通知が来ます。 2FAではなくこれだけでログインさせるので設定時に「この機能使う時、画面ロックかかるよ」って言われています。

スマートフォンで表示される画面はこんなんです。 リッチな...とか言ってましたがあんまり情報ないですね。まぁいいか。

f:id:ritou:20201021220719p:plain

「はい」を押すと、さっき言ってた同じ数字をタップしろやと言ってきます。

f:id:ritou:20201021220731p:plain

これでログインできます。

2段階認証

違いとしては

  • ユーザー特定後、パスワード認証
  • パスワードがあっていたら「スマートフォンを確認しろ」画面(上述したような数字のくだりはなし)

というあたりです。

CIBAを用いた実装案

ここでは一旦、「利用するスマートフォンの設定が済んでいる」前提とします。

上で紹介したGoogleの例と揃えると、CIBAの仕様におけるOP/RPという役割がどちらも同一サービス(Google)とする方がイメージしやすいかもしれません。

  • RP : Webアプリやモバイルアプリ
  • OP : 認証基盤的なやーつ

最初に、RPはHTMLフォームなどでユーザー特定に必要な値を受け取ります。 ここではメールアドレスとしましょう。

次に、RPからOPにバックチャンネルで AuthN Request を送ります。 (Client認証部分は省略しています。)

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

   scope=openid&
   binding_message=93&
   login_hint=user@example.com

パラメータとしては

  • login_hint : 対象ユーザーのメアド
  • scope : ログインできたらいいので openid のみ
  • binding_message : 上述のGoogleの例に揃え 93 を指定

というあたりがあれば十分そうです。 レスポンスはこうなります。 パスワードレス、2FAのコンテキストを指定したい場合は acr_values あたりを使っても良いかもしれません。

    HTTP/1.1 200 OK
    Content-Type: application/json
    Cache-Control: no-store

    {
      "auth_req_id": "1c266114-a1be-4252-8ad1-04986c5b9ac1",
      "expires_in": 120,
      "interval": 2
    }

このレスポンスを受けたら、RPはユーザーに「スマートフォンを確認しろ」「binding_messageで指定した値を選択しろ」という画面が出せます。 一方、OPはAuthN Requestを受けたらユーザーのAD(スマートフォンのアプリなど)に通知を送ります。

通知を受けたADでは

  • (パスワードレスをうたうなら)画面ロックなどの再認証要求
  • 対象ユーザーのプロフィール画像、メアドの取得
  • ログインしますか?とユーザーに聞く
  • 「はい」の場合に、binding_message に指定した値とそれ以外の値を払い出し、選択させる

binding_message のあたりは独自でルールを決めつつって感じですが、1 ~ 99 までの数とかに制限しておくと Google のような画面が作れそうです。 OKならRPはIDTokenを取得でき、認証成功したことを検証できます。

ということで、ほぼCIBAの仕様範囲内で実装できそうです。 まぁ、ここまで理解してできる開発者ならもうちょっとシンプルに設計/実装できそうな気もしなくはないですが。

CIBAを利用するにあたり、考えるべき点

RPがWebアプリの例を示しましたが、モバイルアプリでも同様に実装できそうです。 ただし、CIBAはConfidential Clientを対象としているのでリクエストを送るWebサーバーを間に置いておく必要があるかもしれません。

あとは前提のあたりで書いた「RP/OP」が別サービスの場合ですが、

  • 最初にRP(example.com) 内でユーザー特定し、そこから先(AD上の表示など)はOP(example.net)のコンテキストで行われるあたりのユーザーへの見せ方
  • RP->OPのAuthN Requestの login_hint に指定する値

あたりをよく検討してユーザーが気持ち悪く思わないようなUXに仕上げる必要があるでしょう。

登録

上にも書きましたが、CIBAの仕様では、ADとの紐付けは仕様の対象外です。 この辺りはよしなに...とすると悩んじゃいそうなので、この前書いたDevice AuthZ GrantっぽいUXを使って登録フローを考えても良いと思います。

ritou.hatenablog.com

リッチなUI、環境に関する情報

Googleでは2FAの時の画面では

  • バイス(OS情報?)
  • 場所(ネットワーク情報?)
  • 時刻

などを表示していました。 ユーザーへの表示以外にもOP側でリスク判定などに使える値だったりするので、目的外利用とか言われないようにちゃんと同意を得た上で環境に関する情報をやりとりしても良いでしょう。

まとめ

  • CIBAを使って「スマートフォンでログイン」的なパスワードレス、2FAの仕組みが作れそう
  • RP/OPが同一サービスだったらシンプルに作れそう
  • RP/OPが別で「2FA専用SaaS」みたいなのも面白そう

この辺りはプッシュ通知を受けられるPWAなWebアプリでも作れることはわかってるので、どこかでデモできればいいなと思っております。 これからもAuthentication Device (AD)を使うユースケースを探究できたらと思います。

ではまた!

f:id:ritou:20201021234131p:plain

OIDC CIBA の拡張として OAuth 2.0 Device AuthZ Grant を使う仕様を考えてみた

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

なんか急に寒くなりましたね。私は先週末、風邪をひきました。

何の話?

OpenID Connect の CIBA と OAuth 2.0 Device AuthZ Grant は手元の端末を用いてユーザーがID連携やリソースアクセスを許可することから似ている面があるものの、プロトコルとしては結構な違いがあります。

ritou.hatenablog.com

tools.ietf.org

あまり深く考えずにこれらの標準化仕様を弄ってどうこうするのはお勧めできないわけですが、今回は特定の条件下においてこの2つを組み合わせられるのでは?というのを考えてみました。

それぞれの特徴

リクエストやらエンドポイントやらのプロトコルの詳細は一旦おいておいて、ざっくり

  • CIBA
    • RPがOP上のユーザーに紐づく情報を知っている必要がある
    • 事前にユーザーと Authentication Device (AD) の紐付けが存在し、AD上でID連携を許可する。紐付け方については仕様範囲外
  • Device AuthZ Grant
    • Clientは事前にユーザーを知らなくても良い
    • ClientがURL+User Code や QRコード を表示して、ユーザーが自らが利用する端末のブラウザを利用してリソースアクセスを許可する。

のように整理できます。

こう書くと結構な違いがありますが、一方で綺麗に仕様が分かれているようにも感じられるのではないでしょうか。

組み合わせの可能性

FAPIとかのガチなユースケースでは変なこと考えない方が良いと思いますが、C向けの比較的ライトウェイトなサービスとかでは既存の仕様を弄り回すのも頭の体操ぐらいにはなりそうです。

自分でPWAを用いたCIBAのデモを作ってみたりして気付いたんですが、CIBAで前提となっているもののその部分自体は未定義である「ADとユーザーの紐付け」や「RPとの最初のID連携」の部分を簡単にやれるといいなーという思いが出てきました。

そんな中、この2つの仕様が交わるユースケースを考えてみたところ、例えば PWA なWebアプリやモバイルアプリなどで

  • OIDC CIBA のように AD が Push を受けられる
  • OAuth 2.0 Device AuthZ Grant のように URL や QRコードで起動できる

という2つの要件を満たせるならば 「OIDC CIBA で RP とユーザーの紐付けがない状態の時だけ Device AuthZ Grant っぽく」みたいなのができて上記の課題を解決できるのでは?と思ってきました。 そこで、OIDC CIBA の拡張として OAuth 2.0 Device AuthZ Grant を使う仕様 を考えてみたわけです。

OIDC CIBA Dynamic AD Enrollment Extension(仮)

ここからが本番です。いきなりまとめると

  • CIBA の Backchannel Authentication Endpoint への Authentication Request で指定した *hint が空だったり OP 側で紐付けがない/切れた場合に OAuth 2.0 Device AuthZ Grant の Device Authorization Response を返す
  • それにより、動的なAD紐付けが可能になる

みたいな感じです。わかりますか?わかりませんよね。 もうちょっと詳しく説明してみます。

動的なAD紐付け(拡張)

OP上でユーザーとADの紐付けが行われていないもしくはリセットされたような状態からの動的な紐付けを行うケースを想定します。 あとはADが複数存在する場合にRPに対して利用するADを選択するようなケースとかでも使えそうです。

f:id:ritou:20201019005740j:plain

図ではCIBAのPoll modeを想定していますが他のmodeでもあまり変わりません。

1. Authentication Request

RPはOPに対して Authentication Request を送ります。

  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

OIDC CIBAで定義されていいるそのまま載せましたが、今回の拡張を利用するための追加のパラメータが必要になるかもしれません。

CIBAでは*_hintパラメータで指定されたユーザーを特定し、存在しない場合やユーザーが管理しているADと通信できないなどの場合はエラーとして扱いますが、今回の案ではエラーではなく「OAuth 2.0 Device AuthZ Grant」風のレスポンスを返すものとします。

      HTTP/1.1 200 OK
      Content-Type: application/json
      Cache-Control: no-store

      {
        # CIBAのauth_req_id は OAuth 2.0 Device AuthZ Grant の device code 相当
        "auth_req_id": "1c266114-a1be-4252-8ad1-04986c5b9ac1",

        # ここから下が OAuth 2.0 Device AuthZ Grant のレスポンス
        "user_code": "WDJB-MJHT",
        "verification_uri": "https://example.com/device",
        "verification_uri_complete":
            "https://example.com/device?user_code=WDJB-MJHT",

        # 有効期限とインターバルの間隔
        "expires_in": 1800,
        "interval": 5
      }

2. User Interaction

RPは受け取ったverification_uri + user_code や verification_uri_complete をユーザーに提示し、ユーザーはそこにアクセスします。 CIBAのユースケースとしてPOS端末での利用がありましたが、例えばポイントカードを持っていたらスーパーのATMやサービスカウンターにある端末などで最初にこの辺りの設定をする、とかでも良いでしょう。

3. AD Enrollment & Consent

ここで

  • ADとしての登録 (AD Enrollment)
  • RPにユーザー情報を提供することへの同意 (Consent)

などが行われます。

4. Polling Request / Response(NG)

3 が完了するまでは、RPからのPolling Requestに対してOPはエラーを返します。

5. Polling Request / Response(OK)

3 が完了すると、RPからのPolling Requestに対してOPは成功レスポンスを返します。

通常のCIBAフロー

ユーザーとADが紐付けられていて、RPからのAuthentication Requestでユーザーを特定できた場合は通常のCIBAのフローになります。

f:id:ritou:20201019005237j:plain

GNAP, 3D Secure 2.0

以前、XYZとして紹介したドラフト仕様を覚えているでしょうか?

ritou.hatenablog.com

現在はGrant Negotiation and Authorization Protocol(GNAP)として仕様策定が進められています。

tools.ietf.org

これ、最初の頃から

  • バックチャンネルでリソースアクセスを要求
  • 必要であればユーザーインタラクションが発生

という流れになっていました。

OAuth 2.0に求められるユースケース毎の要件を整理し、OAuth 1.0の時のようなバックチャンネルのリクエスト中心のプロトコルとして書き直した感じです。

なので今回紹介したやつとほとんど一緒です。

さらに、XYZの紹介記事でちょっと触れた様に 3D Secure 2.0 のフローにも似ています。

3dsecure2.com

この辺りは細かいパラメータなどは異なるにせよ、大まかな仕組みとしては似ているところに落ち着いていきそうな気がします。

まとめ

  • OIDC CIBA と OAuth 2.0 Device AuthZ Grant の組み合わせを考えてみた
  • OIDC CIBA の仕様外である「ADの登録」のところに OAuth 2.0 Device AuthZ Grant の「動的なリソースアクセス許可」 を適用することで「動的なAD登録」みたいなのが実現できそう
  • XYZ(GNAP)とかと似てる

せっかく仕組み考えたので、次回はこれを使った 「OIDC CIBA as a MFA」 みたいな話を書こうかと思っています。 ではまた!

f:id:ritou:20201017234812p:plain

2020/11/19 に 「idcon vol.28 DID特集その2」 やります

こんにちは、ritouです。

あの #idcon がオンラインで復活!?しかもテーマはDecentralized Identity(DID)!? と言うことで誰かの意識が高まっているのを観測したのでやります。

idcon.connpass.com

今のところの発表案です。

  • 「MSのDID/VC概要」by phr_eidentity : MSのDID/VCを触ってみたので解説します。
  • 「Credential Handler API(仮)」by kg0r0
  • 「DIDCommとかSIOP」by ken5
  • 「Email, Messaging, and SSI/DID: Round2」by s01 : Email, Messaging, and SSI/DID の日本語再放送 + DIDCommで本当にいけるのかという話

順番はテキトーに決めましたが、最初に概要から入り、Credential Handler APIとかDIDCommとかSIOPとか、個別のトピックについて解説されると一気に理解が進むのではないかと期待しています。

そして、大体は こんな感じだよ -> へー、なるほどー終わりーとならない(!)のが idcon でもあります。

  • MSはわかった。他に試せるところって?
  • Credential Handler APIって必要?SIOP拡張したったらこんなのいらなくね?
  • DIDCommってもっとシンプルにならんの?

と言ったあたりはいつもの idcon だと発表の後で盛り上がるところなので、オンラインでも白熱した議論が行われると良いですね。

配信どうしようかまだ決めていませんが、なるようになるでしょう。11月になったら考えます。

と言うことで、参加申込み募集中で〜す。ではまた!

(そろそろ iddance もやらないとなぁ...)

f:id:ritou:20201012185719p:plain

Self-Issued OpenID Connect Provider DID Profile v0.1 とは

f:id:ritou:20200922040730p:plain

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

今日はこれを読んでみます。

Self-Issued OpenID Connect Provider DID Profile v0.1

何のための仕様か

This specification defines the "SIOP DID Profile" (SIOP DID) that is a DID AuthN flavor to use OpenID Connect (OIDC) together with the strong decentralization, privacy and security guarantees of Decentralized Identifiers (DID) for everyone who wants to have a generic way to integrate Identity Wallets into their web applications.

  • WebアプリケーションにIdentity Walletを統合するために
  • DIDとOpenID Connectの組み合わせるための
  • SIOP DID Profileじゃ!

と言うことです。

SIOPについてはもう大丈夫でしょうか?七年前の記事で良ければどうぞ。

ritou.hatenablog.com

Qiitaにもいくつか記事があります。

qiita.com

  • OpenID Providerとして特定のWebアプリケーション(Googleとか)ではなく、モバイル端末内で動作するアプリケーションなどを利用する
  • openid:// と言うカスタムURIスキームを用いた認可リクエストにより呼び出され、鍵ペアを生成/管理してIDToken を返す
  • ユーザーの同意のもとで端末単位で保存している情報のやりとりや、使い方次第では端末の識別やリクエストが同端末から送られたことの検証などにも使おうと思えば使える

と言うものであり、仕様としてはモバイルアプリ、ブラウザのプラグイン、デバイスの機能など特定のURI呼び出しを検知して起動できる仕組みで使えるように汎用的に作られています。

この仕様では、特定のサービスではなく端末自体をOPにすると言うSIOPをDID/SSIのIdentity Walletとして使うために必要な差分なりが定義されています。

Protocol Flow

RPはWebアプリ/ブラウザベース(SPAなど)のアプリであり、モバイルもしくはデスクトップブラウザからIdentityWalletアプリを立ち上げて使う想定です。 公式の図を見てみましょう。

https://identity.foundation/did-siop/assets/did_authn_siop_profile_flow.png

流れをざっくりまとめると、

  1. RPは "Sign-in with SSI" ボタンみたいなのを用意し、ユーザーが押すと SIOP Request を生成
  2. openid://?<SIOP Request> として何やかんやで Identity Walletアプリが起動する
  3. Identity Walletアプリは OIDC/DID AuthN に従って SIOP Request を検証する
  4. 必要なら認証をして、その後に SIOP Response を作成する
  5. response_mode の指定にしたがってRPにSIOP Responseが渡される
  6. RPはOIDC/DID AuthN に従って SIOP Response を検証する

となります。

基本的にこのSIOPの流れに、DID用の処理が追加されるイメージです。

  • SIOP Request : RPは自身のDIDを含み、DIDドキュメントから検証可能な秘密鍵で署名を生成
  • SIOP Response : SIOPは自身のDIDを含み、DIDドキュメントから検証可能な秘密鍵で署名を生成

それでは見ていきましょう。

Generate SIOP Request

SIOP Request は次のように定義されています。

  • 互換性のため、response_type, scope, client_id を文字列で指定する
  • それ以外のパラメータは request もしくは request_uri として指定する。RPのDIDもこっちで指定。

例を引用します。

openid://?response_type=id_token
    &client_id=https%3A%2F%2Frp.example.com%2Fcb
    &scope=openid%20did_authn
    &request=<JWT>
openid://?response_type=id_token
    &client_id=https%3A%2F%2Frp.example.com%2Fcb
    &scope=openid%20did_authn
    &request_uri=https%3A%2F%2Frp.example.com%2F90ce0b8a-a910-4dd0

いわゆるリクエストオブジェクトを指定、なんてのはFAPIなどのProfileでも使われているので驚きはないでしょう。

SIOPのフローでは、registration パラメータによってRPのメタデータを登録できます。

  • アルゴリズムRS256 に加えて ES256KEdDSAをサポートしなければならない
  • Request ObjectはDIDドキュメントに記載されている検証方法で直接/間接的に検証可能であり、RPのJWKSにより直接検証可能である必要がある
  • JWKSは jwks_uri もしくは jwks パラメータで指定され、jwks の場合は kid が一致する必要がある。jwks_uriの場合はHTTP(S) DID Resolution Bindingが必要とか...
  • RPはSIOP Responseを暗号化して受信することもできる

リクエストオブジェクトについても細かく書いてありますが、眠いので例示に留めます。

#header
{
    "alg": "ES256K",
    "typ": "JWT",
    "kid": "did:example:0xab#veri-key1"
}

# payload
{
    "iss": "did:example:0xab", # RP's DIID
    "response_type": "id_token",
    "client_id": "https://my.rp.com/cb",
    "scope": "openid did_authn", # did_authn を指定
    "state": "af0ifjsldkj",
    "nonce": "n-0S6_WzA2Mj",
    "response_mode" : "form_post",
    "registration" : {
        "jwks_uri" : "https://uniresolver.io/1.0/identifiers/did:example:0xab;transform-keys=jwks",
        "id_token_signed_response_alg" : "ES256K"
    }
}

SIOP Request Validation

SIOPは scopedid_authn が指定されていたら、OIDCで定義されている検証に加え次のような検証を行います。

  • iss クレームで指定されたRPのDIDからDIDドキュメントを取得
  • jwks_uriが存在する場合、iss とDIDが一致することを検証
  • RPのDIDドキュメントから、kid と一致する検証方法を取得
  • SIOP Requestの検証

Generate SIOP Response

SIOPは以下のような SIOP Response を作成してRPに戻します。

  • sub_jwkkid を含む
    • kid はSIOPのDIDドキュメントの検証方法を参照する DID URL
  • SIOPのDIDを含む : did クレーム
# Header
{
    "alg": "ES256K",
    "typ": "JWT",
    "kid": "did:example:0xab#key-1"
}

# Payload
{
    "iss": "https://self-issued.me",
    "nonce": "n-0S6_WzA2Mj",
    "exp": 1311281970,
    "iat": 1311280970,
    "sub_jwk" : {
        "crv":"secp256k1",
        "kid":"did:example:0xcd#verikey-1",
        "kty":"EC",
        "x":"7KEKZa5xJPh7WVqHJyUpb2MgEe3nA8Rk7eUlXsmBl-M",
        "y":"3zIgl_ml4RhapyEm5J7lvU-4f5jiBvZr4KgxUjEhl9o"
    },
    "sub": "9-aYUQ7mgL2SWQ_LNTeVN2rtw7xFP-3Y2EO9WV22cF0",
    "did": "did:example:0xcd" # SIOPDID
}

(ちょっと追記)通常のSIOPは鍵を生成して端末なりに保存しておくだけのイメージですが、ここではDIDを含みDIDドキュメントから検証できるようにする必要があるわけなのでこれまでのSIOPの感覚で言うと鍵の登録処理も発生しそうです。もう少し細かく追記してもらうのが良いのかなと思ったりします。

SIOP Response Validation

OIDCのSIOP Responseの検証としては

  1. id_token を取得
  2. id_tokensub_jwk の鍵で署名されたことを検証

さらに DID AuthNとして

  1. id_token の SIOP DID(did) から DIDドキュメントを取得
  2. id_tokenのDIDドキュメントから sub_jwkkid と一致する検証方法を取得
  3. その検証方法で id_token を検証

SIOP Discovery

省略します。

UX Considerations

カスタムURLスキームの扱いについて。 モバイルブラウザの場合はアプリ立ち上げるけどAndroid/iOSそれぞれで今までもいろいろ言われてきたよねと。 デスクトップブラウザの場合、もしかしたらブラウザ拡張/プラグインでサポートされるかもしれないけどうまくいかなそうならIdentity Walletのアプリを開かせてQR読み込ませるとかが必要かも。

この辺りが改善されるにはもう少し時間がかかるかもしれませんね。

Security Considerations

まずはSIOP ResponseのIDToken漏れるかも問題

  • Interception of the Redirect URI : SIOP Responseを取られたらIDToken持っていかれるよ -> RP頑張れ(オープンリダイレクト作るな)
  • Identity Token Leak in Browser History : ブラウザの履歴からSIOP ResponseのIDToken漏れるよ -> IDTokenの有効期限短くしたりキャッシュされないようにしたりしよう。完全な対策は難しいかも。
  • Identity Token Leak to Third Party Scripts : SIOP Responseをを受ける時に3rd PartyのJSとかでIDToken持っていかれるよ -> RP頑張れ(信頼できるやつだけ使え)

対策として response_mode=form_post 使えるならう。無理な場合もあるけど。とあります。

次に Session Fixation in Cross-Device Flow として、異なるデバイス間の転送を含む場合の脅威が記載されています。 RPがQRコードからIdentity Walletを呼び出す仕様の場合、攻撃者は自らのセッションに紐付いたQRを読ませることで第3者の認証を攻撃者のセッションでできるかも。 対策としては同一セッションであることの確認、もしくは異なるデバイスでも同一ユーザーであることを別の認証方式などで確認することが必要。

Github

何かあったらここでやってるよと。

github.com

(追記)SIOP側の公開鍵登録についてもう少し説明必要では?みたいなことを書いてみました。

github.com

まとめ

  • SIOPの流れにDIDの検証処理を追加するProfile
  • RPが作るリクエストオブジェクトの部分がモリモリしてるがSIOPのフローは変わらない
  • カスタムURIスキームやQRコード使う部分はもうちょい改善されないとUXキツそう

と言うあたりでしょうか。引き続きウォッチしていきましょう。 ではまた!

フィッシング対策視点から考えるメールやSMS通知のあり方

こんばんは、ritouです。

令和の時代においても、フィッシング攻撃はメール、SMS共に存在します。 だいぶ普及してきたみんな大好きワンタイムパスワードでもフィッシングに対しては脆弱です(FIDOにしましょう)。 フィッシング攻撃への現状の対策はどうかというと、メール自体の検証、メールにあるURLの表示と実際のリンクの差異、URLが正規のものかを確認することは素人になればなるほど困難です。 SMSならばURLはテキストそのものだから安心かもしれませんが、そもそも正規のメッセージに偽物が混ざってきたらわかりません。

ということで、今回は「メールやSMSにできるだけURLや電話番号などを記載するのを避けよう。」という話です。

主張

例えばこの記事

keepmealive.jp

それならば対策は二つだけ 1. SMSに書かれているURLは原則としてクリックしない 2. どうしてもクリックする必要があるときは本物のURLか確認する ということになります。

ここではdocomoの正規のURL(ドメイン)のリストがずらっと並んでいますが、このような検証を幅広いサービスに適用していくことは困難です。 なので、「メールやSMSにできるだけURLや電話番号などを記載するのはやめよう。」という意見ですね。

某、徳●さんのTweetで見かけたんですが、

pc.watch.impress.co.jp

同社では、「正規の当選メールには、サイトのURLの記載やリンクはなく、申し込み時に登録する『マスク抽選販売サイト』にある『当選者専用サイト』から登録する設計になっている。偽の当選メールに記載されているサイトのURLに行かないようにしてほしい」としている。

まさにこれですね。

UX低下を防ぐ仕組み

この話をすると、URLや電話番号を載せなかったらUXが悪くなるのでは?と言われることがあります。 フィッシングサイトや業者まで一発で引っ張っていけるということで、それだけURLや電話番号を利用することは効率的なUXであるとも言えるでしょう。 正規の通知しか送られてこない前提になっている、例えばモバイルアプリの通知のような場合はそこからアプリを立ち上げて...というUXを変える必要はないでしょうけれども、フィッシング攻撃の可能性がある限りはその部分を取り除きつつ通知の詳細確認やその後の必要な処理への誘導について、代替手段を用意する必要があります。 通知に含まれたURLや電話番号に直接アクセスする代わりに、Webアプリやモバイルアプリに通知を確認できる場所を用意しておき、ユーザー自身でそこにアクセスしにいく方法が良いのではないかと。

  • 今まで
    • 通知の概要(メール/SMS) -> URLクリック -> 詳細確認や継続処理
  • これから
    • 通知の概要(メール/SMS) -> (自分でブックマークなどからWebアプリに移動) -> 詳細確認や継続処理
    • 通知の概要(メール/SMS) -> (手元の端末でモバイルアプリを起動) -> 詳細確認や継続処理

「これから」の方に書いたUXが定着していくと、フィッシング攻撃が来ても「このフロー変じゃない?」と気付けるような仕組みの上での「啓蒙活動」もやりやすくなり、世界の平和に向けて一歩前進できるのではないでしょうか。 サービスの種類にもよりますが、個人的にはこの方が通知を受けたデバイスと実際にサービスに到達しにいくデバイスが異なるパターンでも利用できそうですし、UXは向上するのではないかと思ったりします。。

まぁ、実際にプロダクトでやろうと思ってもなかなか受け入れられないかもしれませんが、さいきょうのアイディーを求めることは悪いことではないでしょう。 ではまた!

f:id:ritou:20200903010702p:plain

現在仕様策定中の OpenID Connect RP-Initiated Logout 1.0 とは

こんばんは ritouです。

むかーしむかし、あるところにOIDCのセッション管理に関する3つの仕様がありました。

(2015年の記事)

ritou.hatenablog.com

(Session Managementについてのさらに古い 2013年の記事)

ritou.hatenablog.com

いわゆるソーシャルログインと呼ばれる使い方ではRP/OP間のセッションの整合性をあまり意識しない感じになっていますが、 昔から使われている "SSO" 的な使われ方においてはそのあたりが意識されるかもしれません。 これらの仕様ではRP/OP間でセッションに変更がないか、ログアウトさせるいくつかの方法が定義されています。

これらは最近どうしてるのかな?というところで現状を見てみると、4つの仕様として策定が進められています。

[Openid-specs-ab] RP-Initiated Logout is now its own specification

また、既にOpenID Certificationにはテストも用意されており、パスしたOPも書かれています。

openid.net

f:id:ritou:20200819024520p:plain

というところで、今回はこのRP-Initiated Logoutについて概要(not 翻訳)を紹介します。

openid.net

This specification complements the OpenID Connect Core 1.0 specification by enabling the Relying Party to request that an End-User be logged out by the OpenID Provider.

これはOPによるエンドユーザーのログアウトをRPから要求できるようにするための拡張仕様です。

新しい用語

これぐらいです。

  • Logout Endpoint : RPがログアウトのリクエストを送るターゲットとなるOPのエンドポイント

RPはこの値を後述する metadata から取得したりドキュメントとかで把握する必要があります。

RPからOPへのログアウト要求

RPがOPにログアウトを要求するパターンとして、2つあります。

  • RP -> OP と遷移して終わるパターン
  • RP -> OP -> RP に戻ってくるパターン

前者の場合、必要なパラメータは

  • id_token_hint : OPからRPに過去に発行されたID Tokenの値をヒントとして指定。RECOMMENDED
  • ui_locales : OP上での優先言語、スクリプトの指定。OPTIONAL

となります。AuthZ(AuthN) Requestのように client_id パラメータを用いて明示的に Client を指定したりはありません。 id_token_hint パラメータがあった場合、事前に ID Token にセッション識別子である sid を入れておくことで現在のセッションと一致するかどうかの判定ができますが、ない場合や検証不可な場合はOPとしてはユーザーがどこから来たのかさえわからない(信用できない)状態になります。

セッションとIDTokenの関連というと今までも何度か記事を書いてきましたが、今回のようなセッション関連の仕様を読むときは、IDTokenをセッション識別という目的で一定期間保持することを想定しなければなりません。有効期限はサーバー時間のずれに影響でないぐらいになるべく短くしIDTokenを取得したタイミングで "ID連携" を行う、という本来のOIDCの考え方との違いについてよく頭の体操をしておく必要があるでしょう。(個人的には id_token_hintという使い方が大っ嫌いなのですが精一杯大人な書き方をしています。)

また、仕様中に突然出てくる sid ですが、これは OpenID Connect Front-Channel Logout で定義されています。仕様の最初の方で他のセッション関連の拡張仕様との関連について言及はありますが、sid がどこで定義されたものかが言及されていないと、初めて見た開発者は混乱するかもしれません。

Draft: OpenID Connect Front-Channel Logout 1.0 - draft 04

sid Identifier for the Session.

OPはログアウトURLでユーザーに対して「ログアウトしますか?」と尋ねるべき(SHOULD)とあります。これを行うとユーザーの意図せぬ挙動を防ぐのと同時に、後述するトラッキング判定に対しても効果があるかもしれません。

ここまでの流れを図にしました。

f:id:ritou:20200825010654p:plain

複数のRPに接続済みのOPはログアウト後に、SessionManagementでのセッション判定で "状態変更あり" を示したり、Front-Channel/back-Channel Logoutの仕様でRPにログアウト通知を送ります。

さらに、RP->OP->RPと戻る場合はパラメータが変わります。

  • id_token_hint : OPからRPに過去に発行されたID Tokenの値をヒントとして指定。REQUIRED
  • post_logout_redirect_uri : OPのログアウト後にRPに戻したい時に指定する戻り先URL。このURLが指定されるときは id_token_hint の値が必須となる。検証の際は完全一致。
  • state : 戻り先がある時のCSRF対策のための...(略。必須でいいだろ(OPTIONAL)!
  • ui_locales : OP上での優先言語、スクリプトの指定。OPTIONAL

f:id:ritou:20200825010923p:plain

この場合は id_token_hint も必須になりますが、ここまでやるならAuthZ Requestのように client_id などを利用する方が良いのではないかと個人的には思います。

この仕様の概要としてはこんな感じです。

Metadata

OP/RPのURLの扱いが書かれています。

OpenID Provider Metadata

OpenID Provider Metadata では RP が Logout Endpoint を Discovery できるように、end_session_endpointという値を定義します。

Client Registration Metadata

OP が RP-Initiated LogoutとDynamic Registrationをサポートする場合、post_logout_redirect_uris という値を事前に登録します。

ITP, SameSite Cookieとセッション関連仕様への影響

ちょうど先日、OpenID TechNight vol.17 ~ with コロナ編でiframeを使うユースケースへの影響について説明されていました。

https://www.youtube.com/watch?v=0856pHMoTDs

その中で、iframeを使っているために影響が考えられる仕様として2つが紹介されていました。

  • Session Management
  • Front-Channel Logout

それぞれの仕様にもこの影響については言及があります。

  • Session Management - 5.1. User Agents Blocking Access to Third-Party Content「RPコンテキストで呼び出したOPのフレームがCookieにアクセスできず、ログイン状態が変更されたという応答を返し、再認証されまくるかも」
  • Front-Channel Logout - 4.1. User Agents Blocking Access to Third-Party Content「frontframe_logout_uriがOPによってレンダリングされた時にRPのログイン状態にアクセスできなくてログアウトされないかも」

今回のRP Initiated Logoutでは、OPはLogout EndpointへのアクセスでGET/POSTをサポートしなければならない(MUST)とあります。 よって、POSTパラメータとなると2つのパターンの前者ではOP、後者ではOP/RP両方でログアウト機能に関連するHTTP CookieのSameSite属性を意識する必要があります。

そう言えばチャチャッとSameSite属性毎の挙動を確認するためのツールを用意しましたので良かったら記事を読んでみてください。 medium.com

また、ログアウトしますか?のようなユーザーインタラクションを省略すると今度はトラッカー判定の方にも関連してきそうなので、この辺りの仕様とブラウザのHTTP Cookie, トラッカー判定事情の関係は今後も注意深くみていく必要がありそうです。

まとめ

  • RPからOPへのログアウト要求を送る方法が定義されている
  • OPからRPに戻るかどうかで2種類の挙動がある
  • POSTの場合はHTTP CookieのSameSite属性に気を付けろ

昔SessionManagementあたりのサンプル実装をしたことがあったのですがどっか行ってしまったので、またどこかのタイミングで動作確認ができる環境を用意したいと思います。

ではまた!

f:id:ritou:20200821032656p:plain

認証機能を独自実装する代わりにIDaaSのREST APIを使うアプローチ

こんにちは、ritou です。

最近のあれこれでIDaaSと呼ばれる機能に注目が集まっているような気がしますが、どうしてもフロントエンドでの導入部分が目に付きます。 「新規サービスで使っていこう」ならまだしも「既存のを何とかしたい」みたいな場合にフロントエンドまでごっそり変えるのなんて腰が重くなって仕方ない感じでしょう。

そこで今回は、REST APIを用いた新規導入、移行というアプローチもあるのかなという話を書いておきます。

IDaaS の REST API

この辺りをみてみてはどうでしょう。

APIベースで登録/ログイン/パスワード変更など結構揃っている印象です。 Firebaseだとソーシャルログインも実現できそうですし、Auth0のはまだあんまりじっくりみてないですがMFAとかも書いてあります。 あとはCognitoなんかもAPIいっぱいありますよね。

導入方法

このようなREST APIでは

  • UIを自前で用意
  • 受け取った値をさばくバックエンドの処理をREST APIで実現

という感じになりますね。それこそDeviseでやってたところをこのREST APIを使うパターンです。 サービスの種類は違いますがAuthleteはこれで認可サーバーを作っていく形ですね。

SPAかどうかにもあまり依存せずに使えそうですし、フロントにIDaaSのSDKを入れてガッツリUIレベルまでIDaaSに従う実装よりも自然に導入できそうな気がします。 私自身、自前でいくつか認証機能、基盤の開発をやってきた中でまだガッツリこの方式で作り込んだことはないんですが、やるとしたらこのアプローチかなと考えています。

IDaaS導入における不安要素にIDaaSが落ちたらどうする問題があるかと思うんですが、例えばREST APIを用いて取得したユーザー情報を "外部サービスであるIDaaSからの認証結果" と捉えてセッション管理などを自前にする設計パターンもあるんじゃないかと。 万が一IDaaSが落ちてたとしてもエラーハンドリングというかConfig設定とかで一時的にIDaaSに流さないようにし、登録済みメールアドレスなどを用いて自前でリカバリーというか暫定的な認証機能を提供するような感じならそれほどリスクなくできそうかなー、いやでもやっぱめんどくせーなーなどと思いながら引き続き検討してみるつもりです。

IDaaSにとってそれを使うサービスはどんな役割なのかを意識しよう

例えばOpenID Connectでいうところで ”IDaaSがOP、利用サービスがClient" という立場であるように考えがちです。 今回紹介したREST APIを使うイメージとあっているでしょう。

しかし、フロントエンドのSDKなどを使う場合、セッション管理のあたりまでJSでできてしまいます。 IDaaSの責務でセッション管理までする場合、利用するサービスが行うべきことは「現在ログイン中のユーザーを把握してそれに対するリソースアクセスを提供する」ということになり、役割としては利用するサービスのSPAがClient、バックエンドサーバーがResource Serverとなります。

IDaaSを効果的に使っていくためにはこの辺りも意識して設計/実装を進める必要があるでしょう。

まとめ

  • REST API結構ある
  • フロントエンドをあまり使わずにバックエンドで導入していくアプローチもあるのではないか
  • 自分はClientを作るのかResource Serverだけにするのかというレベルの検討も必要そう

おまけ

Firebase AuthnのAPIに「OAuth認証情報でサインインする」というのがあります。

https://firebase.google.com/docs/reference/rest/auth#section-sign-in-with-oauth-credential

いわゆるソーシャルログインをAPIベースでやろうとするものですね。

過去にネイティブアプリとバックエンドサーバーをOAuth 2.0のClient/Serverとして作り込まれたプラットフォームに関わっていたときに、ネイティブアプリでのソーシャルログイン実装でこのような独自拡張を実装したことがあります。

メンテナになってるPerlのOAuth 2.0 Serverライブラリである OAuth::Lite2 にはその痕跡が残されています。やりたい放題でした。

Changes - metacpan.org

0.09 2014-07-22T07:36:43Z
    - rename grant_type to external_service
    - rename params for grant_type=external_service
 
0.08 2014-06-03T07:54:41Z
    - add support for new grant types
        - "urn:ietf:params:oauth:grant-type:federated-assertion" : obtain access_token from external service assertion

GrantTypeにソーシャルログイン用のものを作成して、例えばGoogleなどから受け取ったAT/RT/AuthzCode/IDTokenなどを送ってログインさせようというものです。 オレオレ拡張仕様のメモ:

social_login_bearer_profile_for_oauth2.md · GitHub

このように、APIベースでもソーシャルログインなど実装できるものはたくさんありますので、今回紹介したREST APIを使ったアプローチを検討してみてはいかがでしょうか。

ではまた!

f:id:ritou:20200819131651p:plain

Capability URLsをBearer Tokenと捉えた場合のJWT適用の可能性

f:id:ritou:20200812192943p:plain

こんばんは。ritouです。 少し前に、このようなスライドを見かけました。

docs.google.com

今回はこのCapability URLsにJWTを使ってみてはいかがかなというお話をします。

Capability URLs as a Bearer Token

挙げられている特徴や要件として

  • 推測できてはいけない
  • URLとして適切な長さ(ブラウザによって処理できないやつが出てこない)

ぐらいで、"えいち、てぃー、てぃー、ぴー、..." とラジオのDJが番組内で紹介できるぐらいの短さを求められたりしないのであれば、OAuth 2.0のBearer Tokenの要件と同等に捉えることもできそうです。

qiita.com

JWTの適用

JSON Web Token、正確には JSON Web Signature を使うことで

  • 構造化されたデータを文字列にできる : リソースに一意に紐づけられるだけでなく、ちょっとしたパラメータを加えられる
  • 改ざんされていないことを検証できる : 第3者が有効なURLを生成しにくい

という特徴を利用できます。

JWTといえばステートレス信仰が湧き上がって来るわけですが、ここでは一旦おいておきます。 JWTをCapability URLsに利用する際のポイントを整理すると

  • 元々設計されているリソース識別子のエントロピーに影響しないURLが作成可能 : 任意のURLにアクセスできる確率の話は署名の方に依る
  • 同じリソースに対して細かいパラメータを加えてやれば有効期限などのちょっとした制御もできる
  • 無効化などの管理もJWT自体の識別子や全体のハッシュ値などを使えば それなりにできる

となるでしょう。 当然、

  • JWTのPayloadに含まれる情報には気をつける必要がある(見られたくないデータは含まない)
  • Payloadにたくさん入れすぎるとURLが長くなる(CWTワンチャン?)

というあたりには気をつける必要があるわけですが、十分実用に耐えうるのではないかと思います。

まとめ

  • Capability URLs も Bearer Token の要件に近いのではないか
  • JWTを適用することで得られるもの、気をつけるべき点をざっくり整理した

という感じです。 この手の機能の設計を行う際に、JWTの適用も選択肢に加えてみるのもいかがでしょうか?

それにしても私が数年前から罹患しているこの「何でもJWTで解決しようとしてしまういわゆるeyJ病」なかなか厄介です。 ではまた。