フィッシング被害が多発しているというAmazonからのセキュリティ通知の仕様の危うさ

こんにちは、ritouです。

こんな記事を見かけました。

internet.watch.impress.co.jp

Amazonをかたるフィッシングが報告全体の35.8%を占め、特にSMSによるものが多かった。同協議会では、SMSではメールよりも本物と誤解したり、ついアクセスしたりしやすいため、注意が必要だとしている。

Amazonでなんでもポチれる時代にこれは切ない事態です。 今回はその Amazonから送られてくるセキュリティ関連の通知の仕様がよろしくないのでなんとかして欲しいというお話 をちょっとだけします。

セキュリティ通知

中の人じゃないので細かい仕様を全て把握できているわけではありませんが、例えばログインの設定をいじろうとしたときなどにこんな画面が表示されます。

f:id:ritou:20210709115406p:plain

SMSとメールで通知を送ったので確認しろという内容です。

その下の謎の申請ってのはもしかしたらアプリへの通知かもしれませんが、昔いろいろあって今はアプリを入れてないのでSMSとメールを見てみます。

そして送られてきた内容を見てみましょう。

f:id:ritou:20210709115516p:plain

左がSMSです。

  • 送信元の検証が困難すぎぃ
  • URLを送ってくるUXが存在することでフィッシングにかかりやすくなる
  • URLつけたら届かないとかいう都市伝説も昔からある気がする

と言った観点からもSMSでリンクを送るのはよろしくないでしょう。

こんなことやってるから "Amazonをかたるフィッシングが報告全体の35.8%を占め、特にSMSによるものが多かった。" なんて言われてしまうのです。

右のメールの方も、

このEメールがAmazonから送信されていることを確認するにはどうすればよいですか? このEメールのリンクは「https://www.amazon.co.jp」で始まります。以下のリンクをいつでもブラウザに貼り付けて表示できます。

とか書いてあってなんとなく厳しい感じが伝わってきます。

URLの検証が困難なので個人的には避けたいところですがメールでURL送信は長い長い歴史があるので難しいところですね。

提案するなら

  • リンクは送るな
  • 何かを送ってそれを入力させる、2FAでよくあるフローの方がまだ良さそう
  • メールで怪しくないアピールするならURLにアクセスして表示された後もドメイン確認しろって言え

あたりでしょうか。

今度、アプリの方も見てみます。

おまけ

メールのタイトル。

f:id:ritou:20210709115031p:plain

何を言ってるんだ、amazon.co.jpはお前だろ。

ではまた。

FIDOアライアンスのUXガイドラインには何が書いてあるか

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

前の投稿でも取り上げたWebAuthnとかFIDO認証って呼ばれてる認証方式のお話です。

ritou.hatenablog.com

今回は、FIDOアライアンスからUXのガイドラインが出ているので紹介します。

fidoalliance.org

一言で言うと

MacとかiOSとかAndroidとかWindowsの生体認証が使えるデバイス上でWebアプリを使ってるユーザーに対して、新規登録/ログインフローのなかでをどうやってデバイスを登録させてFIDO認証を使わせるか

っていうお話です。

今回のターゲットとしては一般的なユーザーが使いつつ、強固なセキュリティが求められる銀行のWebアプリケーションのようなところを想定しています。FIDOにより一番平和になって欲しい世界のお話です。

これまでtoCのサービスでも、FIDO認証を取り入れる際には「YubiKeyのようなセキュリティキーを用意させるよりも "デバイス自体" を登録してWindows/Mac OS/iOS/Androidそれぞれで提供されている生体認証をする方が使われるようになるだろう」というのは以前から言われていました。

しかし、実際にどのようにデバイスの登録を求めるかと言ったあたりは先行して導入するサービスがそれぞれ探り探りやっているような部分があったので、このUXガイドラインによりその辺りの迷いが解消されることに期待せざるを得ません。

構成

UXガイドラインは3つのコンセプトとして User journey, Process steps, Use Case の3つがあります。

  1. User journey : エンドユーザーがFIDOのAuthenticatorを登録し、そしてログインするまでの処理が対象です
  2. Process steps: “sign in(ログイン)” とか “detect device eligibility(デバイスの適合性の検出)” みたいな細かい処理をまとめて “awareness” とか “consideration” と言ういくつかのゴールを表現し、目的を達成するためにこうしたら良い!ってのが整理されています
  3. Use Case: 銀行のWebアプリを想定してます
  4. Biometric sign-in or FIDO sign-in: 生体認証もしくはデバイスアンロック手段を用いたFIDO認証を利用することを想定しています

(3つと言いつつ4つ書いてあるじゃないか)

ゴールとProcess Stepsの関係はこんな感じで図示されています。

f:id:ritou:20210701121005p:plain

  • Awareness : このサービスはFIDO認証に対応してるよと伝える
  • Consideration : ログイン中のユーザーをAuthenticatorの登録に誘導する
  • Registration : Authenticator を登録する
  • Sign-out (post registration) : Authenticatorを登録してからそれでログインしたりログアウトしたり

と言う感じですが、まずは細けぇことはあまり気にせず画面ごとの要件を拾っていければ十分でしょう。

テストサイト

このUXガイドラインの参照実装として、テストサイトが用意されています。

https://digitalbank-test.com/

  • メールアドレスや電話番号などは不要
  • ユーザー名、パスワードで登録
  • 登録したユーザー情報は30日で消滅

となっているので気軽にお試しいただけます。が、どうせみんな見ないでしょう。 IDの技術なんてそんなもんです。「後で読む」「後で見る」IDおじさんは知っています。なので動画をとりました。

これはiPadでもちゃんと動いた!(けどAuthenticator登録完了時に必ずエラー出るな!)」って言う動画です。

www.youtube.com

ガイドラインにもこのサイトのスクリーンショットが掲載されています。 この後の説明でも実際に動作させた自分用のスクリーンショットを載せていきます。 では見ていきましょう。

UXガイドラインの内容紹介

Awareness: Sign in Pre-FIDO Registration

目的 : 自サービスでFIDO認証が可能であることを複数の方法で宣伝する

最初に、FIDO認証をサポートするデバイスを利用するユーザーに対して、永続的/一時的なメッセージングによりRelyingParty(FIDO認証を利用するサービス)がFIDOに対する認知度を高めることが説明されています。ユーザー調査によると、登録(Authenticator登録の意味かも?の)前に何度もFIDOの概念について触れる必要がありそうとのこと。

まず、未ログイン状態のログインフォームを見てみましょう。

f:id:ritou:20210701122430p:plain

ここにはFIDOと言う文字は出て来ません。プラットフォーム毎の生体認証っぽい画像を表示することでこのサービスは生体認証に対応してるんだな〜ってのを認識させようと言うのが狙いです。(私の環境はChrome on Mac OSなのでTouchIDっぽい指紋認証のアイコンが表示され、マウスオーバーで説明が出て来ます。AndroidWindows 環境の時はそれぞれのプラットフォームの中で使われている生体認証の画像を使うという細かい出しわけが紹介されています。)

この後に出て来ますが、うちのサービスはFIDO認証に対応してるんだ!ではなく、生体認証に対応してるんだよってアピっていくと言うのがポイントですね。

Because the FIDO brand is not yet familiar to most consumers...

謙虚!

他にも

  • セキュリティ設定変更機能からいつでもAuthenticatorを登録/削除できるようにする
  • eメールのチャンペーンやメール配信、ソーシャルメディアで生体認証が可能であることを通知する
  • CSに教育する

みたいな涙ぐましい努力をしながら、FIDO認証を促進していかなければなりません。

Consideration: Targeted invitations

目的 : FIDO認証をサポートするデバイスにログイン中のユーザーを、Authenticatorの登録画面へと案内する

Chrome on Mac OSSafari on iPad OSなどでテストサイトに登録して再度パスワードを用いてログインし、ログイン状態になったら、画面に案内用のメッセージが表示されます。

f:id:ritou:20210701122503p:plain

ここでの"FIDO認証をサポートするデバイス" ってのはいわゆる Platform Authenticator の利用が可能なブラウザのことであり、WebAuthnの仕様でいうところの "isUserVerifyingPlatformAuthenticatorAvailable()メソッド"を使って判断をしているように見えます。

なので、例えば同じPCでも生体認証が動かないブラウザの場合はこれは表示されません。

あと、ガイドラインにはもう一つ "Spotlight" page takeover invitation format for Mac users ってのが載ってます。 どっかの広告のように全面に主張してくる感じなんだと思いますが、どこで出るんやこれは...

その他、

  • パスワード認証に代わる安全な認証方式だという価値を示す
  • 案内のメッセージは "シンプル(シンプルな認証方式を利用できるよ)" もしくは "オプショナル(安全な認証方式を追加できるよ)" が効果的
  • 対象デバイスの場合は何回も案内しよう!けど設定は必須にせず、ユーザーの制御可能にしておく(ウザがられたらダメ。要はバランス...)
  • Authenticator登録ページにたくさんリンクさせる

などが記載されています。

Registration

目的 : 対応デバイスを利用しているユーザーにFIDOについての教育を行い、Authenticatorを登録させる

先ほどのトースト通知から "Register now" に進んでいくと、Authenticator 登録のための説明画面に遷移します。

f:id:ritou:20210701122534p:plain

  • この設定は必須ではないので右上の "×" から取り消すこともできる。ユーザーが制御可能なように
  • アニメーション画像で生体認証の流れを説明
  • 既にコンピュータのアンロックに使っている方法でアカウントにログインできることを説明
  • "Learn more" を押すとFIDOの説明が展開
  • FIDO CERTIFIEDなロゴ表示

ここぞとばかりにFIDOの説明してますが、これぐらいしないとユーザーは何だか分からなくて使わないってことなんでしょう。 ちなみにFIDOのロゴ利用についてはこの辺りを確認しましょう。

Logo Usage & Style Guide

Organizations that wish to use the FIDO logo on websites must adhere to the terms of our FIDO Trademark and Service Mark Usage Agreement for Websites license. You can download our logo files here.

Authenticate

目的 : Windows HelloやApple Touch IDでログインできるようにAuthenticatorを登録する

いわゆるAuthenticatorの登録処理です。 WebAuthnの仕様でいうところの "navigator.credentials.create()" を呼び出すところですね。

先ほどの画面から "REGISTER" を選ぶと処理が始まります。

f:id:ritou:20210701122600p:plain

成功すると画像も成功っぽくなってます。

f:id:ritou:20210701122624p:plain

失敗の場合もそれっぽく変わります。Platformごとの生体認証の画像に続いてこの辺りは芸が細かいなーと思ってしまいますが、現代のUXとしてはそれぐらいやらんといけないってことなのでしょうね。

ちなみにテストサイトでは Authenticator登録直後に100%の確率でIBMのなんたらエラー画面が出てウワッてなりますが、一旦心を落ち着けてトップのURLにアクセスしなおせば何事もなかったかのように続けられます。

FIDO Sign-in

目的 : 登録済みのデバイス上でユーザーをFIDO認証する

最後に登録済みのAuthenticatorを用いてログインさせる部分です。 WebAuthnの仕様でいうところの "navigator.credentials.get()" を呼び出すところですね。

テストサイトでは、ログアウトした後に

  • ユーザー名
  • "SIGN IN" ここからWebAuthnのログインが始まる
  • FIDO CERTIFIEDロゴ
  • ユーザー変更リンク : 空のパスワード認証フォームへ
  • パスワード認証への切り替え : ユーザー名が保管されたパスワード認証フォームへ

といった構成の画面になります。

f:id:ritou:20210701122653p:plain

これなら一回でログイン処理が走りますが、ここで注目なのは"ログアウト" してもユーザー名が保存されているということでしょう。

我々はつい "ログアウト" というと完全にセッションデータを吹き飛ばし、フォームに何もない状態からのやり直しを想像してしまいますが、そこからこの処理を行う場合は一度ユーザーを特定する必要があります。

この辺りは

  • 最後にログインしていたユーザーのユーザー名を記憶しておく
  • そのユーザーがFIDO認証を利用可能な状況(環境+デバイス)ならばログイン画面からすぐに開始できるようにしておく

というあたりを意識していく必要があるのかなと思います。 昔から "最後にログインした方法" "最後にログインしたユーザー" を記憶しておくみたいなアイディアはあるので、この辺りはもう少し整理しようと思います。

f:id:ritou:20210701122721p:plain

ちなみに後から気づきましたが、このテストサイトは Console Log に処理途中のデータもいくつか流しているのでWebAuthnの具体的な実装を見たいときにも参考にできそうです。

(ログアウト状態でも最後に利用したユーザー名が保存されているあたり)

f:id:ritou:20210701122805p:plain

(WebAuthnのログインが行われる時もログが吐かれるあたり)

f:id:ritou:20210701122821p:plain

それ以外にも、Authenticatorの管理もできるようになっているので、この辺も参考にできそう。

f:id:ritou:20210701122901p:plain

と言ったあたりで一連の流れに沿ってガイドラインの内容を紹介しました。

感想

今回のガイドラインには

アカウント登録 -> Authenticator登録 -> ログアウト -> FIDO認証でログイン

の流れに沿ってどのようなUXにしたら良いかというのが書かれています。 また、FIDOアライアンスからはいわゆる "アカウントリカバリー" のために複数のAuthenticatorを登録させるためのホワイトペーパーも出されていたりするので、今回のと組み合わせて参考にしながら実装してユーザーに提供する必要がありそうです。

すでにいくつかのサービスでFIDO認証は使われ始めていますが、開発者向けのサービスより一般的なユーザーに向けての啓蒙となるとより詳しい説明が必要になるでしょう。

ちなみに、個人的にこの前ちょっとハマったのが

  1. SMS番号やメアドを入力
  2. ユーザーの登録状態によって分岐
    1. Authenticator登録済みユーザーならWebAuthnの認証フロー開始
    2. Authenticator未登録ユーザーならSMS認証

みたいな処理をレガシーなフォーム送信を使って実装しようとしたら、iOS/iPad OSのSafariでうまく動かないと言う挙動にハマり苦戦しました。 理由はちょいと細かい話で、Safariはユーザーの明示的なアクションが起こらないとWebAuthnの処理が行われないようになっており、"ユーザーのクリック"をトリガーにする場合は問題ないものの、"ユーザーのSubmitボタンによるレガシーなWebアプリのフォーム送信"ではWebAuthnのフローが開始できないみたいな癖があります。Chromeでは問題なし)

今後作るときは、今回のUXガイドラインを参考にしたいと思います。

ではまた。

Appleの発表したPasskeys in iCloud KeychainはWebAuthnをどう変えるのか

f:id:ritou:20210615043226p:plain

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

先日のWWDC2021の "Move beyond passwords" というセッションにて発表された "Passkeys in iCloud Keychain" という仕組みについてどんなものかを紹介します。

developer.apple.com

WebAuthn

数年前からパスワード認証を置き換えると言われ続けている認証技術の一つである "WebAuthn" (やFIDO)という技術をご存知でしょうか。(ご存知ない方は "WebAuthn builderscon" "WebAuthn droidkaigi" などで検索してみましょう) 今回の話をするにあたって、WebAuthnがどんなものかをある程度理解しておく必要があります。

  • 公開鍵暗号の仕組みを利用
    • パスワード認証のようにユーザーとログイン対象のWebアプリケーションがパスワードを共有するのではなく、PC/スマートフォンの端末や外付けのセキュリティキーの中に秘密鍵、を保存しつつ生成した署名を送信、ログイン対象のWebアプリケーションが保存している公開鍵を用いて検証する
  • ローカル認証を利用
    • スマートフォンのロック解除に使われるような指紋、顔認証、パターン、4桁PINなど でユーザーを確認する
  • 認証フローにWebブラウザが介入して一連の認証処理が行われたOrigin情報をWebアプリケーション側が検証可能なため、フィッシングのリスクを排除できる

ということが特徴です。

WebAuthnでは秘密鍵が保存されているデバイスを所持していること、ローカル認証により意図したユーザーが操作していることを検証できるので、単体でもWebアプリケーションのログイン機能の要件を満たせる、かつフィッシング耐性もあるので素晴らしいものだ、という主張です。

この機能が普及するためのキモとして

があります。

前者については、YubiKey(Yubico)やTitan(Google)というようないわゆる "SecurityKey"だったり、スマートフォン/PC自体がその機能を持ちます。 後者についてもPC/スマートフォン向けの対応ブラウザが増えており、今後ますますコンシューマ/エンタープライズ両方での利用が増えていくであろうという状態だとここしばらく言い続けています。

しかし、このWebAuthnの悩ましい問題として、リカバリー困難問題” があります。

  • バイスに保存された秘密鍵は他の端末にシェア/コピーできない

という仕組みのために、デバイスが紛失、壊れてしまったら当然、そのデバイス内に保存されている秘密鍵を用いた認証が利用できなくなってしまいます。

  • スマホもセキュリティキーも、壊れたり壊されたり落としたり無くしたりとにかく平和じゃない(経験済み)
  • PC/スマートフォン自体に秘密鍵を保存するケースでは、新しい端末で使い始める時に手間がかかる
    • 一度 "別の方法" でログイン状態にしてから、"このデバイスでWebAuthnを利用する"(鍵ペアの生成、公開鍵のやりとり) という一連のフローをやりなおさないといけない
  • この "別の方法" で安全なものがなくて困る
    • WebAuthnが最強!なので他の認証方式だと認証強度が弱くなってしまうんじゃ
    • ベストなのは 認証に利用できる状態になったセキュリティキーを大事に引き出しの中にしまっておく ことだけど、コンシューマ向けのユーザーにそこまでさせるのは正直きつい

というのが長年議論されてきました。

Appleの動画にある比較表の"Security Key"の項目で、"Always with you" はユーザーがいくらWebAuthn使いたくても秘密鍵が保持されているデバイスがないとダメよってこと、"Recoverable" はデバイスロスト時に困るってことが表現されています。

f:id:ritou:20210615045708p:plain

Passkeys in iCloud keychain

散々前フリしたところで、Passkeys in iCloud keychainは、ここまで話したWebAuthnの困ってるところをうまく解決しようという試みです。

概要

一言で言ってみると、WebAuthnのキモである バイスに保存された秘密鍵は他の端末にシェア/コピーできない という部分を バイスに保存された秘密鍵を「安全な方法」で他の端末とシェア/同期できる ようにすることで、デバイスロスト/リカバリーの問題を解決しようとしています。

Appleの場合は、iCloud Keychainを用いることで他のApple端末とWebAuthnで利用する秘密鍵を共有するぞってわけです。

iCloud キーチェーンを使えば、パスワードやその他の機密情報をお使いのすべてのデバイスで最新の状態に同期できます。

support.apple.com

用語的には、"Passkeys" = "WebAuthnの秘密鍵を共有可能な仕組み" それを iCloud Keychainから利用するんだというのが "Passkeys in iCloud Keychain" だというところでしょう。いや、テキトーなことは言わんほうが良い。

WebAuthnとの利用フローの違い

例えば、WebAuthnに対応したWebサービスAと手元に🍎なデバイスが2台ぐらい(iPhone/iPad)があるとしましょう。

  1. iPhoneでは指紋認証を設定済み
  2. WebサービスAにiPhoneでログインし、新たなログイン方法としてiPhoneを設定
  3. WebサービスAをiPhoneから利用する際は指紋認証でOK
  4. iPadでは顔認証を設定済み
  5. WebサービスAにiPadから何らかの方法でログインし、新たなログイン方法としてiPadを設定
  6. WebサービスAをiPadから利用する際は顔認証でOK

となっていたところが、

  1. iPhoneでは指紋認証を設定済み
  2. WebサービスAにiPhoneでログインし、新たなログイン方法としてiPhoneを設定
  3. WebサービスAをiPhoneから利用する際は指紋認証でOK
  4. iPadでは顔認証を設定済み、iCloud Keychain で秘密鍵を同期!!!
  5. WebサービスAをiPadから利用する際は顔認証でOK

となります。

f:id:ritou:20210615053954p:plain

セキュリティキー(を持ち歩いてUSBの形があれやこれや言いつつとりあえず使えたわ!っていうの)と同じ体験がAppleバイスを持っててiCloud Keychainで同期してるってだけで味わえます。 このリストだけではあんまり便利になった感覚がないですが、これが複数のWebサービス×複数の端末ってなっていくとじわじわ違いとして現れてくるでしょう。

使い物になるかどうか、懸念点はないか

WebAuthnのデバイスロスト/リカバリーの問題を避けられるとなればWebAuthnの普及促進に繋がるでしょう。

秘密鍵の管理という点では、Passkeys in KeyChainはこれまで "デバイス単位" でセキュリティを担保していたものが、プラットフォームを支える "Identity単位" のセキュリティで担保することになります。 秘密鍵にアクセスできる端末が増えたということは、それだけ不正利用のリスクも増えると考えることもできます。 WebAuthnをログインに採用しているサービスから観ると、これまで設定済みの端末のみに絞られていたリスクが、iCloud Keychainで同期している全てのApple端末全体に広がってしまうことを認識する必要があるでしょう。

このメリット/デメリットを意識するまでもないコンシューマ向けサービスにとっては良いニュースだと思いますが、NIST SP800-63シリーズ で定義されている、厳密なユーザー認証の強度(Authenticator Assurance Level, AAL)を厳密に意識する必要のあるレベルのサービスには多少気になるかもしれません。 "他の端末にシェア可能な秘密鍵は利用できない" "Passkeys in Cloud KeyChain経由のアサーションは受け入れない" みたいな細けぇ分岐処理が出てきたらカオスになるので避けたいところです。

ID連携との違い

Appleはこれを独自の技術としてアッピールするというよりは、「他のPlatform(と言ってもGoogle/Microsoftを名指ししているようなものですが)でも同じような仕組みを用意して使って行ったらいいじゃない」みたいなスタンスを取ろうとしているのが新鮮なところですが、結局大きなPlatformを持つ巨人たちのための仕組みじゃねーか と感じる人もいるでしょう。

バイスからIdentityへみたいなことを言ったついでに、Sign in with Appleのようないわゆる "ID連携" と今回の "Passkeys in Keychain" の仕組みの比較をしてみたいと思います。

  • Webアプリ側はWebAuthnのプロトコルを意識するだけで、しれっとAppleアカウントのセキュリティの恩恵を受けられるのが "Passkeys in Keychain"
    • 開発者はWebAuthnに対応するだけ
    • ユーザーは個々のWebアプリごとに一度手元のApple端末でログインの設定が必要
  • Webアプリ側が明示的にAppleアカウントの恩恵を受けにいけるのが "Sign in with Apple"

Sign in with Appleでも顔認証などを使ってパスワードなしで認証できることから、"WebAuthnによるログインやID連携の設定済みの状態でApple端末からのUX" という点では同等になり得そうですが、開発者、ユーザーと言った視点では細かい違いがあることを意識しておきましょう。

この辺りの比較は、実際に動きを見れる状態になってから比較してみるのが良さそうですね。 できるようになったらやります。

まとめ

  • WebAuthnはセキュリティキーや対応デバイス単位で秘密鍵を保管する仕組みだったが、デバイスロストやリカバリーなどに課題があるってずっと言ってる
  • Passkeys in iCloud KeyChainはiCloud KeyChainの同期の方法を用いて、秘密鍵を安全に共有するための仕組みである
  • バイスからIdentityレイヤーにコンテキストが変わることで、ID連携に近い感覚になるが、こまかいところで違いがある

というお話でした。何はともあれ、普及が楽しみですね。 質問があったらマシュマロかTwitterでいつでもどうぞ〜。

marshmallow-qa.com

ではまた!

【久々の投稿と思ったら】Web24というイベントで 5/8 12:50~14:20にお話します【告知】

お久しぶりです、ritou です。

今週の金/土に行われるこんなイベントにお誘いいただいて、5/8 12:50~14:20にWebアプリケーションとIDについてセッションオーナーとして議論させてもらうことになりました。ハッシュタグ#web24_id です。

connpass.com

どんな展開になるのかのネタばれではなく、最近の私の思いを少し書いておきます。

一言で"WebアプリケーションとID" と言っても、

  • いわゆる認証方式
  • 登録から退会までのライフサイクル
  • ID連携

など多岐にわたっています。

さらに、Webアプリケーション単体で見た時も

  1. Webサーバーからの応答だけ
  2. Webサーバー + SPAのようなクライアントの組み合わせ...
  3. Webブラウザが提供するAPIを利用...

という具合に考慮すべき範囲が複雑化しており、IETFW3Cでは新しいプロトコルAPIが続々と策定されていく... 開発者が個別の機能の要件をしっかりと理解して作り込んでいくよりも、フレームワーク、IDaaSなどを用いて安全性を担保しながらアプリケーションを作り込んでいく時代にあると言えるでしょう。 当然、サービスとしてモバイルアプリケーションが存在する場合はさらに考慮すべき点も増えそうです。

そんな時代に開発者はどのようにIDと向き合っていくべきか、というのをお話できたら良いのかなーと思っており、個人的に標準化仕様、ライブラリやプロダクト開発辺りを意識できる3人の方 にお声がけをさせていただきました。 特に打ち合わせも台本もなくやっていくのでどんな展開になるかは想像もつきませんが、なんとか盛り上がったら良いなと思います。 お時間のある方は見に(聞きに)来て下さい♪他のセッションも豪華メンバーで楽しみですね!

ではまた!

f:id:ritou:20210502175057p:plain

最近よく見かける初心者エンジニアが転職の際に作る今時のポートフォリオに必須だと噂の「ゲストログイン」について

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

f:id:ritou:20210131121026p:plain

タイトル長くてすみません。

QiitaでID連携や認証まわりの投稿記事を見ていると、最近「ゲストログイン」という文字列が目に止まることが増えたので何か書いておきます。

ゲストログインとは

「ゲストログイン」の検索結果 - Qiita

実はそんなに引っかかりませんが、このゲストログインと呼ばれる機能、実装者により内容もバラバラです。 どれが正解ってのもない気はしますが、1/31ぐらいの検索結果からどんな認識なのかを見てみます。

qiita.com

ポートフォリオ必須といわれているゲストログイン。

そうなの?

それとは異なり今回のゲストログインはあらかじめ設定されたデータでUserを新しく作成します。 なので「ゲストログイン」より「簡単新規作成」の方が言葉的に近いかもしれません。

  def guest
    user          = User.new(user_params)
    user.name     = "ゲストユーザー"
    user.email    = SecureRandom.alphanumeric(15) + "@email.com"
    user.password = SecureRandom.alphanumeric(10)
    user.save
    sign_in user
    redirect_to how_to_path
  end

ランダムデータで新規登録&ログインさせる系っぽい。

qiita.com

ポートフォリオを作成する際はゲストログイン機能が必須と言われています。

やっぱり、そうなんだ?

Google認証やTwitter認証を頑張って導入しても、自分のアカウントを使うことが心理的なハードルになって、アプリを良く見てもらえない可能性が出てしまいます。

ソーシャルログインに心理的ハードル...ザワザワ

const user = { name: 'ゲストユーザー', email: 'guest@example.com' };

予め用意してたユーザーでセッション生成っぽい。

qiita.com

今回はポートフォリオを見てもらう確率を上げるために必須な、簡単ログインの実装方法を書いていきます。

また必須言うてる。これあれじゃないの?スクールでそう言われた系じゃないの?

  # emailでユーザーが見つからなければ作ってくれるという便利なメソッド
  user = User.find_or_create_by(email: 'guest@example.com') do |user|
  # 自分はユーザー登録時にニックネームを必須にしているのでこの記述が必要
  user.nickname = "ゲスト"
  # 英数字混合を必須にしているので、ランダムパスワードに、英字と数字を追加してバリデーションに引っかからないようにしています。
  user.password = SecureRandom.alphanumeric(10) + [*'a'..'z'].sample(1).join + [*'0'..'9'].sample(1).join
  end

ニックネーム、メアド固定のゲストさんで(最初は登録しつつ)ログイン状態に。パスワードはなんとなく設定する。

qiita.com

新規登録で mail: guest@guest, password: 111111で登録していること

この人でログインさせる。

qiita.com

たくさん読まれてるやつ。自分もコメントしてみたけどもなんだかもうカオス。 上記の予め用意していたアカウント系のリスクが書いてある。

qiita.com

転職活動用のポートフォリオ等にゲストログイン機能があると、多忙な採用担当の方の負担が減り、アプリを利用してもらえる確率が高まるメリットがあります。

利用した気にさせることが大事っぽい!

ゲストログイン用のユーザー(ゲストユーザー)の登録されている

予め用意されている系

※セキュリティをしっかり固める場合、ゲストユーザーのアカウントを通常のユーザーアカウントと一緒に、usersテーブル/Userモデルで管理するのはあまり望ましくありません。

これはわからん。一緒でもいいだろ。

最後に、セキュリティ的な対策です。 もしあなたの開発しているアプリに、ユーザー名やメールアドレス等を編集できる 「ユーザープロフィール編集機能」がある場合、 ゲストユーザー用アカウントのものに関しては変更できないようにした方が良いと思います。

ゲストユーザーを扱うためにアプリにも分岐入れて判断とかが必要。

と言うところで、どうやら

  • ポートフォリオにゲストログインは必須
  • とは言え定義はなんかふんわりしてる
  • **予め用意したユーザーでログインさせる系が多い

ってぐらいな感じです。

本当にこの程度の機能でアピールになるのかは採用側の経験者の意見も聞きたいところですが、 控えめに言うと フレームワークが標準で提供していない機能を追加するだけでも価値はあるでしょうし、想定外のことが起きてそれに対応することも経験としては重要な気はします。

みたいなことをTwitterで言ってたら質問来てました。

せっかくなのでこれぐらいまで実装したら実用的かも?ってのを書きます。

実用的なゲストログインとは

そもそも「ゲストログイン」と言うか「ゲストユーザー」機能ってのの実用的、汎用的な要件はどうなんでしょう。

  • ECサイトで会員登録をせずに商品を購入するゲスト購入
  • ゲーム系のサービスで会員登録をせずにある程度まで使えるお試しプレイ

あたりを考えてみると、

  • メアド確認やパスワード設定など、新規登録をせずともある程度もしくはフルでサービスが利用できる
  • 他の端末、セッションからは同じユーザーでログインできない/紐づけられたデータを流用できない
  • サービスが気に入ったら改めて新規登録を行い、データは引継ぎつつ全てのサービスを利用できたりできなかったり

みたいなところが要件として出てくるのではないかと考えます。 それを設計/実装に落とそうと思うと

  • Userモデル
  • セッション管理
  • アクセスコントロール
  • 本登録処理とデータ引き継ぎ

あたりになります。それぞれのポイントを整理してみましょう。

Userモデル

まぁ、こんなのは一例でしかないわけでありますが、Userモデルに対する要件としては

  • ゲストユーザーであることを判定できる
  • メアドなどを識別子とする場合は空
  • パスワードなどのクレデンシャルが空
  • ニックネームなどプロフィールは登録可能

ぐらいでしょう。

小規模なアプリにありがちなUserモデルであれもこれも含むてんこ盛りモデルだったりすると "必須" 項目になっているものがあり、なかなか対応が困難になる場合もあるかもしれませんが、あまりランダムな値などを入れるのは望ましくないでしょう。

上記の記事でメアドやパスワードにランダムな値をいれるような実装もみられましたが、実際のプロダクトで "設定することでログイン可能になる" 場合は "知らないからいいだろう" と言う話でもないでしょう。

これは極端な例ですが、規模が大きくなることを想定したアプリなどで細かくテーブルを分けるようにするなら、

  • 識別子を払い出す : User(ID発行は既存のものと一緒で良い)
  • 識別子とロール : UserRole としてゲスト状態を保持
  • 識別子とメアドを紐付ける : UserEmail を持たない
  • 識別子と認証方式、クレデンシャルを紐づける : UserCredential を持たない
  • 識別子とプロフィール情報 : UserProfile は持つ

みたいな管理をすることで、ゲストユーザーの要件に対応できそうです。

ゲストユーザー用のモデルを用意する方法もあり得るとは思いますが、この後言及するアクセスコントロールの部分やデータ引き継ぎなどを実装する際に既存のアプリの機能に大きな改修が入らないように気をつける必要があります。

セッション管理

ECのゲスト購入であれば、購入フローで必要な値を引回す必要があります。 これは未ログイン状態のセッションに紐づけることでも実装できますが、この後言及するアクセスコントロールをしっかり実装できるならば、ゲストユーザーによる処理を開始する際に

  • ゲストユーザーを作成
  • セッションとの紐付け

を行うことで実現できそうです。

アクセスコントロール

ビジネス向けに比べて比率は少ないかもしれませんが、コンシューマ向けのサービスでもユーザーのロールを意識してサービスの利用制限を行う例はあるでしょう。 例えばゲームなどでいわゆるユーザーランクによって利用できる機能が解放されると言うことはそれに近いかもしれません。ゲストユーザーを扱う際も同様です。 上記の記事でも触れられていたものもありましたが 「ゲストユーザーが利用できない機能」を決めておき、利用制限をしっかり行うこと も重要でしょう。

本登録処理とデータ引き継ぎ

ゲームなどのゲストログインでは

  • ゲストユーザーの利用が制限された機能を利用しようとした
  • 利用可能なゲームのポイントを失った

と言うあたりで本登録処理を促し、そのまま設定などを引継いで利用できるような実装が必要となりそうです。 ECサイトでは購入フローが完了した後などに会員登録を促して継続的な利用を促したりもするかもしれません。

Userモデルのところで意識したゲストユーザーと通常のユーザーの違いを意識して、既に設定してあるプロフィール情報や同一セッションでユーザーが入力した情報は生かしつつ不足している部分を埋める実装が必要となるでしょう。

まとめ

  • 最近目に付くゲストログインについて調べた
  • ここまでやれば実用的かな?ってとこを説明した
  • スクールかなんか知らんけど、ゲストログインを課題にするならもうちょい詳しく教えろ

転職を考えている初心者エンジニアの皆さんの成功と、より一層のご活躍をお祈り申し上げます。

以上です。

おまけ画像

f:id:ritou:20210201034652p:plain

f:id:ritou:20210201034706p:plain

ではまた!

噂のマイナンバー要求APIをCIBA+FIDOで作れないか考えてみた

f:id:ritou:20201212024655j:plain

こんばんは、ritouです。

Digital Identity技術勉強会 #iddance Advent Calendar 2020 15日めの記事です。

qiita.com

何の話か?

このプレスリリース、ニュースを覚えていますでしょうか。

www.jiji.com

マイナンバー要求APIの説明としては

事業者が同APIを導入すると、利用者にマイナンバー提出をリクエストすることが可能となります。それを受けた利用者は、PINコードを入力、もしくは生体認証(指紋または顔認証)した後、マイナンバーカードのQRコードスマホで読み取り、そしてカード本体をNFCで読み取るだけで瞬時にマイナンバーを提出することができます。

とあります。これはこれで "瞬時にマイナンバーを提出"とはどの部分にかかってるのかが気になる文章ではありますが、xIDのサイトにも説明があります。

my-number.x-id.me

今日はこのマイナンバー要求APIの仕組みを標準化仕様、既存の技術を組み合わせて作るとしたらどんな感じかと言うところを考えてみます。

マイナンバー要求APIのフローを理解する

上述のサービスに概要が書かれております。

f:id:ritou:20201210034727j:plain

(引用元 : https://my-number.x-id.me/)

xIDアプリでやることっていうのがこの図ですね。

f:id:ritou:20201210041807p:plain

(引用元 : https://www.jiji.com/jc/article?k=000000023.000037505&g=prt)

これを5つの処理に分解しましょう。

  1. サービスからのマイナンバーリクエスト : 属性情報要求
  2. ユーザーへの通知、確認コード選択 : ユーザーへの通知
  3. PIN or 生体認証 : ユーザー認証
  4. マイナンバー入力 or QR読み通り + マイナンバーカード読み取り : マイナンバー取り扱いのためのお約束
  5. 暗号化して送信 : 属性情報応答

で、それぞれの処理に標準化仕様をあてはめてみましょう。

  1. 社内のマイナンバー登録フローみたいなのに入り、サービスはこのユーザーのマイナンバーが欲しいとxIDに要求、ユーザーには確認コードを表示 : →CIBA
  2. xIDはアプリへの通知を用いて「サービスがマイナンバーを欲しがってるよ」と通知、ユーザーは表示された確認コードと一致するものを選択 : →CIBA
  3. 通知を受けたxIDアプリでPINもしくは生体認証を行うことで2FA完了 : →FIDO
  4. マイナンバーを入力もしくはQR読み取りを行い、さらにマイナンバーカードをNFCで読み取る : マイナンバー取り扱いのお約束
  5. xIDアプリで暗号化されたマイナンバーがサービスに返される : →CIBA(w/ JWE?)

1,2,3について、「手元のスマホでログイン」的な流れ、利便性を上げるためにFIDOとの組み合わせ、なんてところは本ブログで何度も扱ってきた通りです。 4の処理については「民間事業者におけるマイナンバーカードの活用」というPDFなどに記載されている券面事項入力補助APを使う際のアクセスコントロールに従っているようです。

https://www.cao.go.jp/bangouseido/pdf/topic_card_minkan.pdf

あとは5のところでモバイルアプリの段階で暗号化して送ってサーバーも見れませんよ!って言えるなら出来上がりでしょう。

CIBA/FIDO で作るマイナンバー要求API

ここまで分解できれば、あとはシーケンス書いてそれぞれの処理を整理しましょう。

登場人物

実際はxIDのアプリの他にxIDのバックエンドサーバーがいるだろうと言うところで、登場人物は4人と言うところでしょうか。

  • RP : マイナンバーを要求するサービス
  • IdP(Backend) : マイナンバー要求API(xIDのサーバー)
  • IdP(MobileApp) : xIDアプリ
  • EndUser : マイナンバーカードを保持するユーザー

シーケンス

シーケンスはこんな感じでいけそうです。

f:id:ritou:20201212015723j:plain

それぞれを見ていきましょう。

RPからIdPにマイナンバー要求、受付応答

f:id:ritou:20201212020534j:plain

CIBAにおける、バックチャネル認証リクエストに相当します。

  • RPは社員番号、メールアドレスなどを login_hint などとして指定
  • 確認コードは binding_message として指定

CIBAにはPOLL/PING/PUSHと言ったモードがありますが、ここではPOLLモードを想定し、auth_req_id が返されます。

確認番号の選択

f:id:ritou:20201212021643j:plain

これは以前、手元のスマホでログインみたいなのをCIBAで実現しよう!みたいな記事でも触れた気がしますが、EndUserがこのフローの正しい利用者であることを確認する仕組みとして binding_message をうまく使うことで実現できそうです。 この、3つ表示して1つ選ばせるみたいな部分は結構普通に使いそうなので、CIBAの仕様として組み込んでも良さそうな気はしています。

PIN or 生体認証

f:id:ritou:20201212022016j:plain

xIDアプリは所持 + αの2要素認証をうたっています。 それに相当する仕組みとして、ここでは FIDO を用いることで実現できそうです。

マイナンバーカードのお約束

f:id:ritou:20201212022229j:plain

ここは標準化仕様というよりもガイドライン的なものに従って作る感じですね。

暗号化したマイナンバーのやりとり

f:id:ritou:20201212022438j:plain

この辺りはモバイルアプリでJWE形式にしたIDTokenを生成、もしくはマイナンバーだけを暗号化するなどよしなにしてバックエンドサーバーが復号できない状態とし、RPまで返してやる、そして破棄することで実現できそうです。

まとめ

  • マイナンバー要求APIの仕組みを分解してみた
  • CIBA/FIDOとかを組み合わせたら作れそうだったのでシーケンスなどを考えてみた

いかがでしたでしょうか。 ある程度、認証認可周りのプロトコルの理解が進んだ状態であれば、何か新しい仕組みが出てきたときにこんな感じかなーと考えて見ることもできるでしょう。 まぁ実際に実装するとなると細かくいろんなこと決めないといけないんでしょうけど、頭の体操をしてみても面白いのではないでしょうか。

何か気になることがありましたら、匿名でも質問受け付けておりますので気軽にどうぞ!

marshmallow-qa.com

私のアドカレ次回作は12/25の予定です。

qiita.com

で、その間に会社のやつを20日にQiitaの方に書く予定です。

qiita.com

ではまた!

参考

qiita.com

ritou.hatenablog.com

ritou.hatenablog.com

ritou.hatenablog.com

Identity Lifecycleを意識したID管理機能の設計

f:id:ritou:20201207033809j:plain

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

Digital Identity技術勉強会 #iddance Advent Calendar 2020 7日めの記事です。

qiita.com

OIDCとかFIDOとかOAuthとかGNAPとかいろいろな話題の記事が書かれて素晴らしいですね。

今回はID管理の設計の話をしましょう。

ID管理機能、どう作る?

新しいサービスを作る時、必ず必要となるのがID管理機能です。

ID管理!なんていうとエンプラ臭いですが、コンシューマー向けのサービスでも

  • 認証方式どうする?ソーシャルログイン?パスワードレス?自前でパスワード認証...
  • 新規登録ではメアドやSMS確認してパスワード設定させて...
  • パスワード認証の機能作って...
  • 再認証もできないとダメだし...
  • メアドやSMS、パスワード変更も必要だ
  • リスト攻撃怖いから2要素?2段階?できます
  • リカバリーめんどくさい問題
  • 退会の時、データ消す?残す?
  • サスペンド機能が欲しい?承知しました

とかいう流れは普通にあるでしょう。

このあたり、漏れなく設計/実装するために、どんなことに気を付けたら良いでしょうか。

社内にこの辺得意そうな猫がいたらそれに任せるでいいと思いますが いわゆるWeb Application Frameworkについてくる機能に任せたり、Googleとか有名なサービスを真似してなんとなく作ったりしてるとこも多いのではないでしょうか。

そんなのサービスの本質ではない!今はIDaaSの時代!IDaaSを使え!

という流れもありつつも、IDaaSの選定をするにも必要な機能をちゃんと整理できている必要があるでしょう。 今回は、ID管理機能の設計の際に "Identity Lifecycle" というのを意識してみましょう というお話を書きます。

Identity Lifecycle @ ISO/IEC 24760-1

ID管理についての様々な定義が書かれている、ISO - ISO/IEC 24760-1:2019 - IT Security and Privacy — A framework for identity management — Part 1: Terminology and concept というドキュメントに "Identity Lifecycle" が記載されています。

www.iso.org

("The electronic version of this International Standard can be downloaded from the ISO/IEC Information Technology Task Force (ITTF) web site" ってとこから辿れば無料でダウンロードできます。)

"Identity Lifecycle" はB向けC向け関わらず、Identity Systemにおける状態と状態遷移を表現したものです。

f:id:ritou:20201206015413j:plain

5つの状態

f:id:ritou:20201206015424j:plain

ユーザーが取りうる5つの状態が定義されています。

  • Unknown : 未登録や退会して完全にデータを消去した状態
  • Established : データはあるけどまだサービスは使えない、仮登録的な状態
  • Active : 本登録が終わってサービスを利用できる
  • Suspended : 一時的に利用できない
  • Archived : データは残っているけどサービスは利用できない、論理削除の退会済み的な状態

これは割と直感的かと思います。

状態遷移

f:id:ritou:20201206015435j:plain

そしてその状態遷移として、いくつかのアクションがあります。 仮登録、本登録、登録情報更新、一時利用停止、退会など直感的なものもあれば、C向けサービスだとこれあるかな?と考えてしまうものもいくつかあります。

ID管理機能の設計にどう活かすか

新たに設計を行う際にこれを意識できれば一番良いんでしょうけれども、ある程度設計が進んだ段階で 想定している機能に不足がないかを確認する ぐらいでも良さそうです。

  1. "自サービスでユーザーが取りうる状態" を確認
  2. その状態間で取りうる状態遷移から、機能に不足がないかを確認する

ちょっといくつかのパターンでやってみます。

パスワード認証

パスワード認証を利用しつつSMSやメールでリカバリーできる、一刻も早く滅びて欲しい感じの設計です。

  • 最初にSMS/メールの確認、終わったらパスワードや属性情報登録して利用可能
  • 一時利用停止あり、退会しても一定期間データを残す

みたいな場合、こんな感じになるでしょう。

f:id:ritou:20201206022842j:plain

使わない遷移をオリジナルのやつから削ったりちょっと変えてる部分があります。

それぞれを見ていきましょう。

f:id:ritou:20201206022905j:plain

仮登録的な意味合いでまずメアド/SMSの登録ですね。

最初にパスワードやプロフィール情報の入力も同時にやってからのメアド/SMS確認ならここでしょう。

f:id:ritou:20201206022930j:plain

メアド/SMSを確認してパスワード、プロフィール情報を登録して本登録完了。

f:id:ritou:20201206023015j:plain

メアドやパスワード、プロフィール情報は変更機能も必要です。 未ログイン状態からのパスワード変更と捉えると、パスワードリセットもここに含まれるかもしれません。

f:id:ritou:20201206023042j:plain

悪いことをしたり、されたり(不正ログイン)した場合は一時停止の機能が必要ですね。

f:id:ritou:20201206023108j:plain

退会処理も、すぐにデータを消すのではなく一旦 "Archived" な状態にしておいて、やり直しがきくようにします。 (オリジナルのやつと変えて"Restore" のところを "Archived" から "Active" に戻してるのは("Archived" -> "Established" -> "Active") の省略みたいなところです。) そして、一定期間が過ぎたり申告などで全部データを消しますよと。

こんな感じで、一通りの機能をカバーできてるかなと思います。

ソーシャルログイン

Googleでログインとかでさくっと使えるサービスの場合はまたちょっと変わりますね。

  • IdPから確認済みメアドがもらえたらそれ使う、もしもらえなかったりした場合は個別で確認もできる
  • 退会したら即データ消去。同じIdPのアカウントで再登録したら1からやり直し

みたいな場合、こんな感じになるでしょう。

f:id:ritou:20201207024802j:plain

"Unknown" から "Active" への遷移を増やしたり、"Archived" な状態を消したりしてます。

f:id:ritou:20201207024937j:plain

未登録で確認済みメアドを持ってるIdPのアカウントが来たら即登録完了、これがソーシャルログインの醍醐味でしょう。 (直接の状態遷移でなくても内部で "Established" -> "Active" と遷移してるよ、と捉えても良さそうです)

f:id:ritou:20201207024952j:plain

ざっくりソーシャルログインと言っても、

  • 認証のための識別子 : IdPの識別子 + IdPから受け取ったユーザー識別子
  • 連絡先などの確保 : 確認済みメアド
  • その他属性情報 : IdPから受け取ったプロフィール情報

と細かく整理できていれば、

  • IdPから確認済みメアドが受け取れないケースにも対応する
  • 複数IdPに対応しており、同じメアドを受け取った場合に(追加で認証するなどして)既存のアカウントと紐付ける、もしくは別ものとして連絡先を確認するかをユーザーに決めてもらう

みたいなことができます。

実際はあまり見かけませんが、確認済みメアドがなかった場合を仮登録状態として、ここから確認したら登録完了みたいな設計もありでしょう。

f:id:ritou:20201207025008j:plain

なのでこの状態遷移も残しましたよと。

f:id:ritou:20201207025024j:plain

別のIdPのアカウントと紐付け直し、メールアドレスの変更機能が必要ですね。

f:id:ritou:20201207025051j:plain

IdPのアカウント単位でブラックリストに入れたり、IdPから不正利用があったよと通知が来たりしたら一時的な利用停止もあり得るでしょう。

f:id:ritou:20201207025108j:plain

退会でIdPとの紐付けなどのデータをバッサリやっちゃうならここはシンプルになるでしょう。

どうでしょうか。このパターンも一通りカバーできてそうな気はします。

パスワード認証 + 2段階認証

追加認証があっても状態/状態遷移が増えなければパスワード認証の場合と変わらなそうです。

パスワード認証 and/or ソーシャルログイン

取りうる状態/状態遷移が異なる認証方式が組み合わされている場合、当然増えた状態/状態遷移を追加することになるでしょう。

IDaaS利用時にも参考にできる?

機能単位で使っていけるパターンなら、これまで書いてきたような考えを適用してIDaaS側、利用する側でそれぞれ機能が足りているかどうかを確認し、選定時に役立てられるのではと思います。

まとめ

  • ISO/IEC 24760-1にIdentity Lifecycleと言うものが定義されているよ
  • ユーザーの取りうる状態、状態遷移を意識することで、設計中/実装済みのID管理機能において不足してる部分がないかを確認できそうだよ

と言うお話でした。

匿名でも質問受け付けております!

marshmallow-qa.com

私のアドカレ次回作は12/15です。

qiita.com

正直そろそろしんどくなってきました!ではまた!

OAuth認証とは何か?なぜダメなのか - 2020冬

f:id:ritou:20201108013816p:plain

こんばんは。ritouです。

Digital Identity技術勉強会 #iddance Advent Calendar 2020 1日めの記事です。

qiita.com

初日なのでゆるふわな話をしましょう。

何の話か

もうだいぶ前ですね。9月のお話です。こんなTweetを見かけました。

このbotに対する思うところはもう良いです。

今回は、「OAuthの仕様に沿ってID連携を実装するいわゆる"OAuth認証"の実態に迫り、なぜダメなのか、そして代わりにどんな方法があるのか」 を振り返ります。

(追記)長いので結論から先に

  • OAuthとOIDCで 目的が違う ことはよく知られている
  • OAuthのリソースアクセスの仕組みだけを利用してクライアント側がID連携の実装を試みても最低限の要件を満たせず、クライアントの構成によっては認可サーバー、リソースサーバー側の拡張が必要となる場合がある
  • ID連携のためには「●●でログイン」と言う認証イベントを実施したユーザーの情報を "安全に" やりとりする仕組みが必要
  • TwitterGithub, Facebook安全に利用できるフローを示したり、不足している部分を独自に拡張したりしてOAuth認証を可能にしている
  • OpenID ConnectではOAuth認証で独自実装になり得る部分を標準化仕様としてサポートしているのでご利用ください

それでは始めましょう。

OAuth認証とは?そもそもOAuthとは?

OAuthは異なるサービス間での「APIアクセスのためのアクセストークンの発行(取得)」や「アクセストークンを用いたAPIアクセス」と言う、APIの保護を目的として標準化された仕様です。

雰囲気でOAuthやっちゃってた勢に人気の本を意識しながら、OAuthの登場人物から振り返ってみましょう。

f:id:ritou:20201127103729j:plain

  • 認可サーバー : アクセストークンを発行するサービス(例:Google アカウント)
  • リソースサーバー : アクセストークンを利用したリソースアクセスの対象なるサービスで、認可サーバーと一緒でも別でも良いが実際のサービスでは同一サービス内の別機能的な立ち位置が多い。(例:有料化が話題となったGoogle フォト)
  • クライアント : 認可サーバーからアクセストークンを取得し、リソースサーバーにリソースアクセスを要求するサービス(例:画像編集アプリ)
  • リソースオーナー : リソースサーバーが提供するリソースの所有者(例:Googleのユーザー)。ユーザーの場合もあるし、クライアント自身がリソースオーナーになるパターンもある。

処理の流れを見ていきます。

f:id:ritou:20201127103748j:plain

  1. クライアント(画像編集アプリ)は認可サーバー(Google アカウント)にリソースサーバー(Google フォト)で管理されているデータへのアクセスを要求
  2. 認可サーバーがリソースオーナー(Googleアカウント)を認証し、クライアントへのリソースアクセス許可についての同意を得る
  3. 認可サーバーはクライアントにアクセストークンを発行
  4. クライアントは、アクセストークンを用いてリソースサーバーにあるリソースオーナーの画像を返すAPIにアクセスし、取得した画像を編集対象として利用

OAuthの特徴としては

  • APIはアクセストークンにより保護される
    • 3rdパーティーなクライアントでも有効なアクセストークンを持っていたらリソースオーナーの代理としてアクセスOK
  • 認可サーバーがリソースオーナーの認証とアクセストークンの発行を行うため、3rdパーティーなクライアントは直接リソースオーナーのクレデンシャル(パスワードなどの認証に必要な情報)を扱う必要がない。よって安全!

となります。ここまでがOAuthの説明です。

そして、OAuth認証とは、 クライアントが「●●でログイン」のようないわゆるID連携、ソーシャルログインをOAuthの仕組みを利用して実現すること です。

f:id:ritou:20201127103809j:plain

  1. クライアントは認可サーバーに リソースオーナーの情報へのアクセス を要求
  2. 認可サーバーがリソースオーナーを認証し、クライアントへのユーザー情報提供についての同意を得る
  3. 認可サーバーはクライアントにアクセストークンを発行
  4. クライアントは、アクセストークンを用いてリソースサーバーにあるアクセストークンからリソースオーナーの情報を返すAPIにアクセスし、取得したリソースオーナーの情報に含まれるユーザー識別子など を自サービスの認証に利用する

このような手順を踏むことで、クライアントは認可サーバー/リソースサーバーから 「ログインしようとしたのは誰か」 を知ることができ、自身の認証に利用できるでしょうという考えですね。

何がいけないのか?

たまに 「OAuthは認可の仕組みであり、認証の仕組みではないのでOAuth認証はダメ」 という言い方を目にしますが、もう少し踏み込んで整理しましょう。

ID連携の最低限の要件

「●●でログイン」しようとしたユーザーの識別子を取得する ことはID連携における、最低限の要件です。 もっと複雑な用件については後述するとして、ここではOAuthの仕様を利用してその要件を満たす実装ができるのかどうかを確認しましょう。

繰り返しになりますが、OAuth 2.0の最も基本的な仕様では

  • アクセストークンをこうやって取得できます(RFC 6749)
  • アクセストークンをこうやって利用できます(RFC 6750)

というのが定義されており、逆にいうとそれしか定義されていません。 よって、クライアントがOAuthを用いてID連携をしようと思うと

  • 「●●でログイン」しようとしたリソースオーナーのアクセストーク を取得しよう
  • アクセストークンを使ってプロフィールAPIなどからユーザー識別子を取得して認証に利用しよう

という考えになるわけです。

(認可サーバーがアクセストークンと一緒にユーザー識別子を返すような実装も見かけましたが、拡張となるので今回はおいておきます。)

アクセストークンの役割とのミスマッチ

ここで、”OAuth認証" を用いたWebアプリケーションのID連携でよくある実装を例示します。 よく知られているOAuth 2.0の認可コードフロー を利用します。

f:id:ritou:20201128231132j:plain

  1. Webアプリであるクライアントがサーバサイドのライブラリなどでアクセストークンを取得する
  2. リソースサーバーにあるプロフィールAPIからリソースオーナーの情報を取得する
  3. 取得したリソースオーナーのユーザー識別子を用いて認証する

この流れを安全に実装することは、可能です。

  • OAuth 1.0であったり、OAuth 2.0の「認可コードフロー」を用いたアクセストークン取得までの一連の流れで 「●●でログイン」しようとしたリソースオーナーのアクセストークンであること が担保される
  • アクセストークン取得後にリソースアクセスを行い、 「●●でログイン」しようとしたリソースオーナーのユーザー識別子であること が担保される

と言うことで、「●●でログイン」しようとしたリソースオーナー の情報をハンドリングできる場合は問題ありません。

次に、クライアントはモバイルアプリとバックエンドサーバーで構成されている場合の実装を例示します。

f:id:ritou:20201128231146j:plain

  1. モバイルアプリがSDKなどでアクセストークンを取得する
  2. モバイルアプリはバックエンドサーバーにアクセストークンを送信
  3. バックエンドサーバーはリソースサーバーにあるプロフィールAPIからリソースオーナーの情報を取得する
  4. バックエンドサーバーは取得したリソースオーナーのユーザー識別子を用いて認証する

(これ以外に 「モバイルアプリ」はただのリダイレクタとなり「バックエンドサーバー」がアクセストークンを取得し、プロフィールAPIにアクセスする という実装も考えられますが、OAuth 2.0ベースの仕組みだと割と一般的にモバイルアプリケーションやSPAなどでアクセストークンの取得まで可能なSDKが用意されている場合が多く、そこから拡張しやすい上記の例のような実装を見かけることが多いため取り上げました)

先ほどのフローにモバイルアプリとバックエンドサーバーのやりとりが紛れ込んだだけなので問題なさそうに思える実装ですが、まさにそのモバイルアプリとバックエンドサーバーのやりとりにおいて、「●●でログイン」しようとしたリソースオーナーのアクセストークンであること」 が担保されなくなります。

具体的には、第3者によって次のようなアクセストークンがバックエンドサーバーに送られる可能性があります。

  • 別のクライアントに対して発行されたアクセストーク
  • 同一クライアントを利用する別のユーザーに対して発行されたアクセストーク

RFC6750で定義されているOAuth 2.0のBearer Tokenの仕組みが利用されている場合、リソースサーバーはリクエストに指定されたアクセストークンが有効であればレスポンスを返します。

このような構成において、「●●でログイン」しようとしたリソースオーナーであること」をアクセストークンだけで担保することはできるのでしょうか?

OAuthにおいてアクセストークンの役割は

  • リソースオーナーは誰か
  • リソースオーナーの代わりにアクセスするクライアントは誰か
  • どのリソースにアクセスできるか
  • いつまで有効か

ぐらいの情報を リソースサーバー が理解し、リソースアクセスの要求の検証、リソースアクセスのレスポンス生成に利用することです。 JWT形式のアクセストークンとかいう仕様もありますが、基本的にはクライアントに情報を伝えるためのものではない ため、クライアントがこれらの情報を取得するためには、リソースサーバーがプロフィールAPIもしくはアクセストークンに紐づけられた情報を返す専用のAPIとして提供する必要があります。このAPIのレスポンスを検証することで、 "別のクライアントに対して発行されたアクセストークン" であることを検知可能です。

しかし、"同一クライアントを利用する別のユーザーに対して発行されたアクセストークン" を検知することは困難です。

これを検知するためには「クライアントのどのセッションと紐づいているか」という部分を認可サーバー側がアクセストークンに紐づけておき、さらにAPIとして提供する必要があります。

このようにクライアントだけではなく認可サーバー、リソースサーバーも独自拡張などの工夫が必要となることから、ID連携の最低限の要件でもOAuthにおけるアクセストークンによりカバーできる範囲を超えたものであり、OAuthの仕様を独自に拡張するなどの対応が必要です。

複雑な要件への対応

繰り返しになりますが、ここまで紹介してきた 「ユーザー識別子が取れたら認証に利用できる」 という要件、これはあくまでID連携を最低限の要件と言えます。

実際に異なるサービス間のID連携を考えていくと、いくらでも要件が出てきます。 例えば、様々なサービスが多要素認証を導入している中でID連携を行う際に、ID連携と自サービスで認証を要求するタイミングや認証強度を揃えたい場合もあるでしょう。

  • クライアントからの認証要求
    • 多要素認証必須で頼む
    • 多要素認証したかどうか、方法の連絡を頼む
    • このリソースオーナーに対して再認証を頼む

みたいな要件が出てくることもあるでしょうし、よりサービス同士が密なユースケースでは

  • セッション関連の要求
    • 自動でセッション同期させたい
    • 手動でセッション同期してるか確認したい
    • 一緒にログアウトさせたい

みたいなセッションに関する話も出てくるかもしれません。

認可サーバー上でのリソースオーナーの認証処理 について、OAuthではノータッチですし、クライアントが認証処理を行った後の認可サーバー-クライアントのセッション管理 についても当然触れられていません。これらを実現するためには、またまた認可サーバー、クライアントの両方が独自で拡張する必要があるでしょう。

オレオレプロフィールAPI

ここまでの流れで "OAuth認証" には リソースオーナーの情報を返すプロフィールAPIが必要 でした。 しかし、OAuthで定義されているのはAPIアクセスのリクエスト/レスポンスヘッダぐらいであり、このようなユーザー識別子を含むリソースオーナーの情報のやりとりは定義されていません

今までも様々な仕様でユーザー識別子、メールアドレス、電話番号などを返す標準化されたAPIが定義されてきましたが、その仕様策定における思惑ってものがあるのです。わかりますよね?

標準化の隙間が引き起こす事態

上記の複雑な要件への対応や独自のプロフィールAPIについて、標準化されていない状態のままでは各サービスが似て非なる実装を行ったりして互換性のないID連携方法の乱立を引き起こします。(現実は標準化された仕様があってもなかなか足並み揃わなかったりしますけどもなかったらもっとカオス)

某OmniAuthなどのようにそこを吸収するライブラリで解決するという方法もありますが、そもそも標準化されたOAuthを使ってる意味が...ってなってきますし、最悪の場合は脆弱性を作り込んでしまう場合があります。

そんなに面倒なら "OAuth認証" を使わせてるサービスはどうしてるの?

例として、TwitterはOAuth 1.0ベース、GitHubFacebookはOAuth 2.0ベースでID連携の仕組みを提供(認可サーバー、リソースサーバー側)しています。Twitterはサービスの規模からもはやTwitter認証として居座っていますし、GitHubは開発者が使うサービスが多いので実装する側も割と意識して作っている印象です。

FacebookはOAuth 2.0以前からFacebook Connectと題してID連携の仕組みを提供しておりそれ自身がOAuth 2.0のベースとなった経緯もあり、上記の課題についても独自路線を貫いていますが、新たにOAuth認証を提供したいサービスが真似しようとしてももはや無理なところまで行っちゃってます。

このような大きなサービスであれば監視の目も多く、脆弱な点についての指摘が行われ、常々対応されていく感じですがそこまでの規模ではないサービスがOAuth認証の認可サーバー、リソースサーバーをなんとなく実装すると逆に指摘されるタイミングが遅れ、脆弱な点が残る可能性もあるでしょう。

ID連携を目的としたプロトコル

ここからは、"OAuth認証" と比較されがちな、最初からID連携を目的としたプロトコルについて見ていきましょう。

  • OpenID Connect : OAuth 2.0がID連携のために進化したぞ!OAuth 2.0で定義されているAPI保護の仕組みに ID連携に必要な機能を追加したプロトコルです。
  • SAML : エンタープライズで実績抜群!XMLだしプロトコルの詳細はめんどいんだけどそれを埋めるプロダクトもたくさんあるので要は金で解決できるやーつ

大人の事情により ここではOpenID Connectについて上記の課題にどう対応しているかを整理します。

OpenID Connect はどうなのか

ここからは上記の "OAuth認証" が持つ課題について、OpenID Connectがどう解決するかを紹介します。用語は OAuth 2.0 あたりのものを利用します。

"認証イベントの情報" をIDトークンとしてやりとり

OpenID Connectではアクセストークンとは別に、IDトークンというものを発行します。

IDトークンには

  • 誰が : リソースオーナーの識別子 "sub"
  • いつ : リソースオーナーが自身の情報へのアクセスに同意した日時 "iat"
  • どこで : 認可サーバーの識別子 "iss"
  • 誰に : クライアントの識別子 "aud", "azp"
  • どれぐらいのリソースに対して : アクセス対象となるユーザー情報の範囲 "scope"

と言った「●●でログイン」しようとしたイベントに関する情報、さらに

  • リプレイアタックを防ぐためのクライアントのセッションに紐づく値 "nonce"
  • リソースオーナーがいつ認証したか、認証方式、どの基準の認証レベルか "acr", "amr"

という値や、

  • 氏名
  • 生年月日
  • 住所
  • メールアドレス、確認済みかどうか
  • 電話番号、確認済みかどうか

と言った、クライアントが要求したリソースオーナーのプロフィール情報を含められます。

IDトークンは(OAuth認証に欠けている)認証イベントに関する情報を JWT(JSON Web Token) と言う仕組みで署名をつけたり暗号化してクライアントに渡すための仕組みであり、署名検証にいよる改ざん検知、暗号化による情報漏洩対策もやろうと思えばできます。

クライアントはこのIDトークンを用いて、"ログインしようとしたのは誰か" を把握し、認証処理を安全に実装できます。 "●●でログイン" を実現するだけであれば、アクセストークンを用いたAPIアクセスを行う必要もありませんし、モバイルアプリとバックエンドサーバーの構成でもこのIDトークンを用いることで安全に実装できます。

f:id:ritou:20201128234715j:plain

Webアプリなクライアントでは、リソースサーバーへの問い合わせなしで認証処理が可能です。 細けぇ話で言うと認可レスポンス(OIDCでは認証レスポンスと呼ぶ)もしくはアクセストークンと共に取得できます。

f:id:ritou:20201128234729j:plain

モバイルアプリ+バックエンドサーバーなクライアントでは、IDトークンを検証することで 「●●でログイン」をしようとしたリソースオーナーであること を担保できます。 一連の流れになっていることを担保するために、nonce と言う値が利用できます。このあたりは去年のアドカレで書いた気がするので良かったらどうぞ。

ritou.hatenablog.com

拡張された認可(認証)リクエス

上記IDトークンで認証イベントの情報を含めるために、認可サーバーへのリクエストも拡張できるようになっています。

  • 認証方式や認証強度を要求したり
  • メールアドレスや電話番号への個別の情報単位で要求するリソースを表現したり
  • それらを(リソースオーナー自身でも)改ざんできないようにJWSで署名つきにしたり

と言ったことが可能です。

OAuth 2.0では様々な拡張仕様が検討されており、これらと重複しているものもありますが、 OIDCでは 最低限のものからある程度複雑化した要件を持つID連携に対しても、必要な機能 が定義されています。

よって、OIDCではIDトークンの利用を含めてと合わせてOAuth認証ではできなかった複雑な要件への対応が可能です。

標準化されたUserInfo API

OIDCではプロフィールAPIも定義されています。

OAuth認証ではクライアントがユーザー識別子をぶっこぬいて認証に利用するためのAPIと言う立ち位置でしたが、IDトークンにその用途を譲り、UserInfo APIではプロフィール情報の同期などを目的としてアクセストークンを用いて最新のリソースオーナーの情報を返すAPI として定義されています。

豊富な拡張機能

それ以外も、セッションに関する拡張仕様や最近はよりセキュアな仕組みが求められる金融サービスに対するプロファイル(FAPI)などの仕様策定が続けられています。

いやいや、結局OAuth 2.0への後付けじゃねーの

それはそうです。 昔からID連携に求められる要件ってのは決まっている中で、どうやったら新規/既存のサービスに普及するかが重要です。

OpenID も前のバージョンなどでは OAuth と全く別の仕様で実装されてきたものの、最新の仕様であるOpenID ConnectはOAuth 2.0ベースで進められることになりました。

「Identityレイヤーを被せた」などとも表現されますが、OpenID Connectは OAuth 2.0を用いたOAuth認証で標準化が必要な部分を定義した仕様 と言えます。

まとめ

今回は "OAuth認証" について振り返りました。

  • OAuthのリソースアクセスの仕組みだけを利用してID連携の実装を試みても最低限の要件を満たせず、クライアントの構成によっては認可サーバー、リソースサーバー側の拡張が必要となる場合がある
  • ID連携のためには「●●でログイン」と言う認証イベントを実施したユーザーの情報を "安全に" やりとりする仕組みが必要
  • TwitterGithub, Facebook安全に利用できるフローを示したり、不足している部分を独自に拡張したりしてOAuth認証を可能にしている
  • OpenID ConnectではOAuth認証で独自実装になり得る部分を標準化仕様としてサポートしているのでご利用ください

と言うあたりで、開発者はどうすれば良いかと言うと

  • ID連携を提供したいサービスは OpenID Connect に対応する
    • オレオレ実装をする場合は "非互換性" を認識し、リスク分析をした上で、SDKやライブラリ、ドキュメントなどを用意して安全に利用してもらえるようにする
  • ID連携を利用したいサービスはそのサービスが OpenID Connect に対応しているかどうかを確認する
    • オレオレ実装の場合、意図せぬ脆弱性を踏まないように純正SDKやライブラリ、ドキュメントを確認する
    • OpenID Connectに対応している場合も、そのサービスがどれぐらい仕様に対応しているかを確認する

てな感じではないでしょうか。

今後も、"OAuth認証" というキーワードを聞くことがあるかと思います。 正しい理解を広めて平和な世の中を目指していきましょう。

私のアドカレ次回作は12/7です。ではまた!

qiita.com

ここで質問受け付けてるので気軽にどうぞ!

marshmallow-qa.com

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枠を減らしてもいいので是非ご参加ください。

ではまた。