パスキー導入時のRelying Party側の考慮事項的なもの

本記事は [Digital Identity技術勉強会 #iddance Advent Calendar 2022](https://qiita.com/advent-calendar/2022/iddance) の11日目の記事です。

最近いろいろ盛り上がってきているパスキーについて、実際にサービスに導入するときに気になりそうなポイントをまとめてみようと思います。

あくまでパスキー調べてる個人の意見です！それはちがくね？みたいなのあったら、コメントください:bow:


## 背景
### 既存の状況・問題点

今までのFIDO認証は、基本的にCredentialはAuthenticatorの外にはでない、Single-Device Credentialと呼ばれるものでした。そのため、セキュアではあるものの、Authenticatorを紛失した場合のリカバリが難しく、サービスの利用にあたってFIDO認証の利用を必須化することは難しい状態でした。

特にコンシューマー領域では、「Authenticatorを複数台持っているユーザは少ない」、「security keyを持っているユーザはもっと少ない」といった点があるため、FIDO Allianceが推奨しているリカバリ対策「複数のAuthenticatorを登録して、全部のAuthenticatorをロストする事態を防ぐ」を実施することが難しく、大きな懸念事項となっていました。

また、「『2台目のAuthenticatorの登録』と『1台目のAuthenticatorでの認証』を紐付けるのが難しい」という問題もありました。これは、先週ちょうど出ていた[Cross-Device Flows: Security Best Current Practiceのドラフト](https://www.ietf.org/archive/id/draft-ietf-oauth-cross-device-security-00.html#name-cross-device-flow-exploits)で紹介されている攻撃フローに対応するようなものになります。

基本的に、Credentialをアカウントと紐付けるときには、その根拠になる認証が必要です。当たり前なところでいえば、「アカウントにログインしてないと、passwordを変更できない」という制限も、新しいpasswordというCredentialをアカウントに紐付けるためには、そのアカウントが現在持っている認証要素で認証する必要がある制限です。

FIDOの持つPhishing耐性を活かすためには、Phishing耐性のある紐付けプロセス、例えば強力な認証や本人確認などを含んだプロセスを準備する必要があります。そうしないと、FIDOの認証プロセス自体にはPhishing耐性があっても、攻撃者のAuthenticatorが被害者のアカウントに紐付けられるという状況が作られてしまいます。

1台目のAuthenticator / 2台目のAuthenticatorに当たるのがsecurity keyのようなroaming Authenticatorであれば、この難しさはありません。なぜなら、1台目と2台目が物理的に接続されていて、どちらの操作も同じデバイスから行われるからです（図中①）。[Cross-Device Flows: Security Best Current Practiceのドラフト](https://www.ietf.org/archive/id/draft-ietf-oauth-cross-device-security-00.html#name-establish-proximity)で紹介されているところのPhysical connectivityに当たります。

しかし、コンシューマーアプリケーションではSecurity Keyを持っているユーザは少ないので、この方法は取れません。他にできる方法というと、OpenID Connect CIBAのように、operation(2台目のAuthenticatorの登録)を行うdeviceと、認証(1台目のAuthenticatorでの認証)を行うデバイスを分ける方向性です（図中②）。しかし、この方向性は、Phishing Siteを使った攻撃のリスクが高くなる可能性があります。

![FIDO - ページ 1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/12268/2bc64f43-d1bc-1c59-9914-b0eb91b8f7c4.png)


例えば、以下のような流れが想定されます。
1. ユーザがPhishing Siteでアカウントのログインに必要なCredential(例えば、password + SMS OTP)をすべて入力してしまう
2. それを取得した攻撃者が自分の端末で、被害者のアカウントにログインする
3. その攻撃者は、次に自分の端末をFIDO Authenticatorとして登録しようとする
4. 既存の登録されているAuthenticatorの認証が要求されて、ユーザ自身が持っているdeviceにpush通知なりで認証をするように要求される。
5. ユーザが要求を認証・承認する。
6. 攻撃者のAuthenticatorがアカウントに紐づく。

step4は、ユーザから見ると、ログインに際して認証が要求されているんだなと勘違いしやすいので、この要求は基本的に通りやすいと想定されます。仮にそのタイミングでOTPを入力するように要求したとしても、現状のPhishing SiteではOTPをユーザに入力させることは既によく行われているものなので、特別なんのハードルにもならないでしょう。

![FIDO - ページ 1 (3).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/12268/7604af8e-eb55-8429-f8da-d612e0fea0dc.png)

### パスキーによる問題の解消

パスキーとして利用が推進されている現状においては、「Multi-Device Credential」、「hybrid transport」という機能が使えるようになったことで、それらの問題が解消するめが出てきました。

具体的にどのような挙動になるのかは、FIDO Alliance が出している動画 [Passkeys in Action](https://www.youtube.com/watch?v=SWocv4BhCNg)をみたら、基本的にわかると思うので詳細は割愛しますが、かんたんにまとめるとこんな感じです。

「Multi-Device Credential」とは、Credentialがdeviceに紐づくのではなく、Platformのアカウントに紐付いており、Credentialが複数のdevice間で共有されます。これにより、複数台のAuthenticatorを登録してない状態で一つのAuthenticator(device)を紛失してても、アカウントリカバリの必要がなくなるというものです。

また、「hybrid transport」というのは、QRコードとBluetoothを使いスマートフォンをroaming Authenticatorとして利用できる方法です。これによって、異なるPlatform間でも作成したCredentialを利用できるようになります。device間のやり取りはBluetoothで行われており、物理的な距離の制限がでてくるので、Phishing SiteでCredentialを窃取されるような攻撃は難しくなります。これは、[Cross-Device Flows: Security Best Current Practiceのドラフト](https://www.ietf.org/archive/id/draft-ietf-oauth-cross-device-security-00.html#name-cross-device-flow-exploits)で紹介されているところのWireless proximityに当たります。このため、前述したような「2台目のAuthenticatorの登録」と「1台目のAuthenticatorでの認証」を安全に紐付けることができます。

これらによって、FIDO認証の利用を前提とするサービスを作れる土壌ができてきました。

この記事では、実際にサービスでパスキーを利用しようと考えたときに気になっているポイントを纏めてみようと思います。

## ポイント1: 各Platformにおける違い

まず1つ目は、各Platformにおける違いの部分です。

基本的に同じ仕様に乗っているので大きな違いがあるわけではありませんが、いくつか気になる点があるとおもっています。

* インターフェースの抽象化の違い
* excludedCredentialsの違い
* Single-Device Credentialの取り扱いの違い
* Device Public Keyの取り扱いの違い

### インターフェースの違い
Appleのインターフェースの場合、Platform Authenticatorを使うか、Roaming Authenticatorを使うかによって明確に使うインターフェースが分かれています。[ASAuthorizationPlatformPublicKeyCredentialProvide](https://developer.apple.com/documentation/authenticationservices/asauthorizationplatformpublickeycredentialprovider)、[ASAuthorizationSecurityKeyPublicKeyCredentialProvide](https://developer.apple.com/documentation/authenticationservices/asauthorizationsecuritykeypublickeycredentialprovider)。そのため、アプリケーション側で「Platform or Roaming Authenticatorを明示しない」という選択肢はなく、アプリケーション側でどちらか選択する必要があります。一方、WebAuthnやGoogleのFIDO2 APIの場合は、AuthenticatorAttachmentを指定すれば選択できますが、指定しなければどちらも使うことができます。

> 〜これはわたしの感想〜
Appleでは「すべてのPlatform AuthenticatorをMulti-Device Credentialとして扱う」としているため、Platform Authenticator = Multi-Device Credential、Single-Device CredentialはSecurity Keyだけとなる。そして、後述のようにMulti-Device Credential、Single-Device Credentialはその特徴から想定される攻撃のシナリオが異なり、RPがどれだけリスクを取れるかによって、どちらのパターンを利用するのが適切かが変わってくると。そこを考えると、『RP側でPlatform Authenticatorを使うかRoaming Authenticatorを使うかは、RPの特性に応じて明確に決めるべき』、というのがこのインターフェースの背景なのかな...。ただまぁ、Safari@iOSとかで(webauthn)で使った場合、それを強制されているわけではないので、違うかもしれない...w

### excludeCredentialsの違い

また、Appleのproviderそれぞれで渡せるパラメータが異なっています。特に大きな違いとして、Platform Authenticator側に[excludeCredentialsが見当たりません。。](https://developer.apple.com/documentation/authenticationservices/asauthorizationplatformpublickeycredentialregistrationrequest)そのため、すでに同じRPID/userIDでCredentialが作成されていたとしても、再度Registrationリクエストを送ると別の鍵が作成されます。しかし、Appleのpassword managerで確認できるように、パスキーはRPID/userIDでuniqに保存されているようで、Authenticator側で新しく作成された鍵は前の鍵を上書きする形で保存されます。つまり、RPには鍵が2つ登録されているけど、Authenticatorには一つしかないという状態になります。

>〜これはわたしの感想〜
これはおそらく、Appleでは「すべてのPlatform AuthenticatorをMulti-Device Credentialとして扱う」、「パスキーはdeviceではなく、Platformのアカウントに一意に紐づく」という考えに基づいて、『RP側では同じPlatformのMulti-Device Credentialは一つしかないみせ方にすべし』と言うことなのかなと雰囲気思う...でも現状、サーバ側でどのplatformのかとかって見分けつかないはずなんだよな...。UserAgentに基づいてサーバ側で鍵上書きするのとかやりたくないな...。

### Single-Device Credentialの取り扱いの違い

機能面においても、機能のサポート状況として、多少の違いがあります。

まずはSingle-Device Credentialの取り扱いです。AppleではPlatform Authenticatorでsingle-device crentialを作るということはできません。一方Googleの場合、「Discoverable-CredentialをMulti-Device Credentialとして扱う」となっているので、Discoverable-Credentialをオフにすれば、Single-Device Credentialを使うことはできます。また、[passkeys.dev](https://passkeys.dev/device-support/)に書いてあるサポート状況を見ると、Microsoftの場合、passkeyはplanned、single-device passkeyはsupportedになっています。これはつまり、Discoverable　なSingle-Device Credentialもサポートするということです。これは、iOS15以前にWebAuthnで作成したAppleのFIDO Credentialと同じ位置づけのものと言えるかなと思います。まとめると以下のような感じです。

![スクリーンショット 2022-12-11 13.45.14.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/12268/bb9db87e-bf0a-5ceb-5b74-26e9b93bf4d3.png)

### Device Public Keyの取り扱いの違い

もう一つ機能的な違いとしてあるのが、[Device Public Key (DPK)](https://w3c.github.io/webauthn/#device-public-key) のサポート状況の違いです。DPKというのは、Multi-Device Credentialと一緒に導入された、device毎にCredentialとは別の非対称鍵が作られる機能のことです。Multi-Device Credentialの場合、ユーザのCredentialは異なるdevice間で共有されます。そのため、RPではそれがもとのdeviceで作られたものなのか、syncされて別のdeviceから使われてるものなのかわかりません。それをわかるようにするために準備されたのがDPKです。ユーザのCredentialとして使う鍵とは別に、deviceごとの鍵を作成してその公開鍵をPRに送ります。それによってRPはCredentialが登録時とは別のdeviceから使われているかどうかを判別できるようになります。また、DPKには仕様上DPK Attestationというものも定められていて、どのAuthenticatorがそれを管理しているかを検証できるようになっています。

現状、GoogleにおいてはDPKがサポートされていますが、Appleにおいてはサポートされていません。また、Googleにおいても、DPK Attestationはサポートされていない状況です。[passkeys.dev](https://passkeys.dev/device-support/)に書いてあるサポート状況をみると、MicrosoftはDPK、DPK Attestationともにサポートする予定があるようです。


> 〜これはわたしの感想〜
このような現状だし、仮にRPがiOS / Android / Webをサポートしている状況で、各OSで共通した機能を提供しなければならないのであれば、Appleの状況に引きづられて、以下のような状況になるだろうな...。
>
> * AppleのPlatform Authenticatorでsingle-device credential使えないし、Platform Atuhenticatorはmulti-device credetnialが前提となる
> * DPKは、Appleがサポートしてない以上積極的には、使えない。
> * Security keyの利用は検討可能

## ポイント2: User Experienceに対する影響
### 機種変更において詰むパターン

パスキーが使える状況において、ユーザが機種変更等で別のデバイスを利用したい場合に基本となるやり方は以下です。
同一Platformのdevice間であれば、Credentialがsyncされる。
異なるPlatformのdevice間であれば、hybrid transportを使って認証する。

しかし、現段階ではまだ、いくつか詰むパターンが存在します。例えば、以下のようなパターンです。

* **MacOS上Chromeブラウザ経由で最初のCredentialを作成する**
そのCredentialは、Multi-Device Credentialではなく、Single-Device Credentialとなっており、他のiOS device や Android deviceに共有されることはありません。また、MacOS上でHybrid (Authenticator)がサポートされていないので、他のdeviceからChrome@MacOSで作成したCredentialを使うこともできません。

* **Windowsのdeviceで最初のCredentialを作成する**
このCredentialは、Windowsのdevice間では共有されますが、WindowsがHybrid (Authenticator)をサポートしていないので、他のPlatformのdeviceを使おうとした場合、そのCredentialを利用する事ができません。

* **iOSで最初のCredentialを作成して、Androidでそれを利用する**
現状まだ、AndroidでHybrid(Client)をサポートしていないので、iOSで作ったCredentialを使って、Androidで認証することができません。これはサポート予定になっているようです。

対応関係を図にするとこんな感じです。

![FIDO - ページ 1 (6).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/12268/36783458-26ba-febb-8752-39500aede36a.png)


また、パスキーがサポートされていない端末・OSを利用しているユーザにおいても同様のことがいえます。

パスキーをサポートしているのは現状、iOS16以上とAndroid9以上なので、それ以前のOS versionを使っているユーザは、FIDO認証自体使えないもしくは、Single-Device Credentialが作られるとなります。その場合、同じデバイスでOSをアップデートしない限り、その鍵を使って別のdeviceと鍵を共有するとか、その鍵を別のdeviceでの認証に使うことはできません。

このようなパターンに陥った場合の対応方法としては、基本的パスキー導入以前の対応、「サービス側でできる限り安全なbindingの方法を提供する」とか「Customer Support経由で本人確認を経た上で弱い認証での登録を許可する」とかになると思います。

この状況は、後々には解消されていくと思われます。[特にAndroid のHybrid(Client)は、提供される予定があるようです](https://passkeys.dev/device-support/)。そのため、定期的に状況確認するのが良いと思いました。


### 既存のSingle-Device Credentialと共存しているときの鍵の表示方法

> 〜この項目はほぼ全部自分の感想な気がする...〜

ちょっとだけ上ででてきましたが、「Single-Device Credentialはdeviceに紐づくけど、Multi-Device CredentialはPlatformのアカウントに紐づく」状態になります。この違いは、現在登録されているCredentialをユーザへのみせ方に影響します。

ユーザが登録済みCredentialを確認する方法は大きく分けて3つあります。
* RPの登録済みCredential確認画面
* Authenticatorの保持しているCredential一覧
* 各Platformのパスワードマネージャー

「RPの登録済みCredential確認画面」には、特定のRPアカウントに対して紐付いているCredential一覧が表示されることになります。Single-Device Credentialの場合、Credentialはdeviceに紐付いているため、device名を表示するのがわかりやすいと思います。しかし、Multi-Device Credentialの場合、Credentialは複数のdevice間で共有されます。また、登録できるCredentialはPRID/user_idでuniqになります。そのため、この画面で表示する名前としてdevice名は適切ではなく、Platformの名称あたりが適切かなと思います（Platformのアカウント毎にCredentialを作れるので、正確にはPlatformアカウント名ですが、それを取得する方法はないので）。

ただ後述するように、Multi-Device Credentialには現状Attestationがないので、Authenticatorの正確な所属を確認することはできないため、登録時のRequestのUserAgentで確認するとかになると思います。そのため、鍵の名前自体は編集できるようにしておいたほうがいいでしょう...。

「Authenticatorの保持しているCredential一覧」は、特定のRPIDに対してAuthenticatorが保持しているDiscoverable Credentialを表示するもので、Authenticatorに渡すuser.displayNameとuser.nameが表示されます。これは基本的にFIDO認証を使ってログインをするときに使われるものなので、表示する内容としては、RP側のアカウントを区別できるようなアカウントの名称とかを表示するのが適切です。

また、Multi-Device Credentialの場合、「各Platformのパスワードマネージャー」においても、登録されているCredentialとその名称を確認することができます。その値は、「Authenticatorの保持しているCredential一覧」で表示されるuser.displayNameとuser.nameなので、そちらと同じくRP側のアカウントを区別できるようなアカウントの名称とかを表示するのが適切です。

まとめると以下のような感じかなと思います。
![スクリーンショット 2022-12-11 13.50.02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/12268/efc881b5-2131-0628-355d-be50d314fc38.png)

「RPの登録済みCredential確認画面」にユーザの名称出したり、「Authenticatorの保持しているCredential一覧」にdeviceの名称出したり、Multi-Device Credentialなのにdeviceの名称出したりとかすると、区別ができなくて、かなりユーザの体験が悪くなるので気をつけなきゃいけないなと思いました。一方で、登録時にユーザに設定してもらうかたちにしたら、そういうこと気にしなくてもいいのでは、という気もしますが、ユーザの立場からすると、名前考えるのも文字入力するのもめんどくさいから、適切な名前かってにつけてくれって個人的には思う。


## ポイント3: Securityに対する影響

パスキーの導入によって、アカウントリカバリが必要となるケースが減り、2台目のAuthenticator登録もsecureに行える様になったので、全体的にはUX・Securityともに向上しています。しかし、今までにはなかったSecurityリスクが生じていることも確かです。

基本的にRPが避けたいポイントとしては、「ユーザが登録したCredentialを窃取される」「信頼できないCredentialを登録される」の2点です。「ユーザが登録したCredentailを窃取される」は、例えば、Phishing攻撃の場合は、ユーザのCredential (passwordやSMS OTP)をPhishing Site経由で窃取されて、攻撃者にアカウントを奪われるというパターンです。「信頼できないCredentialを登録される」のは、例えば、FIDO Authenticatorを登録するときに特別な認証がないために、Phishing攻撃でアカウントを奪われたあとに攻撃者自身のFIDO Authenticatorを被害者のアカウントに紐付けられるといったものです。

パスキー導入においてRP側が新しく検討する必要のあるリスクは以下の2点です。
* PlatformアカウントのCredentialが窃取された場合、パスキーも窃取される可能性がある（「ユーザが登録したCredentialを窃取される」リスク）
* Attestationがないので、passkeyを提供するPlatformを制限できない（「信頼できないCredentialを登録される」リスク）

### Credentialが共有されることによるリスク
まずは、パスキーを提供しているPlatformのCredential自体が奪われることでパスキーも一緒に奪われてしまう可能性です。

基本的にどのPlatformでも、複数デバイスで共有するパスキーは、E2E Encryptionをする形になっているため、仮にPlatform側に攻撃者がいたとしても、Platform側で管理されている秘密鍵を取得、利用することは容易ではありません。

* [Security of Passkeys in the Google Password Manager](https://security.googleblog.com/2022/10/SecurityofPasskeysintheGooglePasswordManager.html)
* [About the security of passkeys](https://support.apple.com/en-us/HT213305)


しかし、もしPlatformのアカウントへのログイン・パスキーの取得までに必要なCredentialがPhishing耐性のないpassword + OTPだけであった場合、PlatformのアカウントをPhishing Siteで奪われるリスクは存在することになります。また、E2E Encryptionのために、新しいデバイスでパスキーを同期するときに、「別の端末で利用しているPIN」を入力することを求められる場合もありますが、実質それも4桁数字のみなので、Phishing Siteで聞かれたら入力しちゃうのでは？という思っちゃいます。

このリスクへの対策として、FIDOの仕様的に利用可能かもと思えるのは、Device Public Keyです。PlatformアカウントがのCredentialが奪われた場合、攻撃者が攻撃者自身の端末で共有されたCredentialを利用することになるので、DPKを使えば、Platformアカウントが窃取されたシグナルとして利用できる可能性はあります。

しかし、それはあくまで新しいdeviceが使われたことを検知するだけなので、Platformのアカウントが窃取されたシグナルとしてはfalse positiveが非常に大きい状態になってしまいます。そのため、そのシグナルを受け取ったときにできることは、UXを大きく毀損しないような対応、「ユーザに使われたことを通知する」とか「他の認証要素(Phishing可能)で、reauthenticationを促す」といったことしかできず、Platform account takeoverによる被害を事前防止することは基本できないと思います。また、DPKは現状iOSではサポートされません。

### Attestationがないことによるリスク
もう一つのリスクは、Attestationがないことによるリスクです。

新しくFIDO Credentialを作成し、RPのサーバ側でアカウントに紐付ける際、基本的には送られてきた公開鍵が改ざんされていないか、信頼できるAuthenticatorがそれを作成したかを検証します。この検証の仕方には色々なパターンがあって、秘密鍵を管理していることだけ検証できるパターンもあれば、Authenticatorが出自を検証できるパターンもあります。選択肢の一つとして、検証方法を提供しない(Attestation Statement format=none)パターンもあります。

パスキーにおいては、Attestation Statement format=noneだけです。また前述した、DPK Attestationもついていないので、秘密鍵の管理・Authenticatorを検証を行う事はできません。これが行えない場合、「信頼できないCredentialを登録される」ことを防ぐことができません。そのため極端なことをいえば、攻撃者が自分でAuthenticatorを作って、特定のユーザにそれを使わせるような、攻撃する価値のあるユーザを狙い撃ちするような攻撃を防げなくなります。


また、[先月1passwordが発表していたような](https://www.future.1password.com/passkeys/)パスキー自体を1passwordのようなpassword managerが管理する形がもし今後一般的になり、そこにもAuthenticatorを検証する仕組みがなければ、password managerがどのようにCredentialを守っているかによらず、ユーザはどのようなpassword managerでも利用でき、RP側はそれを制御することはできません。password manager毎にそのアカウントの管理の仕方は異なるので、万が一問題のあるpassword managerが使われていた場合、そのアカウントが奪われ、Credentialが共有されることも起こりうると考えてしまいます。。

passkeyを提供する側で、DPK Attestationが実装されていれば、このリスクは解消可能ですが、現状においてはまだDPK Attestationが実装されているPlatformはありません。

![FIDO - ページ 1 (7).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/12268/7f1a8e37-6d90-b268-ba7c-ef8169740976.png)


現状、これら2つのリスクに対して、明確にRPができる対応策はありません。そのため現実問題、そのリスクが存在する上で、利用していくしかないと思います。事実、大多数のRPにとってこれらのリスクはすでに存在し、受け入れている状態であることも否めません。

* Sign-In-with Apple等のPlatformアカウントを使ってのログインをサポートしているRP
* passwordを忘れたときのリカバリ方法として、emailにリカバリリンクを送っているRP
* Password managerは現状、RP側が制限できるようなものではない。

しかし、中にはFinancialやHealthcare等、取り扱っているデータの性質上そのようなリスクも考慮する必要があるRPも中には存在します。その場合、現状できるのは、その攻撃が発生してしまったときの対処方法を検討しておく、くらいしかできない気がします。

もしこれらのリスクをのむことができない場合、現状においてはMulti-Device Credentialを使わずSingle-Device Credentialを使う方向にならざる負えないかなと思います。ただ、AppleではPlatform AuthenticatorはすべてMulti-Device Credentialと定義している状況なので、選択肢としてSecurity keyを使う以外になく、それはコンシューマー向けアプリケーションにおいては取るのが難しい選択肢となります。。

>〜これはわたしの感想〜
せめて、パスキーでもAuthenticatorを検証できるようになるか、Single-Device Credentialを作る選択肢が取れる様になることを期待したいところです

## まとめ
パスキー導入時にRPが考慮する必要があるかもしれないポイント考えてみました。

導入する際には、RPがサポートしているPlatformや、許容可能なリスク等を鑑みて、しっかり考えないといけないな...と、普通のことを思いました。

## Reference
https://w3c.github.io/WebAuthn
https://developer.apple.com/documentation/authenticationservices
https://developers.google.com/android/reference/com/google/android/gms/fido/Fido
https://passkeys.dev/device-support/