プラットフォームアカウントに紐づけられたクレデンシャルを利用するユーザー認証について

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

何の話?

最近のユーザー認証を取り巻く状況について、次の2つの事例の共通点を考えましょう

  • Passkey(FIDOアライアンスが言ってるMulti-Device FIDO Credentialsの方)はFIDOクレデンシャルがApple/Google/MSといったプラットフォーム(など)のアカウントに紐づけられる仕組み
  • Google Authenticator のクレデンシャル管理がデバイス単位からGoogleアカウントに紐づくデバイス間で同期されるように変わる

これらは "クレデンシャル" と呼ばれる、秘密鍵やパスワードなどの "認証のための情報" をデバイス単位ではなくプラットフォームアカウント単位に保存/管理するというお話です。

そのおかげで、新しいデバイスを使い始める際にこれまで利用してきたサービスに対して色々と設定しなおすことなく、AppleGoogleアカウントを設定してゴニョゴニョするだけで今までのデバイスと同様に利用できますよ、というのが謳い文句となっています。

本投稿では

  • 「プラットフォームアカウントに紐づいたクレデンシャルを利用する認証デバイス」をどう捉えるべきか
  • プラットフォームアカウントとのID連携との違い

について考察します。

Google AuthenticatorのE2EEの話はしません

認証方式とクレデンシャル管理

世の中で使われているいくつかのユーザー認証の説明において、いわゆる認証要素と呼ばれるもので分類されることがあります。 私たちは以下の3つの中のどれか、もしくは組み合わせによってユーザー認証の特徴を表現してきました。

  • 記憶 : Something You Know(SYK)
  • 所持 : Something You Have(SYH)
  • 生体 : Something You Are(SYA)

パスワード認証はSYK, SMS OTPや公開鍵暗号を用いた認証方式はSYH, 指紋や顔を用いたいわゆる生体認証はSYAに分類されます。 FIDOでは、公開鍵暗号方式(SYH)とローカル認証(SYA or SYK)が組み合わせられることで高い認証強度を実現できていると説明されています。

ここまでのところでは、それほどプラットフォームアカウントの概念は出てきません。 そこで一段深掘りして、このようなユーザー認証を実現するためのクレデンシャル管理に着目した時に出てきます。

  • パスワード認証 : 人体の記憶領域、パスワードマネージャー、デスクトップに貼られた付箋、エンディングノート
  • TOTP : 設定したデバイス、もしくはプラットフォームアカウントや専用アプリのアカウントが所有する複数デバイス
  • FIDO/Passkey : 端末やセキュリティキーのTPM、もしくはプラットフォームユーザーのクラウドストレージ

このクレデンシャル管理の多様化によって影響を受けるのが、最初に挙げた3要素の中の所持要素(SYH)です。 クレデンシャルの保存箇所について、当初はユーザー本人の記憶や設定したシングルデバイスのみに保存されている前提が一般的だったと思います。 複数デバイスで(暗号化を駆使しつつ)の同期について語られることが増えたのは、パスワードマネージャーやTOTPでAuthyのような専用アプリが登場したあたりでしょうか。 現状はパスワードもChromeSafariのようにブラウザに関連するプラットフォームアカウントに紐づけて保存する仕組み、1Passwordのようなアプリのアカウントに紐づく管理はもはや普通に行われていますし、PasskeyやGoogle Authenticatorの動向からもその勢いが加速していることがわかります。

プラットフォームアカウントをキーとしてクレデンシャルを奪われるリスク

このようなクレデンシャル管理は端末が壊れた時や新規端末を使い始めたときにとても便利です。しかし、クレデンシャルの漏洩というリスクを考えると頭を抱えてしまうこともあるでしょう。 具体的にいうと、これまで想定されていた "デバイスのコントロールを奪われる" リスクに加えて "プラットフォームアカウントを奪われる" リスクについても考慮する必要が出てきます。

もうちょっと細かい話をすると、"複数デバイスにクレデンシャルが保存されている状態" と "プラットフォームアカウントに紐づけられた複数デバイスでクレデンシャルが同期されている状態" は特性が異なります。 "複数デバイスに..." は単純に管理しなければならないデバイスが複数ある話なのでいずれかのコントロールを奪われることだけがリスクとなるわけですが、"プラットフォームアカウントに..." はプラットフォームアカウント自体のクレデンシャル管理が一番の肝となります。

C向けのサービスであればユーザーの責任でこの辺りちゃんとやってねとなるのかもしれませんが、B向けのサービスとなるとデバイス管理の方法というところから考慮が必要となるでしょう。

これまでも議論を呼んでいたメールOTP

これまでの人生において、いくつかのユーザー認証の方式を比較しながら説明してきました。その中でたまに議論になっていたのが "メールOTP" の扱いです。 ユーザー認証を要求するサービスは対象アカウントのメールアドレス宛にOTPを送信し、受信したOTPを画面のフォームなどに入力することで認証する方式です(リンクを踏ませるものもありますがその辺はおいておきます)。

この認証方式を SYH と捉える場合、所有しているのは "メールを受信できる環境" です。 SMSの場合、"SIMが設定されてSMSを受信可能なデバイス" とすると(通信網に依存はするものの)一意に識別可能な端末として扱えますが、メールに関してはメールアプリに "メールアカウントが設定されている端末" となります。 そのメール設定のためにはメールアカウントのクレデンシャルもしくはメールアカウントを提供するサービスとのOAuthによる設定が必要ですし、その対象はシングルデバイスではなく複数デバイスメーラー、そしてWebアプリだったりもします。このため「メールOTPはSYHの扱いとしてどう扱うべきか」みたいな議論は以前からありました。

今回の "プラットフォームアカウントにクレデンシャルが紐づく" ユーザー認証についても、上記の."メールアカウント" の話に近いものがあります。 ここで "メールアカウントやプラットフォームアカウント、専用アプリのアカウントの認証強度とは?" を詰めていけば全て整理できるのではと考えたくなるのですが、メールアカウントの例で設定方法がパスワードからOAuthの形式に変わったりしてメールアカウントのユーザー認証と分離されるようになったように、 "プラットフォームアカウントがどの認証方式を採用しているのか" というところに依存することで認証強度の解釈が多段というか複雑になり、統一的に語れなくなるでしょう。 よって、今後は "プラットフォームアカウントに紐づく" というクレデンシャル管理のパターンをしっかり定義して、使っていく必要があるででしょう。

プラットフォームアカウントによるID連携との違い

Apple信者という言葉はなんだか信仰のなんたらを意識してしまいそうなので、例えばGoogleプロダクト大好きさんがいたとします。

  1. Google Chrome にパスワード、Google AuthenticatorでTOTPのSecretを保存した状態で2FAでログインする
  2. Android で同期しているパスキーを利用してログインする
  3. Sign In with Google(ID連携)でログインする

これらのユーザー認証はいずれもクレデンシャル管理をGoogleアカウントが支えている状態なので、Googleアカウントがあれば新しいAndroid端末からすぐにこれらのユーザー認証を利用できます。では、1,2 と 3 の違いは何があるでしょうか?

  • 認証方式の違い : 1,2 は認証を行うサービス側からパスワード、TOTP、FIDOという方式を固定してユーザーに要求しますが、3はどの認証方式を利用するかはプラットフォームやユーザー自身により決められます
  • 他プラットフォームアカウントの利用 : 1,2はAppleプロダクト大好きさんであればSafariAppleアカウント、iCloud Keychainのパワーで同じようなことができますが、3はサービスがSign In with Appleに対応する必要があります
  • プラットフォームアカウント情報のやり取り : 3はOIDCの仕組みなどによりプラットフォームアカウントの属性情報をサービスに渡せますが 1,2 は基本的にそれができません。

というところで、1,2はユーザーから見たらプラットフォームアカウントに依存しているがサービス側からは見えない、言うなれば "シャドーID連携" といった感じに見えます。特定のOSやブラウザ、アプリの組み合わせによってはID連携と似たようなUXとなることはあるものの、細かい違いがあること、そして逆にプラットフォームアカウントによるSPOFを避けるためには、パスワードと2FAで利用するクレデンシャルが紐づけられているプラットフォームアカウントを分けるという方法もあるということを意識しましょう。

ユーザー認証に関わるガイドラインについて

ユーザー認証というかIdentity管理について様々な仕様から参照されているガイドラインは "NIST SP 800-63 Digital Identity Guidelines" です。現行のものは63-3というもので、63-4が現在策定中です。

OpenIDファウンデーション・ジャパンによる翻訳に参加された方のTweetで63-3と63-4で今回の話と関連する記述の変更がされているようでその影響ではないか、という意見が見られました。

対象はSP 800-63B Authentication and Lifecycle Managementというドキュメントです。 63-3では複数デバイスでの秘密鍵保持に対して否定的でした。

OTP authenticators — particularly software-based OTP generators — SHOULD discourage and SHALL NOT facilitate the cloning of the secret key onto multiple devices.

63-4ではデバイス変更時にユーザーアカウントに紐付け(て移行し)、古い方消せみたいな雰囲気の記載になっています。

If a subscriber needs to change the device used for a software-based OTP authenticator, they SHOULD bind the authenticator application on the new device to their subscriber account as described in Sec. 6.1.2.1 and invalidate the authenticator application that will no longer be used.

表現の仕方が変わったとはいえ、あまり複数端末でクレデンシャルを同期してどっちもアクティブなまま使えることまでは想定していないように見てとれます。

繰り返しになりますが今までもTOTPを複数デバイスで使える仕組みはあったわけですし、個人的にはこの記載の変更によりGoogleが対応したというよりは時流の流れをNISTが少しだけ汲み取ったという方が適切な気がしています。

今後はシングルデバイスなのかマルチデバイスなのか、それをアプリやプラットフォームアカウントが仲介するのかによって認証強度(AAL)の定義が変わったり、NISTの定義を参照しつつ「この処理を行うサービスではこのような仕組みを利用してはいけない」と言った細かい整理が行われる可能性もあるでしょう。

まとめ

ざっくりまとめると次のようなところでしょうか。

  • クレデンシャルの保存がシングルデバイスからアプリやプラットフォームアカウントへと拡張される事案が増えてきた
  • いわゆる認証の3要素の所持要素の部分に影響する話であるが、単純な複数デバイスにクレデンシャルを保存されている状態とも話が違う
  • NISTの定義も認証アプリをプラットフォームアカウントと紐付けて移行することについての記載がありこの辺りの潮流を意識している気はするが、今後より整理が行われるのではないか

この話をすると「巨大プラットフォーマー、特にモバイル端末を持っているAppleGoogleへの2極化が進んでいるように見える」という感想をいただくことがあります。全てを握られている感は気になるものの、"シャドーID連携" と表現したようにプラットフォームアカウントの管理だけ頑張れば良い仕組みと言い換えることもできるので、今後も動向を見守りたいと思います。

ではまた。

「使える人にだけ使わせる」 ~ マネーフォワード IDのログインUXから見るパスキー普及のポイント

ritouです。

いよいよドコモさんもパスキー対応が始まりましたね!いや、これを書いている時点ではまだです。

k-tai.watch.impress.co.jp

それよりも、今回はマネーフォワード IDのパスキー対応に注目します。

corp.moneyforward.com

(4/5追記) マネーフォワード側からも解説記事が出ていました。この記事で言いたいことが全部書いてあります。

moneyforward-dev.jp

ブラウザのパスワードマネージャー機能を利用したパスワード認証のUX

パスキー対応に触れる前に、マネーフォワードIDのパスワード認証のUXから見ていきましょう。

マネーフォワードの「メールアドレスでログイン」のフローを何も考えずに使うと、最初にメールアドレスを入れてからパスワード入力を求めるUXになっています。

このようなUXでブラウザのパスワードマネージャーの機能を使う場合、まず思いつくのはパスワード入力欄が自動的に埋められるパターンですね。

例えばGoogleなども同じようなUXを採用していますが、パスワードマネージャーで複数のクレデンシャルが保存されている場合、メールアドレスの入力欄とパスワードの入力欄でそれぞれ選択するという謎UXに出会うことがあります。(ローカル認証が求められるかどうかなど、ChromeSafariで挙動が違うところもあるかもですが)

マネーフォワードの場合は、メールアドレス入力欄でパスワードマネージャーのクレデンシャル選択を行うと、スーっとログインできます。

これはメールアドレス入力フォームのところにもパスワードのinputタグを持つことで実現できます。

この辺りのブラウザ機能の使い方は参考になるものだと思います。

パスキーでパスワードマネージャー機能を使うための仕組みである "Autofill"

次にパスキーでログインする部分のUXに触れます。

■「パスキー」ログインのご利用方法 下記URLからログインのうえ「パスキー」をご登録いただき、その後「メールアドレスで認証」を選択してください。 URL:https://id.moneyforward.com/webauthn/credentials

上記のパスワード認証でログインした後に、パスキーを設定してみましょう。

設定のところは現状のよくあるUXなので詳細は省略します。

先ほどのメールアドレス入力画面を見てみると、パスキーを設定したことで変化が見られると思います。 Chrome @ MacOS だとこんな感じです。

Safari @ MacOS だとこうなります。

ここでパスキーのクレデンシャルを選択することで、ローカル認証が要求されてログインできます。 Chromeは同等の扱い、Safariはパスキー優先に見えますがパスワードでログインすることもできます。

このように、ブラウザのパスワードマネージャーの機能をうまく利用しているのがマネーフォワード IDのパスキーでログインするUXの特徴です。このようなUXを実現するために使われているのがAutofill / Conditional UIと呼ばれる仕組みです。

web.dev

「使える人にだけ使わせる」を実現する難しさ

これまで、パスキーでログインさせるUXというと、次の2つがあったと思います。

  • "Identifier-First" メアドなどの識別子を入力し、サービス側でパスキーが設定されていたら要求
  • "Identifier-Less(と自分が勝手に名付けて呼んでる)" 「パスキーでログイン」みたいなボタンを押すとサービス側は誰かわからないまま認証を要求

Yahoo! JAPAN は "Identifier-First" 方式を採用しています。また、後者もイメージしやすいのではないでしょうか。

これまで認証関連の登壇をしてAutofillの機能に触れる際は、"Identifier-First" もしくはユーザー識別子とパスワードを同時に入力させるようなUIからパスキーでログインさせるためのショートカット的なものを実現するための仕組みとして紹介してきました。 しかし、今回のマネーフォワード IDの実装をみると「使える人にだけ使わせる」を実現するための現状唯一の方法としてAutofillを採用するものありだと思っています。

"Identifier-First" な方式の場合、次のようなケースでパスキーが見つからないエラーが起こり得ます。

  • パスキーを設定した端末だがその後、端末側でパスキーを破棄した
  • パスキーを設定した端末とは別の端末を利用している

この辺りの技術に注目している開発者ならばエラーが出てもやり直すフローが整備されていたらなんとでもなるわけですし、エンプラ向けであればマニュアルでカバーも効くでしょう。しかし、一般のユーザーであればそうはいかないですね。

セキュリティキーの利用を許可するか等にも関わってきますが、"Identifier-Less" な方式の場合、ブラウザはなんとかしてパスキーが使えないかという感じのプロンプトを出してきます。このプロンプトも一般のユーザーにとってはなかなか理解しづらいものでしょう。 また、ユーザーが興味本位でボタンを押してしまうことも考えられます。

Autofillを使うと、ブラウザ機能のパスワードマネージャーが判断して選択肢を出してくれます。 これにより、「使える人にだけ表示する」ことが可能になり、これはつまり「使える人にだけ使わせる」UXを実現できるということでしょう。

まとめ

  • マネーフォワード IDのログインUXはブラウザのパスワードマネージャーの機能を活用している
  • パスキー対応においてもAutofillという仕組みを使ってパスワードと同様のUXを実現できる
  • 現状のパスキーでログインするUXにおいて重要なのは「使える人にだけ使わせる」ことであり、ブラウザ/端末側の判断を利用することでそれを実現しようとしているように見える

今日からサポートが開始されると言われているドコモ様には期待しておりませんが、今後パスキーの採用が広まるにあたり使いやすいUXを求めた議論が深められることを期待しています。

追記 : この話についてもうちょっと詳しく2つの記事にしたものを社内ドキュメントとして残しておいたので興味のある方は入社して読んでみてください。

ではまた。

追記: はてブ コメントどうもです

メールアドレスの入力欄とパスワードの入力欄のステップが分かれている UI はSSOでIdPに飛ばすか飛ばさないかをメールアドレスでまず決めてるから、だと思ってたけどそういうことではなく?

いくつかの認証方式をサービス側で判断して要求するケースで使われていますね。(B向けだとSSOのためのドメイン判定、C向けだとY!Jのようにサービス側で認証方式を判断するケース)

パスワード入力欄最初から出しとけや

上記と同じように、識別子で判定できるようにしている中でパスワードマネージャーの利便性を活用している、という認識です。

アレ何なんだろ。「メールアドレスの入力欄とパスワードの入力欄でそれぞれ選択するという謎UX」 / パスワードのinput不可視にするのも行儀悪い。「メールアドレス入力フォームのところにもパスワードのinputタグを持つ」

ユーザー識別子とパスワード入力欄を単純に分けたような作りで、そうなっているところを見かけます > 「メールアドレスの入力欄とパスワードの入力欄でそれぞれ選択するという謎UX」

これは上述のような識別子を先に入れさせるパターンでの利便性向上を狙ったものと想像しています。 前にhidden inputで自動入力の住所などを持っていくパターンがdisられてたことを目にした記憶があるので、今後議論されていくと良さそうですね。 > パスワードのinput不可視にするのも行儀悪い。

あと、autofillに非対応環境があることについて触れるのを忘れていました。 WebAuthn対応環境=autofillが使えるわけではないので、今回のような判断をする際は考慮する必要があります。

Twitterで2FA使いたいならパスキー"も"使ったらどうかという話

ritouです。

土曜なのに騒がしいですね。

blog.twitter.com

平日じゃないとID猫おっさんがSlackで活躍できないじゃないですか。その辺考慮お願いします。

gigazine.net

gigazineの人はたくさんのTwitterアカウントを持っていることがわかりました。

気を取り直して、まずはこのカオスは何なのかを整理しましょう。

ユーザー認証の特徴

そういえば最近ユーザー認証について振り返る機会がありました。

zenn.dev

今回話題になってる

  • SMS OTP
  • TOTP
  • セキュリティキー

あたりも説明していますので参考にどうぞ。

表題の通り、必ずしも2FAを使わなくてもいいんじゃないのって話もあります。

2FA使わなくてもいいんじゃないかという話

他のサービスとの使い回しを避け、推測不可能なパスワードを安全に管理でき、フィッシングに引っ掛からない自信があれば別に2FA使う必要はないでしょう。

令和の時代でこの辺の要件を満たそうとするとはパスワードマネージャーを利用すれば安全でしょう。 Twitterの普通の使い方ならこれでいいんじゃないかと思いますし、自分も本投稿の検証が終わったら2FA外します。

そういえば、パスワードマネージャーが同期していない端末で使うんじゃという方がいらっしゃいました。 そんな人のためにID連携を使う話もあります。

GoogleAppleアカウントでパスワード認証をショートカットできる

他のサービスとの使い回しを避け、推測不可能なパスワードを思いついて設定できるが自分では安全に管理できなかったり、フィッシングに引っかかってしまうかもしれないと思ったらGoogleAppleのアカウントを使ってログインしてみてもいいと思います。 自分はGoogleどっぷりな人生なので、ログイン画面にこういうのあったら使いたくなります。

既にGoogleにログインしているとこういうのも出るかもしれません。

One-Tap SignInってやつですね。 Twitterの中ではこれはパスワード認証と同じ扱い、つまり1段階というか要素というかにあたる扱いとなるようです。

なんと、これを使うために特に必要な設定はありません。 TwitterGmailのアドレスを登録していたらそのユーザーでログインできます。 (Gmailとかだから何とかなってるけど、ID連携でメアドをキーにしてユーザーの同意なしに紐づけるのはアンチパターンだと言ってるだろ。他のところが真似するからやめろ。)

ここからは2FAの話に入りましょう。

2FAを設定したらバックアップコードを保存するのを忘れずに

TOTPでも何でもいいですが、人生色々なことが起こります。 バックアップコードなるものをもらう機会があったら、いらんと思っても保存しておきましょう。

PCのWebからであればセキュリティキーと言いつつAndroid/iPhoneなどのパスキー使えるんじゃないか疑惑

今日の本題です。

Twitterはセキュリティキーが使えるって言ってますが、PC + モバイル端末を持っている場合はパスキーが使えます。

Androidの場合

自分は普段Androidを使っているのでそこからセキュリティキーを設定しようと思ったら、Webでやれって言われました。 そして、AndroidChromeから設定しようと思ったらこんな感じになりました。

これはセキュリティキーが必要ですね。家にYubiKeyとかいう名前のやつが4つぐらいありますが出してくるの面倒なので諦めました。

PCからやってみましょう。Chromeだとこんな感じのプロンプトになります。

あっ、この「別のデバイス」...QRで繋ぐFIDOの「hybrid transports」とかいうやつです。

まずは手元のAndroidでパスキーを生成して設定してみます。 PCのChromeから使う時は、またQRコード読み取りかpush通知によってAndroidと接続し、パスキーの認証ができます。

Safariからもこんな感じでQRコードを使って接続して使えます。

次に、パスキーが設定されているAndroidでのログインフローを確認してみました。

AndroidChromeTwitterにログインしようとすると、WebAuthnで登録済みのパスキーによる認証が要求されます。 当然ながらAndroidでそのパスキーを管理しているので、これまでのFIDOのフローのようにローカル認証が要求されてそれが終わるとログインできました。(スクショなし)

AndroidTwitterアプリにログインしようとすると、一度ブラウザが開かれてそこで先ほどと同様のローカル認証が要求されました。 そこを突破すると「ログインしますか?(おそらくアプリに)」みたいな画面が出てきてアプリにもログイン成功しました。

Android複数持ちでパスキーが同期されている端末でも同じ挙動になります。

iOS/iPadOS系端末

少し話を戻して、iPadiPhoneでパスキーを生成して登録してみます。この登録のところはAndroidの時と変わりません。

次に、iCloud KeyChainでパスキーが同期されているMacOSSafariでログインをしようとすると、パスワード認証の後にローカル認証が要求されます。MacOSだけで完結するので楽です。

これもだいぶ楽。ってかパスキー使えるならもうパスワードいらない。

まとめ

  • 2FA無理して使わなくてもいいという話はある
  • PCだとセキュリティキーを選んでiPhoneAndroidで繋げられるものがある
  • Androidで生成したパスキーはhybridでPCと繋ぎつつ、Android内ではローカル認証だけで使える
  • iOS/iPadOSで生成したパスキーが同期されている端末であれば、そのままローカル認証で使える

というように、パスキー生成(登録)のところだけモバイル端末を使ってやるとセキュリティキーよりちょっと便利になりそうというお話でした。フィッシング耐性もあってTOTPをガチャガチャコピペよりは楽でしょう?

ご自身の利用環境を踏まえ、便利になりそうだったら試してみてはいかがでしょうか?何かあっても責任は取れません! 不安な時は他の認証方式も設定したりバックアップコードの保存を忘れないようにしましょう。

ではまた! おっとその前に2FAの設定を戻します。

おまけ

この認証方式の関連というか整理をしっかりして理解を深めたいと思った開発者の方に最適なイベントがあります。

openid.connpass.com

この機会に沼に足を踏み入れてみてはいかがでしょうか?

パスキー導入検討 (1) 採用スタイルと対応環境

ritou です。

今年2023年、いよいよパスキーが本格的に利用され始めるとお考えの方もいらっしゃるでしょう。 果たして「パスワード認証に代わりパスキーが使われ、パスワードレスな時代へと突入する」という予想は現実的なのでしょうか? この記事ではサービスにパスキーを導入するために最初に何を考える必要がありそうかというところから整理していきます。

ここではこれまでパスワード認証やID連携(ソーシャルログイン)を利用してきたサービス、それらと同様の新規サービスあたりを想定しています

パスキーの採用スタイル

「ユーザー認証の方式としてパスキーを採用する」と言っても、いくつかのスタイルがあります。

  1. メインの認証方式として採用
  2. オプショナルな認証方式として採用
  3. 採用しないが、採用しているIdPとID連携する

サービスがパスキーの恩恵を受けるために、どのスタイルを採用するかを最初の方で考える必要があるでしょう。

1はまさに「パスワードを置き換える」というイメージに近いかと思います。 これが理想な姿であるのでしょうが、これを実現するためにはサービス、アプリが必ずパスキーが動作する環境にある、もしくは対応している端末と接続できるような環境である必要があります。

2は他の認証方式との組み合わせのイメージです。

  • 1を目指す上で徐々に移行
  • 認証強度の高いIdPとのID連携がメイン、それを使いたくない/バックアップ用途としてユーザーが利用

などがこれに当たるかと思います。

1,2のいずれかが採用スタイルになるかと思いますが、あえて3を追加しています。 FIDOアライアンスのセミナーなどではID連携との関連はあまり語られていませんが、ユーザー認証の設計ではID連携も含めて検討する必要があるでしょう。

  • ID連携機能を提供するIdP
  • ID連携機能を利用するRP

と言う、ID連携の登場人物それぞれにおいてパスキーを採用するメリットがあります。

  • IdPがパスキーを採用 : パスキーで保護されたユーザーの情報をRPに利用できる
  • RPがパスキーを採用 : IdP上のアカウントBANや障害時など、ID連携が利用できない状態のリカバリー手段としてパスキーを利用できる

パスキーの文脈と混乱しがちですが、ID連携の文脈でApple/Google/Microsoftなどプラットフォーマーのアカウントはリスクベース認証や同一プラットフォームに接続されている他の端末を利用した認証機能など、認証強度やアカウントリカバリーの面で優れていると言われています。 そのようなプラットフォーマーではないIdPでも、パスキーを採用することでIdPのアカウントがフィッシング耐性を持てるのであれば価値向上につながると言えるでしょう。また、パスキーに対応したIdPがn個のRPと接続している状況ではそのRPのサービスもその恩恵を受けられることになります。

RP側としても上述の強度の高いIdPとID連携している場合、何かあった際のリカバリーのための認証方式としての採用が考えられるでしょう。 このようなID連携の話をする場合は "acr" や "amr" などを用いてIdP-RP間で認証強度や認証方式に関する情報までやりとりすべきであると声を大にしてずっとずっと言って来ました。今回のパスキーあたりは良い機会になると思うのでIdPを実装している開発者は考慮していただきたいと思います。

対応環境についての検討

上述の採用スタイルのうち、自分のサービスはどれに当たるのか、これで行きたいと決める際に、対応環境について確認、検討する必要があります。

  • サービスを提供する環境について対応状況は十分か?
  • 非対応環境での代替手段はあるのか?

昨年末に行われたFIDOアライアンスのセミナーでも、「(サービス名、会社名)はiOSでのパスキーサポートを表明しました!」みたいな発表がありましたよね。 例えばiOSアプリのみ提供、OSのバージョンが高く、制限があるAppleアカウントがあまり使わないようなサービスであれば、Appleアカウントによるバックアップが取られている=パスキーがサポートされていることがある程度保証されていると言えるでしょう。

悩むのは非対応環境が様々なレイヤで存在するケースですね。 例えばWebアプリケーションの場合、

  • プラットフォーム
  • 端末(ロック解除方法がどの程度用意されているか)
  • ブラウザの種類、バージョン(WebAuthn, DiscoverableCredentialsなど)

などで実際使えるユーザーがどれぐらいいるのか、使えるとしてもロック解除を使うUXがまともかどうかというのを検討する必要がありますね。現時点において、メインの認証方式として採用できるような状態にあるサービスはまだ少ないかと思います。 今後のパスキーを取り巻く状況の変化によりますが、採用スタイルとしては2を選びつつ、サービスによって1にできるかどうかを引き続き検討していく形になるのかなと思います。

まとめ

  • パスキーの採用スタイルを整理した
  • 対応環境と採用スタイルの関係を整理した
  • ID連携との組み合わせも考えるべき

というところですかね。 次回はプラットフォームアカウントとのID連携とプラットフォームアカウントにバックアップされているパスキーの似ているところ、違うところを整理しましょう。

ではまた。

IDaaSの認証機能でID連携を利用することをおすすめする理由

ritouです。

"Digital Identity技術勉強会 #iddance Advent Calendar 2022" 13日目の記事です。

qiita.com

現状、Digital Identityを専門とするような開発者がいないような場合に新規サービスを立ち上げようと思ったら、Auth0やFirebase AuthenticationのようないわゆるIDaaSを利用するのも選択肢として上がるでしょう。

いわゆるID基盤的なものを0から設計、実装できるような 俺の考える最強の...みたいなの を既に見つけてる感じの人からすると「ちょっと違う」「凝ったことやろうとすると機能というか自由度が足りない」「帯に短し襷に長し」みたいな意見が出ることもありますが、現状だけではなくDigital Identity分野の今後のトレンドを追いつつ機能追加していくみたいな長い目で見た時にはそれなりに有用なものであると思います。

今回は そんなIDaaSをおすすめするに至る考え方みたいなところ を紹介します。 内容はほとんどが 個人的な考え なので、解説記事のようなものが多い Zenn ではなくここに書いています。

1. 認証機能の自前実装よりもソーシャルログイン/ID連携

まずはここからです。いつも言ってるやつですね。

そういえば今年、10月に DroidKaigi 2022 というカンファレンスでお話をしてきました。

speakerdeck.com

前半はユーザー認証の現状に至るまでの経緯的な部分を自分の目線でまとめたもの、後半は手元のスマートフォンを用いてログインする仕組みについて紹介しました。

パスワード認証 -> リスト攻撃に対するTOTP -> スマホアプリを使ったPush通知を用いた認証 -> それらでも防げないフィッシングに対抗できるFIDO認証からパスキーへみたいな複雑な流れを側で見てきた身からすると、現世において1からユーザー認証機能を実装して運用することは大変に難しくなっていると言えるでしょう。

これまでWebアプリケーションの認証機能を実装する方法としてよくこんな分類をしていました。

  1. 何もない状態から設計/実装していく
  2. 採用しているプログラミング言語のWebアプリケーションフレームワークやライブラリを利用する
  3. 外部のSaaS(今回のIDaaSもこれ)を利用する

1で多要素認証やリスクベースなしくみを考えるには私みたいな専門家ぶったエンジニアを雇う必要があります。 となると2のように既にあるものを組み合わせていくかとなるところですが、パスワード認証 or ソーシャルログインぐらいしかなかった時代に比べて、実現したい認証機能のどこまで実現できるのか、自分が想像する挙動になるかどうか良く調査、検証した上で実装していく必要があるでしょう。となると、3でしっくりくるサービスがあったらそれを使うのも一つの手ですね。

また、2や3でも、最近は普通にソーシャルログインやID連携とよばれる機能を "普通に、そこそこ安全に" 実現できる仕組みが増えてきました。深く考え始めるとキリがないユーザー認証方式の設計について考えるのはもう大手のところに任せ、ソーシャルログイン/ID連携と呼ばれる方法でそれらのユーザー情報を利用する方が開発/運用コストともに良さそうです。これは今後パスキーのようなどんな安全な認証方式が普及したとしても変わらないどころか、より安全なIdPやユーザーが使いたいIdPを選んでID連携するような世界に近づくのかなと思っています。

2. 認証以外にもあれこれ必要なID管理機能

ソーシャルログインでユーザー認証機能が実装できたところで、そもそもそれだけ実装したらいいわけでも無いのが実情です。 新規登録から退会まで、いやその先もまだあるかも知れませんが、いわゆるID管理といった機能が必要となります。 昔は良い意味での疎結合的な割り切りで各種トークン取得のところまでしかしないライブラリがあってそこと自前のID管理の仕組みをつなぐ必要があったりしました。今はそれなりに改善されてつなぎも楽にできるものがありそうですが、ここで変な実装をしてしまうと後で困ることになります。

この辺りは以前、記事を書きました。

ritou.hatenablog.com

ID管理における状態遷移と言ったらイメージしやすいかも知れませんが、ある程度ちゃんとしたサービスを作ろうと思うとこのIdentity Lifecycle というものを意識する必要があります。 とはいえ、この辺りはサービスに必須である機能ではあるものの、サービスが提供したい本質とは異なります。これにどれだけコストをかけられるのかを考えると、自前でやるよりもこの辺りをまとめて面倒見てくれる外部のサービスを利用した方がいいってなりますよね。

そこでIDaaSでしょうとなるわけです。 むかーしからあるmBaaSみたいにアプリのバックエンドに必要な機能を全部SaaSに任せろとは言いません。ざっくりID周りだけ頼む、他は自分たちで頑張るからってのができるのが最近のIDaaSの良い面であると思います。

3. 独自認証の選択肢、将来的な機能追加まで考える

さっきはソーシャルログインだけでいいって言いましたが、他にもありました。ごめんなさい。

ID連携って言うと、どうしても "IdPに何かあったら" "結局自前でも認証機能が必要なんじゃないの?" みたいな話が出てきます。 IdPやってるようなところが急になくなるとは考えられません(Twitterみたいに不安になることはあるかも?)が、そこのログインが一時的に止まったり、アカウント単位でBANされたりは想定しておく必要はあるでしょう。 サービスの内容によっては、その時にアカウントリカバリー用途として別の認証機能と設定変更の機能が必要になるでしょう。最近だと、TwitterでZennのGoogleアカウントの切換機能を目にしました。まさにこれの話です。

Zenn の場合は専用のメールアドレスを利用した認証を行った上でGoogleアカウントの切換と言う設定変更の機能が提供されるわけです。

IDaaSにはID連携だけではなく他の認証方式も最初から利用できるものや、その選択肢にない場合に拡張可能なところもあります。また、今はなくてもこれから勝手に対応してくれるものもあるでしょう。

最近だとパスキー/Paskey/passkeyと呼ばれる仕組みが話題ですが、IDaaSの中にも早い段階で実装してくるところ、時間がかかるところがあると思います(例えばAuth0は早そう)。

auth0.com

現在のFIDO2(WebAuthn)と呼ばれるあたりの扱いにおいても既に実装されていたり、カスタム実装で実現可能なところなどがあると思います。IDaaSの機能を利用して安全な認証方式が利用できるのであればアカウントリカバリーもしくは利便性向上あたりでID連携と併用して実装するのもありだと思います。 初期の機能開発におけるコストだけではなく、運用コスト、将来的な機能追加まで見据えてIDaaSの採用も検討してみるのも良いと思います。

PR ちょうど良い本、あるよ

そういえば "Firebase Authenticationで学ぶ ソーシャルログイン入門 ID管理の原則にそった実装のベストプラクティス" とかいう本が 昨日2022/12/12に発売された らしいです。

@authyasan が今回の記事のような話を実際に手を動かしながら実感/理解できるように書かれた本です。

自分も監修としてたくさん意見をお伝えして参考にしてもらったので、あれこれどっかで見たことある考えや言い回しだと思ってもらえるかと思います。良かったら読んでみてください。

明日のアドカレ

ついに @phr_eidentity さんの登場ですね。 DID/VCあたりの最新のお話が聞けそうです。

qiita.com

ではまた!

idcon29のY!Jの事例からログインフローにおけるWebAuthn対応の課題を考えた

ritouです。

idcon の Yahoo! JAPAN の人の資料と動画を見たメモです。

www.docswell.com

youtu.be

2画面のログインUX

p5

2画面か一回でやるかの話は、個人的にこだわっているスキャンの話もありますね。 Y!JはFederation(RP側)をやっていませんが、マネフォのようにパスワード認証/FederationがあるところにWebAuthnを追加する場合にどうすべきか、みたいなのは別途どこかで整理したい気がしています。

推測

Platform Authenticator だけはなく YubikeyとかのRoaming Authenticatorに対応してる場合、リセットした場合も同じことが起こりそう。 そもそもFIDOはブラウザ - 認証器と多段の処理になっているのでブラウザレイヤーでの完全なコントロールってのも難しそう。 例えば、AndroidChrome -> Firefoxと使っていくとCookieなどではFIDO使った形跡がないけど認証器は使えるみたいな場合があることは知られている。

BackupState

p20

複数登録させないと問題については、この値があるCredentialIdは一つでいいけど、ないやつは複数登録させたいみたいな気持ちにはなりそう。

そういえば、FIDOアライアンスが出してたこの動画にある、AndroidでcaBLE使ってログインした後にWindows側のpasskey作るみたいなUXについて、passkeyがここまでやってくれるみたいなのとこれまでのFIDO認証のプラクティス(Platform Authenticatorのある環境なら登録させちゃう)と干渉してしまう部分はありそうなので、これが更新されてどうなるのかにも注目しています。

www.youtube.com

Conditional UI 万能?

これ便利そうで注目しているものの、なんとなくですが、こいつを認証方式の分岐の主役として使うのは思うよりも難しいのかなーと思ったりします。 非対応のブラウザもあるし、Roaming Authenticatorの扱いは難しい。となるとやはりショートカットやユーザーが他の認証方式を選択した後にWebAuthnに戻ってくる経路として使う感じがいいのかなと思ったりします。

Conditional UIの課題

p39

サービス側で削除しても、認証器側ではまだ有効っぽく振る舞われる問題に関して、ユーザー識別を先にやるパターンでは excludeCredentials が使えるかもしれません。

ベターなUX

p40

この辺、Y!Jのような最短経路を提供しようと思うとなかなか困難なところはあると思います。

  • まずはベタベタなユーザー選択式のUXを用意、とにかく詰まらないように網羅的な経路を用意
  • Cookieとか前回のなんとかで推測がいけない訳ではなく、Conditional UIみたいなのはショートカットとして使っていく
  • 推測失敗やユーザーの選択ミスでこの方式が使えないみたいな残念体験は一定数存在すると想定し、そこからフォールバックの経路をしっかり用意する

ぐらいでどこまで精度を上げていけるかなのかなーと言うところですね。

こう言うのをまとめてpasskey対応とか言うのをヘルプとかで説明するの大変問題 がある。

質問 : クレデンシャル共有

合法、違法問わずパスワードでも公開鍵暗号方式でも共有されている世の中なので使われそうな気はするがサービス側の扱いは変わらなそう。

質問 : 乗っ取りリスク

これはFederationでも通ってきた道だとは思うが、ポリシー判断の際はこれまでのFIDOよりは扱いが下がるかもしれない。 金融機関で使いたい時にプラットフォーム側にAAL2以上を要求、みたいな話は難しそう。

(追記ここから) ↑をちょっと補足すると

(追記ここまで)

他にもあった気がするけど一旦ここまで。

個人的にはもうちょっと Discoverable Credentialsについての細けぇ議論があったら面白いかなと思いました。displayName変えられないとかポツポツあったけど。

ではまた。

フィッシング対策観点でメールでリンクが送られない世界を目指すために我々は何ができるか

ritou です

急に寒くなりましたね。

この記事は何の話か

最近のメール経由のフィッシングの話で、

  • その辺のユーザーにとって、メールの送信元が正規のものかどうかの確認は容易ではない
  • さらに、メール本文に含まれるURLの確認が容易ではない

という現状があります。

前者がうまいこと解決されると一番良いんでしょうけれども、そうもいかないのでしょう? 後者のところでよく「メールに含まれる怪しいリンクをクリックしないでください」と言うのがあります。 そもそも怪しいかどうかがわからないからクリックするわけなので、「怪しい」部分を説明するのも大事なことですが、細けーことは一般ピーポーには無理なので、「メールに含まれるリンクをクリックしないでください」まで振り切る方がいい気がしてます。

しかし、これはこれで

  • サービスはユーザーとのコミュニケーションツールとしてリンクを送る(クリックして欲しい)
  • ユーザーはメールのリンクをクリックせずに、お気に入りなどからサービスにアクセスして内容を確認してください

という不整合が起こり、サービスが期待する処理をユーザーが進めてくれないという事案にもつながりかねません。 こんな状況よりは、

  • サービスがメールを受け取れるユーザーにのみ可能な処理を行わせるためにリンクを送る
  • ユーザーがそのリンクをクリックして処理を続ける

というUXにリスクがある前提で話を進め、

  • メールをコミュニケーションのツールとして捉えるのではなく通知の仕組み程度の用途に止める
  • メールを受けた後にユーザーが適切に処理を継続させられるような誘導ができる世界を目指す

ような変化をしていくという方向性も検討する余地があるのではと思っています。

そこでこんなTweetをしてみました。

我々一般開発者がワーワー声を上げても基本的に何も起こらないもので、セキュリティに詳しい人の集まりでこの辺りが少しでも話題になることがあって何かしらの反応や動きにつながったら良いなと期待しております。

現状に対してこんなことしないといけないのでは?みたいな話はzennの記事で書きました。

zenn.dev

これの続き的な立ち位置で、今回は、 サービスがメールでURLを送ってユーザーがそれをクリックして何かの処理が行われるようなフローをなくすために何が必要なのか をもう少し考えてみます。

そもそもメールでリンクが送られるのはどんな時?

色々あるとは思うんですが、大きく分けて2種類あるかなーと思っております。

  • メールを受け取れるユーザーにだけ次の処理を許したい
    • パスワード再設定リンクを送信
    • マジックリンクでログイン
  • 何かを伝えたい
    • メッセージを受信しました + リンク
    • サービスからのお知らせとか + リンク

他にあったら教えてください。

代替案

メールを受け取れるユーザーにだけ次の処理を許したい : リンククリック -> OTP送信

「メールを受け取ったことを確認したければ、OTPを送ればいいじゃない」 という案です。

OTPを使うと、厳密には「今画面を操作しているユーザーがメールを受け取ったこと」を確認できるのでいわゆる経路外認証としてログインで使われていたりもします。 あと、動線がメール受信後のリンククリックの後にで分かれてしまうのも避けられるので、使い所によってはその後の繋ぎが便利になるかもしれません。 面倒な点といえばOTPのコピペですが、そこはWebOTPで頼む、ということですね。

何かを伝えたい : サービス内コンテンツへの誘導リンク送信 -> お気に入りなどから確認を促す

これもよく言われていることですが、実際は結構辛い気がします。 お気に入りからって言いますけど、お気に入りそんなにちゃんと使われてると思いますか? ってことで、この辺りもう少しいい感じにできないのかなーと前に思ってたことを思い出しました。

まずはブラウザについてですが、例えば Google Chrome とかだとブランクなページを開くと最近使ってたサービスみたいなのを表示してくれたりしますよね。自分ので試したら Gmail / Twitter / GitHub / 自分のブログ ... みたいな感じでした。これも履歴みたいなもんではありますが、このようにざっくりでいいのでサービス単位の管理ができれば良いのでは?と思います。

その上で、サービスは次のような自サービスのメタデータを定義しておき、そこにリンクできる HTTP Header なり meta タグなりを仕込みます。 メタデータの扱いについてはこれまでもいくつかのWeb標準APIなどで利用しているものもあると思いますし、それを束ねる仕組みもできそうです。

あとはブラウザはそのメタデータを読み込みに行ったりキャッシュしたりして、ユーザーを期待するページに誘導可能なのではないか?と言う案です。

  • トップページ
  • お知らせ一覧 : 重要なお知らせがあることをメールで通知しつつここから誘導を試みる
  • ヘルプ / 問い合わせ
  • 利用規約 / プライバシーポリシー : ●●が変わりますメールを送りつつ実態はここから誘導を試みる

画像はイメージです。

なんとなく、こんな感じならお気に入りよりももうちょっとなんとかなるんじゃないか、そうでもないかも、みたいな感じですね。

まとめ

  • フィッシング対策とサービス側の意識の違いなんとかならんか
  • メールからリンクを無くす方法を考えてみた
  • なんだかんだでメールをコミュニケーションツールから通知ツールに格下げしようとしている私をお許しください

以上です。

はてブのコメントどうもです!

サービス登録機能はあるといいなと思うけどiGoogleがまだあれば、ほしかったなと思う気持ちがある

サービス管理のあたりは確かにあの頃欲しかったところですね。

URL入らなくなったらユーザサポートめんどくさくなるなぁという感想。

確かに、ユーザーサポートの負担を上げずに実現できる方法はもうちょっと探っていきたいところです。

今回はメールも通知目的に全振りしてはどうかな話なので、例えば今のSMSで送られる情報ぐらいには最小化できるのでは? という意図で書いています。

ヘルプデスク的な業務もしてる自分としては、FAQのここ見ろやバーンってURLを送りつける機能は残してもらいたい。

これも同意ですが、バーンと送られ的たリンクをクリックしないでください!みたいな現状は切ないので、正規のサービスとの繋ぎの部分はもう少し考えていきたいところです。

FedCM入門 その2 ~ 現状のFedCM実装解説

おはようございます。ritouです。 前回の記事に引き続き、FedCM入門です。

ritou.hatenablog.com

何の話か

6/21(火) 19時から、OpenIDファウンデーション・ジャパン主催のイベントがあります。

openid.connpass.com

明日じゃん。

これに先立って、Federated Credential Management API(FedCM) について 非公式 の入門記事を書いています。 今回は、FedCMの現状の実装について解説します。

それでは始めましょう。

登場人物

FedCMの登場人物は、わりと一般的なID連携のものと同じです。

  • IdP : Identity Provider. 他サービスに対してユーザー情報を提供する サービス
  • RP : Relying Party. IdPのユーザー情報を用いて認証機能を実現する サービス
  • ユーザー : IdP/RPそれぞれを利用するユーザー
  • ブラウザ : FedCMに対応したブラウザ

ID連携フロー

FedCMはGOALとしてOpenID Connect(OIDC)/SAMLを対象にするとか言ってましたが、今のところは RP上にID連携のためのプロンプトを出してOIDCを簡略化したような仕組みでユーザー情報を受け渡してログインさせる というのが実装されています。 言い換えると、現在のFedCMで実装されている機能はGoogleが提供するOne Tap Sign-In and Sign-Up(Twitter, Medium, 他いろんなサービスでGoogleアカウントでログインするか?って出てくるやつ)相当である ということです。

developers.google.com

はじめにFedCMを用いたID連携の流れをざっくり説明します。

  1. ユーザーはIdPにログインしている前提
  2. ユーザーがRPで "IdPでログイン" を利用しようとして、RPはFedCMのAPIを呼び出す
  3. ブラウザはIdPに対してログイン中のアカウント情報(リスト)を要求し、ID連携のためのプロンプトをRPドメイン上で表示する
  4. ブラウザはユーザーが選択したアカウント情報に紐づく認証用トークン(OIDCのIDToken)をIdPに要求し取得したものをRPに渡す。RPはそれを認証機能に利用します。

まず前提として、1. でユーザーがIdPにログイン中である必要があります。一般的なWebアプリケーションのような単一ユーザーがログインできる仕組み、もしくはGoogleのような複数アカウントでログインできる仕組みにも対応しています。

プライバシー保護の観点から、RPが"IdPに誰がログインしているか、誰もログインしていないか" を知りえる状態は良くありません。現状、IdPに誰もログインしていない場合は、RPがFedCMのAPIを呼び出しても汎用的なエラーのみが返されます。この辺、FedCMのユースケースはまた別途考察しようと思っているところですが、実際は ログイン中のユーザーがいる状態のID連携の利便性を上げるショートカット 的な感じに使われることになるのかなーというところです。

2でFedCMのAPIを呼び出す部分はこの後説明します。

3で出てくるプロンプトですが、あるユーザーが単体でログイン状態の場合は次のような画像となります。(私のメアドは公開されてるようなものなのでよし)

「続行」をユーザーがクリックすると、User-Agent は IdP にリクエストが送られ、RPにユーザー情報+認証イベントの情報を含む IDToken (具体的な内容はIdP依存だけど実質OIDC互換)が渡されます。

Googleのように同時に複数アカウントがログインできる仕組みの場合、この画面の前にアカウントリストから選択するプロンプトが入ります。

4ではRPはそれを使ってよしなにログインするなり新規登録するなりをします。ここはRPの要件に依存します。

FedCMではID連携フロー以外にログアウトだったりIDToken無効化(退会?)のリクエストを送ることも可能ですが、現状としてはここをまずおさえておけばいいでしょう。

ID連携のシーケンス

ここまでざっくり説明したFedCMのID連携フローで、実際何が行われるかは公式ドキュメントで公開されています。

developer.chrome.com

シーケンスは以下の通りです。

この図だけで大体わかっちゃう人がいたら是非一緒に働きましょう。

ここからは、公式のドキュメントや自分で作成したRP/IdPの動作例を用いて説明していきます。

0. ブラウザがFedCM対応環境環境かどうかを確認する

実際のID連携のプロダクトでは、FedCMが有効ではない環境のフォールバックも当然必要です。

  • FedCMが対応環境ならば優先的に利用
  • 非対応環境ではこれまで通りのID連携

みたいなところを自然なUXで提供する必要があります。

現状では、RPは以下のコードでFedCMのID連携フローが利用可能かどうかの判定ができます。 FedCMの名前にもなってる FederatedCredential っていう仕組みは既にあるものなので、それとloginが実装されているかを組み合わせで判定します。

if (window.FederatedCredential || FederatedCredential.prototype.login) {
  // If the feature is available, take action
}

ちょっと話はずれますが、個人的に現在の One Tap sign-in and sign-up は未ログイン状態の時にプロンプトを節操なく出してくる印象があるんですが、それと同様ではなくログインや新規登録のフローに入ったときに絞るなどの検討が必要かなという印象です。

1. RPがFedCMの関数を呼び出してID連携を要求

RPがFedCMのID連携を開始する処理は navigator.credentials.get の呼び出しから始まります。 ここでRPはIdPのURLと自分自身の識別子(clientId)を指定します。

const credential = await navigator.credentials.get({
        federated: {
          providers: [{
            url: 'https://ex-fedcm-idp.herokuapp.com/',
            clientId: 'https://ex-fedcm-rp.herokuapp.com/'
          }]
        }
    })

上記サンプル実装では、clientId にRP自身のURLをそのまま実装していますが、これはIdPが提供するClient登録機能などで払い出しされた値を指定することになります。 ちなみに、providers とあるように、ここでは複数のIdPのアカウントとの連携も視野に入れられているように見えますね。 現状の実装としては、最初の1個を読むようになってるような挙動をしていますが、ここで複数が指定されるようになったら一番最初に "プロバイダ選択" みたいなプロンプトになるのかなーという想像をしています。

FedCMではここから FederatedCredential.login() を呼び出すことでRPはブラウザはID連携の処理を開始します。

const nonce = '65a7c572-b4fc-4e27-b899-c67e12ac36a5';
const { id_token } = await credential.login({ nonce });

ここでOIDCにおける nonce パラメータを指定することで、ブラウザがIdPから取得してRPに渡されるIDTokenがこのセッション/リクエストに紐づいていることを検証可能です(いわゆるCSRF/リプレイアタック対策みたいな話)。

ブラウザがIdPに送る最初のリクエストは "Top level domain manifest" と記載されているリクエストです。

GET /.well-known/fedcm.json HTTP/1.1
Host: ex-fedcm-idp.herokuapp.com
Accept: application/json
Sec-FedCM-CSRF: ?1
$ curl "https://ex-fedcm-idp.herokuapp.com/.well-known/fedcm.json"
 -H "Sec-FedCM-CSRF:?1"
 -H "Accept:application/json"
{"provider_urls":["https://ex-fedcm-idp.herokuapp.com/"]}

ここでは、RPが指定したIdPのURLがFedCMに対応しているか、リクエストを送っても良いかどうかを確認します。いわゆるマルチテナントなIdPなどでは provider_urls の値が複数返されることになります。

その後に、ドキュメントで "IdP manifest file" と記載されているエンドポイントにリクエストが送られます。これは IdP で指定されたURLにある "/fedcm.json" というエンドポイントです。

GET /fedcm.json HTTP/1.1
Host: ex-fedcm-idp.herokuapp.com
Accept: application/json
Sec-FedCM-CSRF: ?1
$ curl "https://ex-fedcm-idp.herokuapp.com/fedcm.json"
 -H "Sec-FedCM-CSRF:?1"
 -H "Accept:application/json"
{"accounts_endpoint":"/accounts",
 "branding":{"background_color":"0xFF4500","color":"0xFFFFFF","icons":[{"size":32,"url":"https://ex-fedcm-idp.herokuapp.com/images/icon_32.ico"}]},
 "client_metadata_endpoint":"/client_metadata",
 "id_token_endpoint":"/id_token"}

このレスポンスには各種エンドポイントとプロンプトを出す際のアイコンや色といった情報(branding)が含まれます。

ブラウザはこの後、プロンプトに表示する Client 情報(利用規約、プライバシーポリシーのURL)を要求するために "client_metadata_endpoint" にリクエストを送ります。

GET /client_metadata?client_id=https%3A%2F%2Fex-fedcm-rp.herokuapp.com%2F HTTP/1.1
Host: ex-fedcm-idp.herokuapp.com
Referer: https://ex-fedcm-rp.herokuapp.com/
Accept: application/json
Sec-FedCM-CSRF: ?1
$ curl "https://ex-fedcm-idp.herokuapp.com/client_metadata?client_id=https%3A%2F%2Fex-fedcm-rp.herokuapp.com%2F"
 -H "Sec-FedCM-CSRF:?1"
 -H "Referer:https://ex-fedcm-rp.herokuapp.com/"
 -H "Accept:application/json"
{"privacy_policy_url":"https://ex-fedcm-rp.herokuapp.com/pp",
 "terms_of_service_url":"https://ex-fedcm-rp.herokuapp.com/tos"}

RP じゃなく IdP が RP の metadata を出す というところがやや引っかかりますが、まぁいいでしょう。ここで返されたURLはプロンプト内でリンクとして使われます。

また、このリクエストには当然 client_id の値が含まれますが、この後の Accounts list endpoint へのリクエストには含まれません。 IdPがClientの検証を行うには、この段階で client_id パラメータと Referer ヘッダあたりを利用して検証する必要がありそうです。

次に、ブラウザは Accounts list endpoint に現在ログイン中のアカウントリストを要求します。

GET /accounts_list.php HTTP/1.1
Host: ex-fedcm-idp.herokuapp.com
Accept: application/json
Cookie: ...IdP's Cookie...
Sec-FedCM-CSRF: ?1
$ curl "https://ex-fedcm-idp.herokuapp.com/accounts"
 -H "Sec-FedCM-CSRF:?1"
 -H "Referer:https://ex-fedcm-rp.herokuapp.com/"
 -H "Cookie:..."  -H "Accept:application/json"
{"accounts":
 [
   {"approved_clients":[],
    "email":"ritou.06@gmail.com",
    "email_verified":true,
    "family_name":"Ito",
    "given_name":"Ryo",
    "id":"google_user_114181308725730985237",
    "name":"Ryo Ito",
    "picture":"https://lh3.googleusercontent.com/a-/AOh14GjQ_fcwsIRk6LalbnjCHWzWfk7BkYvX9XAkZP8b8Q=s96-c"}
 ]
}

注目するべきは、ここで1st Party相当のCookieが送られます(6月頭の時点ではSameSite=None(3rd Party相当)のものが送られるようになっているので Issueで連絡済みでしたが今確認したらStrictでもいけました!) RPはFedCMのAPIを利用するだけで、IdPも1st Party相当のCookieのみで利便性の高いID連携を実現できるのがポイントですね。

レスポンスにはログイン中のユーザーリストが含まれ、ユーザー情報としてはユーザー識別子、メールアドレス、名前、プロフィール画像などが返されます。

2. ブラウザがユーザーにIdP/RPのアカウント情報、

概要で説明した通り、ここで複数のアカウント情報が返されたらブラウザはリスト表示、単一の場合は同意のプロンプトを表示します。

3. ブラウザがIdPにIDTokenを要求

ユーザーがブラウザのプロンプト上でID連携することに同意したら、ブラウザはIdPに対象ユーザーのIDTokenを要求します。このリクエストにもIdP向けのCookieが含まれます。

POST /id_token HTTP/1.1
Host: ex-fedcm-idp.herokuapp.com
Referer: https://ex-fedcm-rp.herokuapp.com/
Content-Type: application/x-www-form-urlencoded
Cookie: ...IdP's Cookie...
Sec-FedCM-CSRF: ?1
account_id=google_user_114181308725730985237&client_id=https://ex-fedcm-rp.herokuapp.com/&disclosure_text_shown=true&nonce=1c64ca07-90f8-4eee-b3d4-d0eb871ea816

IdPは対象ユーザーのIDTokenをJSON形式で返します。

{
  "id_token": "eyJ********"
}

4. RPはIDTokenを受け取って認証処理などを行う

RPはブラウザから受け取ったIDTokenを利用して認証処理を行います。 呼び出したときのコードを振り返りましょう。

const nonce = '65a7c572-b4fc-4e27-b899-c67e12ac36a5';
const { idToken } = await credential.login({ nonce });

ドキュメントには { id_token } とありますが現状のChrome Canaryの実装では { idToken } で取得できます。これもそのうち治るでしょう。

この辺りは、RPにとっては、OIDCのImplicit Flowと呼ばれるものと同等の処理です。 細かい違いについては別記事で説明予定ですが、OIDCのIDTokenはJWT形式の文字列であり、次のステップを踏むことで検証できます。

  1. 署名が正しい
  2. iss パラメータがIdPのものである
  3. aud が自身のものである
  4. exp が有効期限内である
  5. nonce が "1. RPがFedCMの関数を呼び出してID連携を要求" で指定したものである

このような検証ステップを終えたら、RPは自サービス内のログインや新規登録処理を行います。

まとめ

今回はFedCMのID連携のフローで送られるリクエスト/レスポンスを説明しました。 ユーザーからの見た目はプロンプトが表示されてそこからID連携が行われるだけですが、裏側でいくつかの処理が行われています。

ここまでの流れはAndroid/PCの新しいChrome Canaryで動作確認できます。

興味があったら試していただいて、気になることがありましたらコメントしてください。

次回予告

現状、FedCMは OIDC寄り の仕様になっているものの、ブラウザ-IdP間のリクエスト/レスポンスはFedCM独自のものです。 特に既存のOIDC IdPの方がこれに対応した実装を行う必要がありますが、そのためにはOIDC/FedCMの仕様間のFit/Gapを整理する必要があります。 例えば、ブラウザのCookieを受け取りつつレスポンスの形式はJSONであるみたいな仕様はOIDCの仕様ではあまり馴染みがないものです。

そこで、次回は

  • RPがID連携を要求する部分、OIDC準拠に近づくにはどうなるべき?
  • OIDC IdPが楽にFedCMに対応するための考え方、違う部分についてはFedCMの仕様がこうなっていると捗る、もしくはOIDCにこのような拡張があると捗る

みたいなところを紹介します。

ではまた!

FedCM入門 その1 ~ ID連携の課題とFedCMのアプローチ

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

何の話か

6/21(火) 19時から、OpenIDファウンデーション・ジャパン主催のイベントがあります。

openid.connpass.com

ここで取り上げられるFedCMについて、3部作ぐらいで 非公式解説 を書いていきます。

  1. ID連携の課題とFedCMのアプローチ 今回はこれ
  2. 現状のFedCM実装解説
  3. FedCM vs OIDC 仕様の差分、RP/IdPの対応、差分解消案

上記イベントでの自分の発表内容は2,3あたりになる予定です。

FedCMとは

FedCMについては、4月末ぐらいにいろいろなドキュメントが公開されました。 英語が読める方はこんな非公式情報を信用せずに、公式なドキュメントを読みましょう。

developer.chrome.com

FedCMで解決したい課題

現在、OpenID ConnectやSAMLを用いたID連携はわりと普及してきましたが、いくつか課題や懸念点があります。 FedCMではID連携で使われているiframe, redirects and cookiesあたりの技術がトラッキング用途のものと区別できないことを問題視しています。

Unfortunately, the mechanisms that identity federation was designed on (iframes, redirects and cookies) can also track users across the web. As the user agent isn't able to differentiate between identity federation and tracking, this makes it difficult to determine when these mechanisms are being used to support identity federation

ID連携の基本動作として、ID連携を利用するサービス(Relying Party, 以下RP)とID連携を提供するサービス(Identity Provider, 以下IdP)の間のリダイレクト、いわゆる「OAuth Dance」があります。 例えば私は Zennに記事を書いております が、Googleアカウントでのログインを始めると一度IdPであるGoogleに遷移してGoogle自体にログインしたり、ログイン中のユーザーからID連携に利用するユーザーを選択したりします。そしてID連携の際にRPに提供される属性情報やリソースアクセスに同意した上でRPに戻ってくるお馴染みのフローのことです。 開発者であれば何が行われているかを割と直感的に理解しやすいかもしれませんが、一般ユーザーはそうではないかもしれません。

このようなID連携フローの利便性を上げるため、いくつかの手法が考えられてきました。 確か2009年とかその辺り...スマホが現在のように普及する前のPC主体の頃、Googleでログインというボタンを押すとポップアップで小さめのGoogleの画面が出てきてログインやユーザー情報の提供への同意が求められ、終わったらそれが閉じて元の画面がログイン状態になるみたいな挙動が実装されました。 なんとなーくおしゃれな感じに立ち上がってくるモーダルの中でログインさせるのではなく、ちゃんとURLを確認可能にする、UIも小さな画面に最適化しつつ現在のログインユーザーやRPに渡される情報などをもれなく表示するといったUX検討が行われ、大手IDプロバイダのSDKなどで実装されるようになりました。

一方で、スマホであればポップアップの挙動が変わるのでリダイレクトでやるしかないかーみたいな話も出てきました。 ID連携だけに止まらないですが、この辺りの利便性を上げる仕組みとして、ブラウザがサポート用のプロンプトを出すような流れが出てきました。 ID連携においてはRPにいる時点でIdPにログイン中のユーザーでログインしますか?みたいなプロンプトを出す仕組みをGoogleAndroidやWeb向けに提供しています。

developers.google.com

私は普段、複数のGoogleアカウントを区別するためにChromeのプロフィールを利用していますが、個人のアカウント以外のところでついうっかり(本当についうっかりです)TwitterのURLを開こうとする とこんな画面になったりします。

これはTwitterドメイン上でGoogleにログイン中のユーザー情報を含むプロンプトを表示し、ワンタップでユーザー情報をやりとりすることで利便性をあげようみたいな仕組みです。よく見ると、他にもmediumとかいろんなサービスで使われていますよ。

先に紹介したポップアップやこのOne Tapみたいな仕組みを実装しようと思うと、3rd Party Cookieとiframeあたりの話を避けては通れません。Googleのサービスであれば開発者はSDKを使うだけなので意識してなかったりしますが、One Tapもブラウザの設定で3rd Party Cookieをブロックすると動かなくなります。

また、ID連携の仕様の中にはRPとIdPの間でセッション同期、ログアウト同期を行うための仕様があります。これらもフロントチャンネルでの処理ではiframe + postMessage を利用しています。

と、ここまで紹介した3rd Party Cookieを利用する仕組みですが、似たような仕組みで広告周りでユーザーの特定や行動把握のために別ドメインとやりとりしたり、リワードのために一瞬Safariを開いてみたいな実装がよく行われてきました。あれもユーザー情報を同期して何かの最適化を行おうとするものですが、ID連携とは別物です。しかし、ブラウザから見た挙動としてはどうなのでしょうか。これらはとても似ていますというかほぼ一緒、区別できません。

昨今、各ブラウザにはプライバシー保護の名の下に3rd Party Cookieを利用する仕組みを減らしたりブラウザから取れる細かい情報を減らしたりする動きがあります。FedCMを含むChromeのプライバシーサンドボックス構想みたいなのもまさにそれです。しかし上述のとおりID連携の仕組みで3rd Party Cookieに依存するものがあるので、3rd Party Cookieが廃止された世界ではそれらは当然動かなくなります。これはなんとかしないといけませんってなるわけですね。

そこでFedCMですよという話です。

FedCMのアプローチ

FedCMの目的は「3rd Party Cookieを廃止してもID連携の仕組みが動く世の中にしよう。必要に応じてブラウザが仲介することでプライバシー面のリスク低減を目指そう」あたりにあります。

The Federated Credential Management API (FedCM) provides a use case specific abstraction for federated identity flows on the web. This purpose-built API allows the browser to understand the context in which the RP and IdP exchange information, inform the user as to the information and privilege levels being shared and prevent unintended abuse.

具体的には次回以降の記事で書く予定ですがざっくりと

  • ID連携にもブラウザが仲介するぞ!
  • RPはブラウザのAPIを呼び出してID連携を要求
  • ブラウザはIdPに対して1st Party Cookie相当のリクエストを送る
  • ブラウザはユーザーのアクション(ユーザー選択や利用の同意)に基づいてIdPから取得した情報をRPへ提供
  • ログアウトやID連携の無効化などもブラウザ経由でRPからIdPに伝えられるようにする

あたりがFedCMの現在のスコープとなっています。

ブラウザが仲介して1st Party Cookieとしてリクエストを行う部分については上記3rd Party Cookie廃止の流れへの対応そのものですが、IdPとしても他のドメインからセッションCookieを参照できなくできることはセキュアになるために喜ばしいことでしょう。 ユーザーアクションに基づいてRPに情報開示が行われる部分は既存とそれほど変わらない気はしますが、その辺り配慮してますと言うのはなんとなく伝わってきます。

実装面で言うと、WebAuthnやWebOTPも同様なのですが、ブラウザがプロンプトなりを出してくれる仕組みの場合はJavaScriptなどでしっかりSDKを作り込まなくても比較的容易にRPが実装可能(もちろんそれをラップしてSDKを提供するのはあり)と言うのが大きいでしょう。

現状のFedCMとChromeの実装状況について、ID連携と書いた部分については上で紹介した One Tap 相当の最低限のログインに必要なユーザー情報のやり取りが実現できるところまで実装されています。PC/Android版のChrome Canaryで動作しますので、次回の記事で紹介します。 正直、ここからOIDC/SAMLがフル互換で動く状態になるまでは時間はかかりそうですが、その辺りの考察も今後記事にする予定です。

次回予告

FedCMの現状の動作と裏でどのような処理が行われているかを説明します。

21日までに3つ記事出せるのだろうか???

ではまた!

FIDOの最新動向から考える巨大プラットフォーマーとの関係

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

Google I/O の "A path to a world without passwords" っていう発表、ご覧になりましたか?

www.youtube.com

FIDO, WebOTP, FedCM...いいネタ揃ってますね!今回はFIDOの話をしましょう。 パスワード認証はもう終わり!時代はパスワードレス認証ですよと言い続けてはや数年経ちましたが、最近こんなプレスリリースが出ていました。

prtimes.jp

すべての人にとってウェブをより安全で使いやすいものにするための共同の取り組みとして、AppleGoogleMicrosoftは本日、FIDOアライアンスとWorld Wide Web Consortium(以下、W3C)が策定した共通のパスワードレス認証のサポートを拡大する計画を発表しました。

何やら大ごと感ありますが、3行でまとめると

  • FIDOは指紋認証などのローカル認証と公開鍵暗号方式を組み合わせた仕組みである
  • FIDOの最大の特徴は それぞれの認証器(セキュリティキーもしくはPCなどの端末にしか存在しない秘密鍵 を利用することであるが、それ故にロスト時のリカバリーや新規端末利用(機種変更など)時に全ての利用サービスで再登録が必要ってところに課題があった
  • Apple, Google, MSなどがプラットフォーマーの強みを活かしてその辺うまく同期する仕組み作ったら課題も解決して便利になるな!ついでにだけど、パスワードに対してパスキーって呼ぶぞ!

といったところです。

1番目はおいておいて、2番目はこれまで段階的にホワイトペーパーなどが出ていた部分ですね。別記事で取り上げました。 今回は3番目を強く全面に押し出してパスワードレスやっていき!みたいなところを印象付けてきているように見えます。それ実現できたらすごいことになるよな!書かれている通り理想を実現できればな!そんなに上手く行かんだろうけどな! っと言う部分を含め、今回はApple, Google, MSといった巨大プラットフォーマーとFIDOの関係について整理します。

これまでのFIDOと巨大プラットフォーマーの関係

FIDOというとYubicoなどのセキュリティキーが印象的ではありますが、実際は端末自体を認証器として利用できる Platform Authenticator が特にコンシューマ分野においては重要だろうと言われてきました。Platform Authenticator側、つまりPC/Mobile端末のFIDO対応みたいなところで考えると、当然Apple/Google/MSの存在を感じずにはいられないですね。**

さらにWebアプリからFIDOを利用するためのWebAuthnについて、肝となるブラウザの対応においてもSafari=Apple, Chrome=Google, Edge=MSとあとはFirefoxなどが割と頑張って対応を進めたことである程度どこでも使える状況になったと言えますがこれはまぁいいか。

一方で、これまで数年にわたりパスワードレス認証やID連携についての動向を共有したりしてきた経験から、FIDOではユーザーが単独でサイトごとに強度の高い認証方式を利用できることで、認証器さえ持っていたらこれまで巨大プラットフォーマーとのID連携を利用してリスクベースなど含めた恩恵を受けてきたところから脱却できるのでは? という声も聞いたことがあります。OpenIDなんとかな立場でID連携いいですよ〜って推していると「認証の全てを巨大プラットフォーマーに握られるのもなぁ」みたいなことを言う人がいて、FIDOならそこから脱却できるのでは?と考えてた人がいました。言いたいこともわかります。

とはいえ、全体としては なんだかんだで巨大プラットフォーマーの対応に支えられてここまで普及が進んでいる と言える気がしていたところに、今回の発表によりそれがさらに加速するのではないかなーと考えています。

プラットフォーマーの力でどこまで便利になるのか?

上述の通り、FIDOにはセキュリティキーや対応端末そのもののロストなどのリカバリー、新規端末からの登録し直し面倒問題という課題もあるわけですが、今まではそれに対応しようとすると 複数の認証器でFIDOが使えるように設定しておく みたいなところしかなく、これも上に書きましたがデバイス自身が認証器として使える端末を複数台持っているようなユーザーでない限りC向けサービスのユーザーにとっては敷居が高そうだな遠いう状態でした。

それを、プラットフォーマーの力技でサポートしていこうというのが今回の話で、この記事が割と明るいです。

www.publickey1.jp

実は各社細かい違いがあったり、得意な部分みたいなのもあるのでざっくり整理すると次のような感じを目指そう!という段階です。

  • Apple / Google / MSアカウント毎にFIDOの秘密鍵(以下、パスキー)を管理できてログイン中の端末同士では セキュアな方法で 共有でき、バックアップもとれる
  • 初めて利用する端末では Bluetoothを利用して手元のスマホから利用可能

前者は少し前に Apple が発表したものそのものです。MSも同様な仕組みをやりたそうな発表をしていました。後者はGoogleAndroid端末で進めているものですね。

zenn.dev

MSは現状のAppleのようにアカウントベースに鍵の共有ができるようになりそうな雰囲気、AppleはいわゆるApple信者的な人であれば前者のみでもOKな感じなのであまり後者の仕組みはやってこない気もしなくはない、GoogleAndroidを用いて他社のプラットフォーム上での存在感を出したいと思っているように見えつつ、一度それをやったら鍵が共有されるような機能を乗せてくるのかなというところです。

blog.google

っていう細けぇ話はありますが、巨大プラットフォーマーの対応により、それぞれのアカウントベースでの鍵管理に近づいていくように見えますね。 今後の課題はプラットフォームを跨いだ鍵管理がどのように行われるかというあたりでしょう。Android -> iPhone に変更、その逆の場合にちゃんと鍵が共有されるような世界になるかどうか、各プラットフォームの利益目的だけでは進まなそうな後一歩を踏み出せるかが重要です。

ID連携 vs FIDO(改)

FIDOが鍵管理の部分でプラットフォーマー支えられる時代が来そうとなると、ID連携との違いがまた気になってきます。

  • ID連携ではサービスはID連携の仕組みだけが必要、とはいえOIDCの接続は必要。認証はIdPで行われもちろんIdPへの認証でFIDOを使うこともできる。
  • FIDO(改)はそれぞれのサービス毎に鍵管理が必要、プラットフォーマーがその鍵管理を支えてリカバリーや新規端末利用時のユーザーの負担を軽減

プラットフォーマーが前面に出るか後ろで支えるか、みたいな話になりそうですね。

認証機能単体の利用サービスの実装負荷としてはFIDO(改)の方がApple/Google/MSアカウントそれぞれとID連携するよりは軽いでしょう。 上述の通り、ユーザーがプラットフォームを跨ぐ挙動(Android -> iPhoneに変更)した時にちゃんとサポートできるかは、もう少し詳しく考える必要があるでしょう。

プラットフォーマー以外は今後どうなる?

Yubicoなどのセキュリティメーカーはどうすべきかってところは気になりますね。 個人的にはプラットフォーマーの鍵管理にうまく接続できる(セキュリティキーでログインしたら鍵情報が端末やプラットフォーマーのアカウントに共有される)方向になるのかなーと思ったりします。

終わり

最近のFIDOの動向を、巨大プラットフォーマーとの関係という観点から見ていきました。 個人の業務としても自サービスへのFIDOの導入を検討してはいるので、こういう動向を踏まえて使いやすい状態を目指していきたいところです。

ではまた!