Android端末をGoogleの2段階認証のセキュリティキーとして使ってみる

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

こんなTweetを見かけたので試してみました。

www.itmedia.co.jp

環境

設定

手順はここに書いてあります。

support.google.com

既に2段階認証を設定してあればすっとできそうです。 2段階認証でセキュリティキー追加を選択します。

f:id:ritou:20190411101323p:plain
2段階認証でセキュリティキー追加を選択

以前はセキュリティキーを刺してください。だけだった気がしますが、Android端末も候補に出て来ました。

f:id:ritou:20190411101440p:plain
私のAndroid端末も候補に出て来ました

選択すると説明があります。

f:id:ritou:20190411101555p:plain
追加するよっていう説明

f:id:ritou:20190411101625p:plain
追加しましたよっていう説明

設定終わり。

f:id:ritou:20190411101916p:plain
完了

もともとスマホのPush通知でログインする機能を有効にしていてわかりづらかったのでその辺を無効化して試してみます。

認証

パスワード認証後に2段階認証の画面が出て来ます。

f:id:ritou:20190411101940p:plain
パスワード認証後、セキュリティキーでログインする画面になる

URLバーを見て!webauthnって書いてあるよ!(大興奮)

この時手元のスマホではこんな感じになります。

f:id:ritou:20190411102306j:plain
Android端末の方では確認だけ

OKしましょう。

f:id:ritou:20190411102402j:plain
処理中です

PCの方でログイン成功です。

f:id:ritou:20190411102518p:plain
ログイン成功

Bluetoothのペアリングがいらないってのが特徴ですね。 単純にスマホにPush通知を送るタイプとかと比べると、世界のどこかで攻撃者が試したタイミングででよくわからずOKしちゃうリスクもあるわけですが、この方法では近くにあるスマホのみ使えると言う点で安全と言えるでしょう。

OAuth/OIDCとかと違って細けぇところをリダイレクトとかで調べにくいのでふんわりですが、YubiKeyとかのセキュリティキーを買うとは思えない層への普及が見えて来ましたね!

以上です。 ではまた。

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 の人たちだけが頑張ってる場合じゃないですね。我々も頑張りましょう!(我々とは)

ではまた。

ファーストパーティーなアプリが使うOAuth/OIDCについてのお話 2019 春

夜分遅くに失礼いたします。ritouです。

こういう記事を読むとうずうずします。おそらく病気です。

terut.hatenablog.com

森羅万象を担当しているわけではないので、OAuth/OIDCが使えんのか?って観点から書いておきます。

ファーストパーティーのOAuth/OIDC利用

単一サービス内でOAuth/OIDC使うことってあるのか?という問いには「条件によっては適用可能」といったふわっとした答えになりそうです。フワッ

Webアプリ

Webアプリでも例えばドメインいっぱいある、別れている系でOAuth/OIDCでつなぐケースはありそうですね。

  • Microsoft : https://www.office.com/ -> https://login.microsoftonline.com/common/oauth2/authorize?client_id=... OAuth 2.0
  • Amazon : https://www.amazon.co.jp/ -> https://www.amazon.co.jp/ap/signin?openid.return_to=https%3A%2F%2Fwww.amazon.co.jp%2F OpenID 2.0!!!

当然、クロスドメインなセッションの確認方法、ログアウト時の処理など色々考慮する点は増えるかと思います。

Nativeアプリ

この辺りはあまり適当なことは書けませんが...要件としては「認証してリソースアクセスしたい」だと思います。 これを3つのステップに分割すると

  • Access Tokenを用いたリソースアクセス : 独自で作ったってどうせBearerっぽいのでやるんでしょう?
  • Access Tokenを払い出す機能
  • ユーザー認証機能

となり、主にユーザー認証とトークン払い出すところどうするんやというあたりでしょう。

  • NativeApp内でログイン画面を実装 : (サーバー側)独自のGrantTypeを作る、もしくは別Endpointとして各種トークンを払い出す機能を作る。WebAppがないNativeAppならこっちで良いかも?
  • 外部ブラウザ(相当のもの)を使う : (サーバー側)OAuth/OIDCのAuthorization Code Grant + PKCEとかで画面スキップ(後述)などUXをキメる。WebAppがあるならこっちの方がメリットあるかも

というあたりの選択になりそうですが、サービスの特性や今後の展開予定などにもよるのではないでしょうか。 サービスとしてNativeAppしかない場合に後者は厳しいでしょう。 例えば、最近のWebAuthnのようにWebAppの認証機能を作り込むといろんな環境でメリットがあるみたいな流れで行くと、後者もアリな気がします。

最近こんなの見かけたんですが、ファーストパーティーならこういう新しい仕組みも使えるかもしれません。

developers-jp.googleblog.com

Trusted Web Activity は、Android アプリ内で Chrome ブラウザを全画面で実行します。アプリ内に URL バーなどのブラウザの UI は表示されません。これは強力な機能なので、アプリとサイトが同じデベロッパーのものであること、すなわち「信頼できる」ことを検証しなければなりません。アプリと TWA で開いたサイトが同じデベロッパーのものであることを検証するために、TWA は Digital Asset Links を使って所有権を確認します。

まさにこれでは?期待ですね。

Resource Owner Password Credentials(ROPC)

ユーザーのCredentialを送ってTokenを取得するこの Grant Type ですが、認証機能付きの Access Token 払い出し機能ではありません。 そう思いたい気持ちはわからんでもないですが、ROPCでログイン機能作ろうと思うと、2段階認証とかどうしたら良いんや〜とかエラー表現〜とか色々思うところあると思います。あとログインだけあっても登録...ってなる。

ROPCは同じくユーザーのCredentialを預かってBasic認証API叩いてた系の仕組みに対して

  1. Basic認証からROPCにより一度Access Tokenに変換してやって保存し、リソースアクセスする仕組みに変える
  2. ユーザーのCredentialを受け取るのではなく、Authorozation Code などでAccess Tokenを取得する仕組みに変える

という手順をとってOAuthを使う仕組みに移行するためのものだと思いましょう。

同意画面のスキップについて

この辺りはコアな仕様の対象外かと思います。特定ユースケースに対するProfile系の仕様なら言及があるかもしれません。

同意画面の目的は "Clientがあなたに代わって(scope相当の)リソースアクセスをしようとしています。"という通知をして同意を得るためのものでしょう。 最近だとClient側のサービスの利用規約、プライバシーポリシーのリンクまで出すようにしてるとこもあると思います。

  • ファーストパーティー、セカンドパーティーならスキップ
  • ユーザーが「次回から表示しない」をチェックしたらスキップ
  • 同じclient,scopeで2回目以降ならスキップ

などなど、仕組みをOAuth/OIDCで作っておいて同意画面を飛ばすというやり方はずっと前からあるのでその辺はユーザーに説明できているかなどで判断すると良いかと思います。

理想としては、ファーストパーティーのアプリだとしてもAndroidのPermissionみたいな感じで例えばセンシティブな機能へのリソースアクセスを個別に拒否でき、拒否した機能を使いたくなったら再認可みたいな世界になってほしい気はします。と言い続けて10年ぐらい経ちました。

そこまでいかなくても、WebベースでやってきたサービスがNative Appを出しても「このアプリを使うとこんなデータが流れる!」みたいなのを気にする人もいるでしょうし、ファーストパーティーでもヘルプなり規約なりでどこかでちゃんと説明しておくってのは必要でしょう。

ザーッと書いてみました。寝かせるほどでもないのですぐに公開(投稿)しちゃいます。 深夜なので書き忘れてることがあったら後から追記します。 気になる点などありましたらコメントや言及してください。

そう言えば、昔のブログ(Y!ブログ)の記事を遡っていったら、自分は当初"ritou"を名乗っていなかったことがわかりました。いつから名乗り始めたのか記憶がない...

ではまた💤

DroidKaigi 2019 にて WebAuthn のお話をしてきました

こんばんは、ritouです。

こちらでお話してきました。

droidkaigi.jp

資料は話す前に上げました。

動画もあるみたいです(貼り方が控えめ)。スタッフさん仕事早いですね。

DroidKaigi 2019 - Chrome +WebAuthn で実現できるパスワードレスなユーザー認証体験と開発者の課題 / ritou [JA] - YouTube

去年の夏にも WebAuthn の紹介っぽい話を別のところでしたんですが、今回はUX的にも実感しやすい Android Chrome に引っ掛けて応募したところ採択された感じです。

終わった後にちょっとだけ質問をもらいましたが、「指紋とパターンロック解除あたりをもっと細かく制御できないのか」みたいなとこでした。 今年は基本的な仕様紹介のところからもう少し進めて、実際のUXや具体的な実装のところ(何ができる、何がAuthenticatorとかPlatformの裁量になるのか)の話を中心にしても聞いてもらえそうな感じがしました。

数少ない知り合いともお話できてありがたかったです。

ネタがあるうちにまた頑張りたいですね。 ではまた。

メアドなどのスクリーニング対策を意識しつつ WebAuthn のログインフローを考える

ritou です。

年末ですが、一年を振り返るエモいポエムを書く気はさらさらないのでいつも通りです。よろしくお願いします。

今年は WebAuthn が話題になりました。 来年はブラウザの対応も進み、本格的に導入してくるサービスも増えてくるかと思います。というか出てこい。というか出そう。

当然、今まで提供してきた認証方式から全てのユーザーを一気に切り替えることは不可能でしょう。 導入にあたってのポリシーはそれぞれだと思いますが、UserVerification を用いてパスワード認証からの完全移行を目指す、もしくはオプションや多要素認証として提供するにしても、既存の認証方式と組み合わせたログインフローを実装する必要があります。

今回は既に複数の認証方式をサポートしているサービスのログインフローをざっと振り返った後に、今年別件で話題になっていたメアドや電話番号などのスクリーニングへの対策という視点を入れてどのようなログインフローを実装すべきかを考えたというお話です。

いきなりまとめ

ダラダラと書いてますが、こんな流れです。

  • GやY!Jはユーザー識別後に設定されている認証方式を提供
  • microsoft はユーザー識別と並列で WebAuthn の認証機能を提供
  • WebAuthn でも Resident Key 使えない環境だと最初にユーザー識別が必要
  • ソーシャルログインも最初に IdP毎の分岐をするのが一般的
  • ユーザー識別後に処理を分岐させるとスクリーニング対策は困難
  • WebAuthn の認証フローでもスクリーニング対策は可能
  • 既存のログイン方法 or WebAuthn のように並列にしておくのが良さそう
  • 利便性低下の防止のために前回と同じ認証方式を使うみたいな仕組みを入れても良いかも

では始めます。

複数の認証方式を提供するサービスを見ていく

まずは Google, Yahoo! JAPAN, microsoftあたりを見てみましょう。

Google

(おそらく普通の) Google ユーザーは2種類の認証方式を利用できます。

ログインフローがどうなっているかを整理します。

まず、ログイン画面で存在しないユーザーのメアドを入れるとエラーになりますね。

f:id:ritou:20181231010133p:plain

Googleの場合、登録されているメアドというよりも 存在するgmailかどうか がここで判断できますね。

次に、「スマートフォンでログイン」を設定していない場合、ログイン画面でメアドを入れるとパスワード入力画面になります。

f:id:ritou:20181231010158p:plain

スマートフォンでログイン」を設定している場合、ログイン画面でメアドを入れるとスマホでタップしろ画面になります。

f:id:ritou:20181231010238p:plain

スマートフォンでログイン」を設定しているユーザーかどうかがここで判断できます。 ちなみに他の方法で...ってやると、こんな画面です。

f:id:ritou:20181231010304p:plain

これはまぁ、いいや。

ここまでで、利便性重視なんでしょうけれども、登録されているかどうか、スマホでログインする設定になってるかどうかがログイン試行している人物に対して丸わかりです。 次は WebAuthn にも対応している Y!J を見ていきましょう。

Yahoo! JAPAN

Yahoo! JAPAN も複数の認証方式に対応しています。

  • 確認コードでログイン(SMS)
  • 確認コードでログイン(メール)
  • 指紋・顔認証など(WebAuthn)

そして、Googleと同様にそれぞれわかりやすいUXとなっています(雑)

まずは存在しないメアドとかの場合。

f:id:ritou:20181231182246p:plain

あ、これ赤枠で囲ったわけじゃなくてログイン画面の背景が赤いんです。念のため。

次、確認コードでログイン(SMS)の場合

f:id:ritou:20181231022859p:plain

確認コードでログイン(メール)の場合

f:id:ritou:20181231022917p:plain

そして、Android Chrome + WebAuthn だとこんな感じです。

f:id:ritou:20181231023101j:plain

確認コードのところはなんかマスクしすぎてわけわかりませんが、Googleと同じような感じですね。 Google と Y!J では、「最初にユーザー識別をしてからそれに紐づく認証方法を提供している」と言えそうです。

次は、同じく WebAuthn のログインを実装している microsoft です。

microsoft

Windows 環境で microsoft + Edge を使うと、ログインに WebAuthn のフローを利用できます。

blog.haniyama.com

ログイン画面はこんな感じです。

f:id:ritou:20181231164906p:plain

"Sign in with Windows Hello or a security key" と言うリンクがここにありますね。 環境判定して Edge だけ出してそうです。 このフローを使うと、メアドなどを入力せずとも Windows Hello や セキュリティキーでログインできます。

f:id:ritou:20181231165437p:plain

navigator.credentials.get() 呼び出してそうです。

f:id:ritou:20181231165600p:plain

スクリーンショットをとった私の環境はPIN入れる画面ですが、とりあえずこれでログインできます。

microsoft の場合、「ユーザー識別をしてからそれに紐づく認証方法を提供 or WebAuthn」のような分岐になっているように見えます。

WebAuthn の Resident Key の現状

上記のように、microsoftWindows + Edge な環境では、「この時点で誰かわからないけどWebAuthnでログインさせる」と言う処理になっていました。 これは username-less とかとも言われますが、ResidentKey を用いた登録/認証機能です。

これは便利なので使いたいところですが、現状、全てのブラウザがこの Resident Key に対応できているわけではありません。 よって、早い段階で WebAuthn をサービスで利用しようと思った場合、Y!J のやっていたような一旦ユーザーを識別した後に紐づく公開鍵を用いて WebAuthn の認証フローに入っていく必要があります。

と言うことは、やはりG や Y!J のようなやり方がベストなのでしょうか?

ソーシャルログイン対応サービス

Google も Y!J も基本的に自分たちで認証機能を提供しています。 それに対し、世の中には既に「ソーシャルログインを利用」する形で複数の認証方式に対応しているサービスがたくさんあります。

例えば、エンジニア向けのイベントで有名な connpass とか

f:id:ritou:20181231170657p:plain

エンジニアの転職で有名なメルカリとか

f:id:ritou:20181231170643p:plain

ソーシャルログインを利用するログインフローでは、「パスワード認証 or ソーシャルログイン」もっと言うと「パスワード認証 or IdPその1でログイン or IdPその2でログイン or ...」と言う感じで、これまでの例でいうと microsoft のやり方に近いです。

ということで、ここまでで複数の認証方式をサポートしたログインフローを考える時の最初のキメは「ユーザーの識別前に認証方式を分岐させるか、識別して設定に合わせた認証方式を提供するか(さらにいうと、識別後に分岐させるか)」あたりかなと思ってきました。

少し落ち着いて、一旦スクリーニング対策について考えましょう。

スクリーニング対策の必要性

今年、メールアドレスなどのスクリーニングについての話題も目につきました。

qiita.com

よくある「メアド or パスワードが間違っています」でやってたところが、新規登録のところでちゃんとエラー返してたのでスクリーニングに利用されたのではというお話ですね。

今回はログインの話ですが、スクリーニングに使われることの何が嫌かというと

  • 悪意のある行為の手助けをしてしまう
  • 例えばSMSをじゃんじゃん送られたらそれなりにお金もかかる
  • 対象となり通知を受けたユーザーが困惑、心配からの炎上
  • 負荷も上がるかも

といったあたりでしょう。 やはり良いことなさそうです。

まぁ、GoogleGmailが生きてるかどうかを聞いてもそんなに得しない気もしますが、オンラインショッピングや決済関係のサービスでスクリーニングされたらそのリストの価値は上がるでしょう。

しかし、上記のGやY!Jのようにユーザー識別後に処理が分岐するようでは、簡単にスクリーニングされてしまうので、microsoft やソーシャルログインを利用するサービスのように、並列に WebAuthn の認証フローに入る、かつスクリーニング対策をする方向で考えていきたいところです。

WebAuthn におけるスクリーニング対策

こんな感じではどうでしょうか。

  1. 存在しないメアドや電話番号でも、認証画面に入る
  2. 公開鍵はメアドや電話番号に一意に紐づけられるダミーの物を用意しておく。毎回同じものを使う。
  3. 万が一認証通ってきたとしても、しれっとエラーにする

この辺りはもう少し考えたいですが、できないことはなさそうです。

既存の認証方式とWebAuthn の組み合わせ方案

ここまでの話を整理して、ログインフローを検討しました。

Step 1 : ログインフローの最初に分岐

例え現状の WebAuthn の認証フローがユーザー識別を必要としても、最初に分岐させるのが良さそう。 Y!J の認証方式の用語を用いるとこんな感じでしょう。

f:id:ritou:20181231030450p:plain

Step 2 : ユーザーに紐づくメアド or 電話番号などを入力

ここで登録されていないエラーは出しません。

Step 3 : 存在しないメアド or 電話番号の場合でもダミーの公開鍵で WebAuthn の認証フローに入る

仮にダミーの公開鍵だったとしても、WebAuthn の Authenticator から見たら「別の Authenticator 向けの公開鍵なんだな」として処理してくれれば問題なさそう。

スクリーニング対策による利便性低下への対策

上に書いたログインフローですが、ユーザー視点で毎回分岐しまくるのは正直辛いですし、エラーも出てこない分、永遠に「ログインできねーや」と詰む人が出てきそうです。 また、どんな認証方式を利用しているか忘れてしまうこともあるでしょう。

実は、ソーシャルログインの普及時期においても同様の議論はありました。 例えばソーシャルログインでサービスアイコンが並んでる時の問題は Nascar Problem と呼ばれていました。

idmlab.eidentity.jp

上記の記事にもありますが、この問題の対策として、前回利用した認証方式を覚えておくみたいな話があります。 WebAuthnが利用できる環境なら使うけど、そうじゃなかったらSMSとかで確認コードを送りたいみたいなユーザーにも、ブラウザごとに前回の認証方式が利用できる仕組みになっていると良さそうです。

まとめ

最初に書きました。

  • GやY!Jはユーザー識別後に設定されている認証方式を提供
  • microsoft はユーザー識別と並列で WebAuthn の認証機能を提供
  • WebAuthn でも Resident Key 使えない環境だと最初にユーザー識別が必要
  • ソーシャルログインも最初に IdP毎の分岐をするのが一般的
  • ユーザー識別後に処理を分岐させるとスクリーニング対策は困難
  • WebAuthn の認証フローでもスクリーニング対策は可能
  • 既存のログイン方法 or WebAuthn のように並列にしておくのが良さそう
  • 利便性低下の防止のために前回と同じ認証方式を使うみたいな仕組みを入れても良いかも

今回のお話ですが、現状の他のサービスを見つつ、優秀な若者氏に相談して見た結果、良さそうってなった提案です。 これでうまくいくかどうかはわかりませんので、実際に自分たちのサービスに導入して検証できると面白そうですね。

長文読んでいただきありがとうございました。来年も頑張りましょう。

ではまた!

OIDC Client Initiated Backchannel Authentication Flow (CIBA)とは - 概要編

ritouです。

今回ご紹介する仕様は、OpenID Connect の Client Initiated Backchannel Authentication Flow(CIBA) でございます。

openid.net

OpenIDファウンデーションの MODRNA WG でただいま絶賛 Public Review 中の一品であります。

サクッと終わるだろと思ってましたが書いてるうちに細かいリクエストのところで盛り盛りになってしまったので、分割して今回は概要編みたいな感じにします。

概要

既存の OIDC の認証フローはユーザーのブラウザを介して RP -> OP -> RP といういわゆる OAuth Dance のために HTTP リダイレクションを利用します。 3-legged な OAuth Dance の感じを示すとこんな感じです。

f:id:ritou:20181229000232p:plain

  1. RP上で「OPのアカウントでログイン」を選択
  2. RPからOPにリダイレクト
  3. OP上で認証、データアクセスの許可
  4. RPにリダイレクト
  5. RPはOPから各種トークン取得

シーケンスでいうとこんなです。

f:id:ritou:20181229000342p:plain

いつものやつですね。

それに対して、今回紹介する CIBA の認証フローでは次のようになります。

  • RP はなんらかの方法(仕様の対象外)でユーザーの識別子を知る
  • ユーザーの識別子を知っている RP が OP と直接通信してトークンを要求、取得する
  • 認証結果の受け渡しに関するユーザーの許可などについては、スマートフォンなどで OP とやり取りする

これだけではわからんと思いますが、なーんとなく、CIBAの認証フローに近くてイメージしやすそうなのは、Google に自分のスマートフォンを利用してログインする機能でしょう。 実際は CIBA とは異なりますが、Google 内部で RP=Youtube, OP=Google みたいな立ち位置にすると、近くなるかもしれません。

f:id:ritou:20181229004954p:plain

  1. RP上でユーザー識別(例:メアド入力)
  2. RPはOPに対してこのユーザーの認証を要求
  3. 手元のスマートフォン + OP上でユーザー認証、データアクセスの許可
  4. RPはOPから各種トークン取得

今のは仕様に書いてなくて私が説明のために考えた例ですが、仕様に記載されているユースケースを見てみましょう。

ユースケースと用語

例として、次の3つが記載されています。後の説明のためにちょっと順番を変えています。

  • ユーザーのスマートフォンで POS 端末の支払い
  • 銀行窓口での顧客認証
  • コールセンターにおける発信者認証

ソーシャルログインなどに代表される OIDC の認証フローの説明では UserAgent(エンドユーザー), RP, OP の3者が登場人物となるユースケースが一般的です。 しかし、このユースケースにおける

  • POS 端末を操作している人
  • 銀行窓口の担当者
  • コールセンターの担当者

という人たちは、実際に認証とアクセス許可を行う UserAgent(エンドユーザー) と同一人物ではなさそうです。

CIBA ではこの人たちが利用しているのを RP 、操作している端末などを Consumption Device (CD)スマートフォンなどユーザーが認証/認可処理を行う端末を Authentication Device (AD) と呼びます。

OIDC では CD = AD = UserAgent と言えるでしょう。 CIBA では CDAD が別でも大丈夫です。 ということは、システム的/物理的に離れていてもユーザー識別がうまくてきればユーザー認証結果を取得して利用できて、「これは良いのではないか」って感じになってきたんじゃないでしょうか?

おまけで、現在のなんたらPayブームに乗って、仮に Ponta の ID と決済できるとこのIDが紐づいてたら

コンビニ店員「Pontaカードカモン」
客「はい」
店員「XXX円です」
客「CIBA Pay(ダッサ)」
店員「はい(ポチ)」
客のスマホ「(XXX円をローソンに支払います。よろしいですか?)」
客「おk」
店員「支払いおわた。レシートどぞ」

ぐらいは出来そうです。

OAuth 2.0 Device Flow との違い

そういえば、OAuth 2.0 には Device Flow ってのがあります。 Device Flow はテレビやスマートスピーカーのような、エンドユーザーとの対話機能に制限があるデバイス上で動作する Client(RP) の 認可処理を別の端末で行うための仕様です。

qiita.com

CIBA とあえて比較するとしたら、

  • CD , AD の分離
    • Device Flow は既存の OAuth Dance の RP -> OP にリダイレクトするタイミングでQRコードやURL表示などで手元のスマートフォンなどに誘導し、 CDAD が分離
    • CIBA は最初から CDAD が分離していて、 OP が AD を用いてユーザーと対話
  • ユーザー識別
    • Device Flow では OP の所でユーザー認証するので事前のユーザー識別は不要
    • CIBA では Client が OP に「このユーザーを認証してください」と要求し、OP は紐づく AD を特定 するため、事前のユーザー識別が必要

という感じで、完全に CIBA が Device Flow を置き換えるような感じではなさそうです。 互いに適切な用途があると思うのでこの辺りの導入を検討する際は気をつけましょう。

概要編の最後に、ざっくりと CIBA の認証フローを見ていきます。

認証フロー概要

CIBA では次のような認証フローが定義されています。

  1. Client は OP の Backchannel Authentication Endpoint にユーザー識別子などを含む HTTP POST を送ってエンドユーザーの認証を要求
  2. OP はバックグラウンドで認証を試みる間、その認証に一意にひもづく識別子を返す
  3. ClientID Token, Access Token, Refresh Token(optional) を受け取る。その方法について、Poll, Ping, Push というモードがある

モードによって最後のトークン取得方法が異なります。

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

Poll モードについては Device Flow と似ています。

Ping / Push モードでは OP から RP へのリクエストも考慮されています。 ということで、このモードを使う場合、RP にも新たなエンドポイントが必要となりますね。

次回予告

ここからの詳細の説明、ちょっと長くなるので次回にします。 また、Device Flow の時もそうだったんですが、こういう飛び道具系の仕組みはセキュリティ面で色々考えるところがあるので仕様の Security Considerations, Privacy Considerations のあたりも見ていきましょう(今回のに含めたかったけどパラメータについての言及があったのでやめます)。

CIBAについてもっと詳しく聞きたい?

誰が詳しいの?と CIBA OIDC あたりでググった結果...

f:id:ritou:20181229192822p:plain

1個めが仕様、その外はこれ全部くどーさんですね。 ということで、CIBAについてすでに情報を発信しており、私よりも熱い思いを持つ人、くどーさんに聞けばいいじゃない。ソレガイイ、ソレガイイ。

私も行きます。行けたら。

参考になりそうなスライド

www.slideshare.net

www.slideshare.net

おまけ : 発音

そういえば、今回初めて CIBA を知った方、ここまで脳内でどう発音してきましたか? 親切な仕様だと発音についての記載があったりしますが、まずは文章やスライドだけ読むマンにとって、OAuth、JOSE、CBORなど、発音に困ることが多々あります。

さすがくどーさん親切ですね。

ではまた!

OAuth 2.0 の Implicit grant 終了のお知らせ

f:id:ritou:20181112110600j:plain

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

先週、こんな記事出てました。

Why you should stop using the OAuth implicit grant!

ということらしいです。

Implicit grantといえば Token Replace Attack や Covert Redirect など、OAuth 2.0の脆弱性を語る上で欠かせない唯一無二の存在であります。

www.atmarkit.co.jp

私の中では最初から非推奨ですが、公式にとなると気になりますね。

策定中のドキュメントではどう書いているかというと

The implicit grant (response type “token”) and other response types causing the authorization server to issue access tokens in the authorization response are vulnerable to access token leakage and access token replay …

In order to avoid these issues, Clients SHOULD NOT use the implicit grant and any other response type causing the authorization server to issue an access token in the authorization response.

OAuth 2.0 の Implicit Grant では Access Token そのものの値を fragment の値に指定して Authorization Server から Client に戻されます。 その部分で漏洩 / リプレイアタックみたいなやつのリスクがありそうなので、Implicit 使うべきではないみたいな感じですね。

この記事における理由としては

  • Implicit Grant のセキュリティは修理不可能なほどぶっ壊れている
    • トークン漏洩に脆弱で、攻撃者は取得した Access Token で 色々できる
  • Access Token の悪意ある再利用を防ぐためには、sender constrained access token が必要
    • このトークンタイプをサポートするために Implicit grant を拡張することは容易でない

となっていて、なるほど詰んでる。って感じです。

続いて、これはOAuth 2.0にとって致命傷となるか?については

  • もともと Implicit = Browser-based JavaScript App onlyではなかった
    • Authorization Code Grant はいいぞ

と、AuthZ Code 推しとなっています。これもわかる。いわゆる、わかりみがある。

ではなぜ、Implicit grant があるのかってとこで...ちょっと引っかかりました。原文のまま見ていきます。

Well, in the old days (back in 2010) browser-based apps were restricted to sending requests to their server’s origin only.

むかーしむかし、ブラウザベースのアプリはリクエストの送信を自分たちのサーバーの origin に制限されていました。

So there was no way to call an authorization server’s token endpoint at a different host.

なので、異なる host から AuthZ Server のトークンエンドポイントを呼び出す方法がなかった。(?)

That’s why the short cut was introduced to deliver the access token in the authorization response through the browser.

それがショートカットで AuthZ Response 内に Access Token を含んで渡す理由だ(??)

The risks associated with this approach should be mitigated by limiting the privileges and lifetime of such tokens. The implicit grant has always been a compromise!

Access Token の権限やライフタイムを制限することでリスクを緩和するしかなかった。みたいな。

この説明について、そもそも AuthZ Server のエンドポイントを叩けないならば、Implicit grant で Access Token をわたしたって Resource Server のエンドポイント叩けるんですか? AuthZ Server だけ制限しているケースってあるの?みたいな気持ちになりました。

そんなのよりも、Access Token をフラグメントで渡す理由は

  • ブラウザベースのアプリケーションは Public Client であり、 Client Secret を安全に管理できない
  • Authorization Code Grant でもユーザー/攻撃者から簡単に取得できる Client IDだけで Access Token に交換できる
  • 最初から Access Token 渡せばいいじゃん。アプリをホストしているサーバーに値が渡されたくないならフラグメントで

ぐらいな感じじゃないのかと思っておりました。今も思っています。

記事ではここから CORS 万歳!みたいになります。

Thanks to Cross-Origin Resource Sharing (CORS) this compromise now ends. CORS allows browser-based apps to send requests to hosts outside of their origin given the destination permits it.

And what’s very important, it’s broadly adopted! This evolution allows the OAuth working group now to recommend use of the authorization code grant for browser-based apps, that way leveraging the aforementioned security benefits to those apps as well.

CORS 使って AuthZ Code Grant でやるのを推してく!みたいに書いてあります。

まだ残る CORS 推しの違和感を解消するため、別の記事で、こんなの見つけました。

What is the OAuth 2.0 Implicit Grant Type?

この記事では、Implicitが今の仕様になった経緯が "When to use the Implicit Grant Type" のところで説明されています。

One of the historical reasons that the Implicit flow used the URL fragment is that browsers could manipulate the fragment part of the URL without triggering a page reload. However, the History API now means that browsers can update the full path and query string of the URL without a page reload, so this is no longer an advantage of the Implicit flow.

ページのリロードなしでフラグメントの値を操作できるので便利たったけど History API で戻ったりできるようになったのでそんなにアドバンテージではないってのと、

The one remaining reason to use the Implicit flow is if the authorization server doesn’t or can’t support cross-origin requests (CORS). The Authorization Code grant requires that the JavaScript app make a POST request to the authorization server, so the authorization server will need to support the appropriate CORS headers in order to allow the browser to make that request. This is a relatively easy change to make if you’re building your own authorization server, but if you are using an existing server then you may be stuck using the Implicit grant to get around the CORS limitation.

AuthZ Server が CORS 対応してない or できない場合には既存の Implicit Grant で回避するしかなかったみたいなのが書いてあります。 この説明であれば少し親切かもしれません。が、これが決め手とはどうしても思えないですね。

では今後どうすれば良いかについて、Draftが出ています。

draft-parecki-oauth-browser-based-apps-00 - OAuth 2.0 for Browser-Based Apps

00なので今はじっくり見てませんが、落とし所としては

  • PKCE : Public Client でも sender constrained な仕組みにできる
  • Response Mode : AuthZ Code Grant でもフラグメントに載せられる

の併用あたりになるのではと予想しています。

違和感を覚えても安易に「いい加減なこと書いてるとぬっCORSぞ」みたいなことは言わずに、ベストプラクティスを追求していきたいですね。

ではまた。

まんぷくになった YubiKey を YubiKey Manager でリセットしたメモ

f:id:ritou:20181102013325p:plain

こんばんはこんばんは ritou です。

それは突然の出来事でした。

光らない YubiKey

諸事情により ResidentKey を使った navigator.credentials.create()何回も何回も何回も何回もしていたら、ある時から

  • ResidentKey を使った navigator.credentials.create() : 動かない(光らない)
  • ResidentKey を使わない navigator.credentials.create() : 動く(光る)
  • navigator.credentials.get() : 動く(光る)

みたいな状態になりました。

色々なところで挙動を確認していたら、Windows + Edge な環境でこんな表示が。

f:id:ritou:20181102012910p:plain

なるほどお腹がいっぱいなのかな?と思いつつもそれ以上の確認方法がわかりません。

どうせこの YubiKey さんはまだ各所のデモサイトで使ったぐらいの開発用というかどうなっても影響のないものだったので、中身をリセットすることにしました。

YubiKey Manager との出会い

誰かが YubiKey Manager というワードを使っていたのを思い出して、調べたところ、CLIでもGUIでもできそうな感じでした。

実際は恐る恐る CLI でやっちゃったのですが、あとからGUIでも試したら最初からこっちでやれば良かったと思いました。

ドキュメント : yubikey-manager-qt

* Reset the FIDO Applications

これです。インストール方法なども書いてあります。

f:id:ritou:20181102015029p:plain

手元にある青いやつをを入れると...デバイスの画像とFirmwareの番号が表示されます。

f:id:ritou:20181102015409p:plain

こいつに対してできる機能は限られており、Applications -> FIDO2 と進んでいくと...

f:id:ritou:20181102015451p:plain

PIN設定とリセットができそう。

PIN設定はまた後で取り上げようと思っているので、リセットの方を選択します。

f:id:ritou:20181102015655p:plain

f:id:ritou:20181102015836p:plain

念入りに確認たあと、YubiKey を一回さし直せって言われます。

f:id:ritou:20181102015859p:plain

んで、タッチすると成功します。

f:id:ritou:20181102015946p:plain

f:id:ritou:20181102020022p:plain

ここまでで作業は終了です。

光を取り戻した YubiKey

再び ResidentKey を使った navigator.credentials.create() を試みると、光るようになってました。

めでたしめでたし

まとめ

  • YubiKey がまんぷく宣言!
  • YubiKey Manager におまかせ!!

容量についてもうちょっと調べ方ないかなーと思っています。知ってたら教えて詳しい人!

とりあえず、YubiKey Manager のご利用は自己責任で!というところでしょうか。

ちなみに、夜中なので「WebAuthn で出会った YubiKey がお腹いっぱいで眠いって言い出したので YubiKey Manager でリセットしたったwww」みたいなひどいタイトルをつけそうになりましたが書いてるうちに落ち着きました。

ではまた。

【ゆるゆるとパスワードレスなUXを検討】(3) 新規アカウント作成時に WebAuthn Authenticator の登録

f:id:ritou:20181022235144p:plain

どーもどーもどーも。ritou です。 下書きのまま放置してました。

WebAuthnを実サービスに導入しようとしたらどこでつまづくんやってのを考えて来ましたが、ここまではわりと無難な設計に落ち着いている気がします。

今回はアカウントを新規登録したタイミングで WebAuthn の Authenticator を登録するあたりを整理します。 と言っても、アカウント作りつつの (1) WebAuthn Authenticator の登録でしかないです。

前提

登場人物を振り返っておきます。

  • あるサービス = WebAuthn の RP
  • ユーザー = あるサービスに登録完了した時点でこうなっていて欲しいと言う状態
    • 1つ以上の User Verification 可能な Authenticator と紐づけられている(MUST)
    • 既に確認済のメアド / SMS番号を持っている(SHOULD)
  • Authenticator : 生体とかPIN(UserVerification)で単体でユーザー認証が達成できるやつ

新規登録フローってのは、この前提条件に引っ張られてしまうのであまり一般化できなくなってしまいそうなのが悩みどころです。が、仕方ないですね。 そこそこのユーザーデータを扱い、あわよくば決済などを提供できるぐらいのサービスを想定すると、パスワードレスになったとしてもメールやSMSの確認の要件は残るだろうと言うことでこの辺りにしていますが、メアドやSMSの確認を後から行うところもあるよねってとこでその辺りで2パターンを考えていきます。

メアド/SMSの確認を最初に行うフロー

大したことない話ですがサクッと書くとすぐ終わるのでちょっと引っ張ります。

新規アカウント登録のフローとして

  1. メール/SMSの確認を行う
  2. 表示名などの必要最低限な設定を行う

みたいなのが一般的かと思います。

今回はそこに

  • WebAuthn の Authenticator 登録

というのを追加したいわけですが、入力フォーム一つで済むパスワード設定と異なり、Authenticator 登録はユーザーのアクションを伴うのでタイミングが重要ですね。

  1. メール/SMSの確認を行う
  2. 表示名などの必要最低限な設定を行う
  3. WebAuthn の Authenticator 登録

この順番であれば、ユーザー情報が存在してからの Authenticator 登録みたいな感じですが、今回の前提としては登録完了時に Authenticator が紐づいていて欲しい。 ということは

  • 1, 2, 3まで終わったら登録完了!
  • 1 が済んだら内部的に仮登録でユーザーID発行、2, 3まで終わったら本登録完了

みたいな作りになるかもしれません。

ResidentKey を用いるログインフローまで考えると、ユーザーIDが振られ、表示名などを登録した後に Authenticator の登録になるのが望ましい気がします。 内部で扱うユーザーIDと Authenticator に渡すユーザーIDを分けるようにしても実現できそうですが、細けぇ話は次回にまとめたいと思います。

次に、ちょっと順番変えてみます。

  1. メール/SMSの確認を行う
  2. WebAuthn の Authenticator 登録
  3. 表示名などの必要最低限な設定を行う

こっちの方がしっくり来る気もします。

これを書きながら思ったことですが、一度 Authenticator に渡してやった user.name ってメアドやニックネーム的な「後から変更可能な値」が使われることが多そうです。 当然、サービス側で更新した時に Authenticator 側との不整合が起こることは容易に想像できますね。 なんとなく、navigator.credentials.update() みたいな関数が欲しくない?と思いました。

とりあえず、IDの振り方あたりを気をつければ WebAuthn の Authenticator 登録処理を含む新規登録フローもなんとなく実現できそうです。

後からメアド/SMSの確認を行うフロー

ここでは、メール/SMSの確認処理による "最初の離脱" を抑えるために、確認処理を後から行うサービスを想定します。

この場合、

  • 表示名などの必要最低限な設定を行う

  • WebAuthn の Authenticator 登録

の組み合わせの話になります。 上記、ResidentKey を利用する可能性まで考えると、name or displayName あたりが欲しいので

  1. 表示名などの必要最低限な設定を行う
  2. WebAuthn の Authenticator 登録

という順番が無難そうです。

ユーザーがもつ "認証方式の種類" について

builderscon の時も少し話しましたが、メール/SMSを確認して、パスワード認証のリカバリーに使ったりする時点で、もうご立派な認証方式じゃねーかと個人的には捉えています。

今回はその確認を先にやる、後回しにするという2パターンを考えましたが、登録完了時にユーザーが持つ認証方式の数が変わることになります。

特に WebAuthn が使える環境が限られている、ユーザー側の事情により生体認証が不可能な場合などを考慮すると、複数の認証方式が利用できる状態(セキュリティ的観点で言うと利用する認証方式を細かく管理できている状態)になっているのが好ましいでしょう。

「認証する手段がなくなって詰んだ」状態を避けるために、離脱のリスクはありつつも最初にメール/SMSの確認を済ませておくのが無難かな〜と思います。

外部サービスのアカウントを利用した登録フロー

アカウントの新規登録で言うと、いわゆるソーシャルログインを利用した登録フローへの WebAuthn の導入も考えられます。

ソーシャルログインによりSNSなどのいわゆる Identity Provider から確認済みメールアドレスなどを取得できた場合、それをリカバリーに利用できます。

また、ニックネームなどを属性情報の初期値として利用するような実装も一般的でしょう。

WebAuthn の Authenticator 登録との組み合わせ方としては

  1. ソーシャルログイン
  2. 表示名などの必要最低限な設定を行う
  3. WebAuthn の Authenticator 登録

とするのが無難かなと思います。

上述の自前の登録フローと組み合わせる場合は、順番を揃えておくことで実装/UX共に統一感が出せそうですね。

まとめ

今回も無難な内容になったかもしれませんが

  • Email / SMS 確認を先にするサービスと後にするサービスがあり、それぞれで WebAuthn Authenticator 登録するタイミングを整理した
  • Email / SMS 確認のタイミングはサービスの内容だけではなく、 WebAuthn の認証ができない場合のリカバリー手段としても考慮が必要そう
  • ソーシャルログインによる登録に対応している場合も、処理の順番は考える必要がある

これで既存ユーザーへの Authenticator 登録、ログイン、新規登録のUXを整理しました。 次回は今回ちょっとだけ触れた、Authenticator に渡す情報とサービス内のアカウント情報の関係、悩ましい点などを整理したいなと思います。

ではまた!

「Webauthn における ResidentKey について」 について

f:id:ritou:20181020210218p:plain

ritouです。

今回はアメブロで言うところのリブログ的な何かです。

おっさん、昨日の夜にこれ読みました。

blog.haniyama.com

  • ResidentKeyの使い所
  • userVerification オプションの指定に "UserVerificationイラネ" はない
  • platform な Authenticator で UserPresent な場合って?
  • そのままで UserPresent として動作し、PIN設定したら UserVerification になる Authenticator の挙動

あたりがガーッと書かれており、熱い想いがつたわってきますね(?)。

こいつら、組み合わせ方によってイレギュラーな動きをするパターンがあるなら別だけど、これらはそれぞれ独立している話っぽい。

なので、個別で考えるのが良いんじゃないかなと思います。

ResidentKey の使い所

自分の中では、

  • 対象のユーザーが特定できている状態からの "WebAutnn 認証" リクエストのみを利用する : ResidentKey 使わなくてもなんとかなる
  • 対象のユーザーが特定できていない、もしくは事前に特定する必要がない状態からの "WebAutnn 認証" リクエストを利用する : ResidentKey 使う必要がある

ぐらいの認識でいて、WebAutnn を用いたログインフローを整理したりしています。

ritou.hatenablog.com

前者は

  • ログイン中のユーザーを WebAuthn で再認証(例:アカウント設定変更時の "パスワード確認" みたいなの)
  • Googleのログインフォームのように先にメアドなどでユーザー識別をした後に認証処理に入る

みたいなところで、ResidentKeyの機能を使わなくてもなんとかなりそうかなと言う感じです。 一方、後者は”生体認証もしくはセキュリティキーを用いてログイン” ボタンから始まるログインフローみたいなので ResidentKey の機能が必要になりそうです。

自分の検討では UserVerification 使うぞって決め打ちなので今の所そんなに悩むとこはないかなーという印象ですが、Authenticator がサポートする認証方式、つまり UserPresent vs UserVerification の話を ResidentKey の話に混ぜちゃうと、Authenticator の挙動に引っ張られて話が発散しそうな予感はします。

User Present な Platform Authenticator?

だが、スマホや PC で UV がない認証がないけど、これってどうなるの?

スマホやPCでUVがない認証、つまり生体認証もPINも不要でAndroidの初期設定みたいな画面タッチだけで通すようなイメージだろうか。 セキュリティカードみたいな使い所とかが platform(internal) な方であるのだろうか?と言うあたりでしょうか。

んで、どっかの仕様でこれを実装/提供してはいけないとか書いてあるのでしょうかね? と言うのが要確認なところ。 それがあれば別だけど、そうでなければこれを用意するかどうかは需要と言うかユースケースがあるかだけな気はします。

UserVerification 任意 はあるけど UserPresent のみでおkを指定できない

これも、要件があるのかどうかってとこですかね。

これは外部 Authenticator も一緒で、たとえば一旦 PIN を設定した YubiKey は、 User Verification オプションをオフにしても PIN の入力が求められることになる。

つまり、サービスA でタッチだけでログインしていたとして(discourage)、他のサービスBで UV が必須(required)だったとする。そこで、サービスB に登録するために新しく PIN を設定すると、サービスA でも PIN が必要になるということ。

そんなんどこに書いてあんねんってのは、CTAP2 の仕様に書いてあったように思うけど、探しても見つからない。

パッと思うのは「こんなの Authenticator(今回はYubiKey) 依存の問題で、細かいとこまで作り込めばいくらでも素直なUXにできるのでは 」ってところだけど、仕様で定義されてるものがあるのか確認が必要ですね。

日本的な言い方で言うところの「コンシューマ領域のユースケースを考慮した WebAuthn Authenticator の設計/実装ガイドライン」みたいなのがあってそれに書いてるなら従うべきだろうし、なかったら Authenticator 作ってる人たちはちゃんと考えなくちゃいけなくて大変そうですね。

まとめ

とりあえずは

  • Authenticator の挙動が仕様に沿ったものなのか、メーカー依存なのかを確認する必要がある
  • Authenticator 周りの事情がはっきりしてから ResidentKey のユースケースを考え直すと良さそう

ってとこでしょうか。 仕様読むの大変なので、もくもく会以外でも継続してオンラインで何かできると良いですね。