パスキーの今を知る

# はじめに

この記事は[WEMEX株式会社 Advent Calendar 2023](https://qiita.com/advent-calendar/2023/wemex)の一記事です。

弊社は医療システムの会社であり、業務効率と厳しい情報管理の両方を求められます。そのため、パスキーについても近いうちに導入する方針に進むだろうと予想されます。またエンジニア業界がパスキー導入が盛り上がる中、パスキーについて何も知らなかったので、これを機にパスキーについて調査した結果を記事にまとめました。

なお、調査内容の詳細や真偽については各自でソースを確認していただくことをご留意ください。

# パスキーとは
端的に言うと、「FIDO2認証＋パスワードマネージャで共有」する仕組みです。

FID2O認証は、生体情報などを使用できるデバイスで生成した鍵を使ってパスワードレス認証を行う手法です。この際、生体情報を用いて生成され、登録された公開鍵をパスワードマネージャで共有できるようになります。

パスワードマネージャは、デバイス間で秘密鍵を共有する仕組みで、iOSのiCloudキーチェーンやGoogleのパスワードマネージャなどが該当します。OSに紐づいたパスワードマネージャだけでなく、1Passwordのような外部パスワードマネージャもパスキーに対応しています。

このFIDO2認証とパスワードマネージャの2つの技術を組み合わせることで、デバイス間で生体認証の秘密鍵を共有して使用できるようになります。

# 導入のメリット・デメリット
### メリット
ユーザ側のメリットとしては、以下が挙げられます。

- ログインの負荷が大幅に軽減される
- パスワード管理が不要
- 鍵生成にデバイスを使用するため、2FAと同等のセキュリティが担保される

サービス提供側のメリットとしては、以下があります。

- フィッシング攻撃対策やクレデンシャルスタッフィング攻撃への有効な対策
- これに伴い、パスワード紛失や流出などの顧客対応が減少

### デメリット
導入にはいくつかの懸念事項も存在します。

1. セキュリティ上の懸念
パスキーの使用により、鍵やデバイスの窃盗・盗難・押収に関するセキュリティ上の懸念が生じます。
2. 大手テクノロジー企業への依存性の高い実装
パスキーの実装は主要テクノロジー企業のデバイスやソリューションに大きく依存しており、オープンソースソフトウェア実装が存在しません。
3. パスキー対応状況の課題
現時点ではまだパスキー対応が過渡期にあり、対象プラットフォームやデバイスが限られていることが問題となっています。認証情報を保存したデバイスへのアクセス制約も考慮すべき点です。
4. ユーザー側の選択と検討
ユーザーはパスワード管理が不要になる一方で、どのパスワードマネージャにどのパスキーを保管するかといった管理を迫られます。

ただし、これらの点は各社のパスキー対応が進む中で将来的には解決される可能性があります。

# 各社対応状況
パスキーの対応状況はまだ限定的であり、対応しているサービスも限られています。導入を検討する際には、サービス提供者がパスキーに対応しているか確認するとともに、利用範囲を検討することが重要です。

### パスキーの各OSの対応状況
詳細は[こちら](https://passkeys.dev/device-support/#matrix)で確認できます

https://passkeys.dev/device-support/#matrix

現時点では以下の点が大きな留意点となりそうです。
- Linuxではパスキーが作れないため、他のデバイスでの鍵生成と、パスキー対応のブラウザもしくはLinuxで使用できるパスワードマネージャ（1Passwordなど）の導入が必要
- Windowsはパスキーが作られたデバイスのみ対応

### 各サービスのパスキー認証の対応状況
詳細は[こちら](https://passkeys.directory/)で確認できます

https://passkeys.directory/

現時点ではまだ対応が少なく、馴染みのある企業としては以下が挙げられます。
- Yahoo
- Nintendo
- Mercari
- GitHub
- Docomo など

# 実装について

## パスキーの認証フロー

### 登録

UserAgent...ブラウザなど
Authenticator...認証器

```mermaid
sequenceDiagram
  actor U as User
  participant A as Authenticator
  participant UA as UserAgent
  participant B as Backend
  
  U->>+UA: 登録ページ開く
  UA->>+B: GET /register
  B-->>+UA: 登録ページ表示
  U->>+UA: 登録ボタン押す
  UA->>+B: POST /register/start username
  B->>+B: 存在確認・新規ユーザ作成・Challenge生成
  B-->>+UA: Challengeを発行
  UA->>+A: navigator.credentials.create()
  A->>+U: 認証ダイアログを表示
  U->>+A: 認証完了
  A->>+UA: 公開鍵とSigned Challenge
  UA->>+B: POST /register/finish 
  B->>+B: Signed Challengeの検証・鍵をユーザに紐づけ・recovery tokenの生成
  B-->>+UA: recovery tokenの発行
  UA-->>+U: recovery tokenの発行
```

参考: https://webauthn-spring-boot-starter.glitch.me/#_diagrams

### 認証
```mermaid
sequenceDiagram
  actor U as User
  participant A as Authenticator
  participant UA as UserAgent
  participant B as Backend
  
  U->>+UA: ログインページ開く
  UA->>+B: GET /login
  B-->>+UA: ログインページ表示
  U->>+UA: ログインボタン押す
  UA->>+B: POST /authentication/start username
  B->>+B: Challenge生成
  B-->>+UA: Challengeを発行
  UA->>+A: navigator.credentials.get()
  A->>+U: 認証ダイアログを表示
  U->>+A: 認証完了
  A->>+UA: Signed Challenge
  UA->>+B: POST /authentication/finish 
  B->>+B: Signed Challengeの検証・ユーザ情報を取得・ログイン許諾
  B-->>+UA: ログイン成功or失敗ページ表示
  UA-->>+U: ログイン成功or失敗ページ表示
```

参考: https://webauthn-spring-boot-starter.glitch.me/#_diagrams

## 何の実装が必要か

### バックエンド
実装APIは下記4つ

- 登録時にChallengeを発行するAPI
- 登録時にChallengeを検証し鍵とユーザを紐づけるAPI
- 認証時にChallengeを発行するAPI
- 認証時にChallengeを検証し、セッションを開始するAPI

### フロントエンド
登録・認証画面でバックエンドのAPIと下記のWebAuthn APIをコールする実装が必要です。

- navigator.credentials.create()
- navigator.credentials.get()

### iOS
登録・認証画面でバックエンドのAPIのコールと下記の対応が必要です。
- パスキーを利用するドメイン登録
- ログイン時・登録時のパスキー対応を[ASAthorization API](https://developer.apple.com/documentation/authenticationservices/public-private_key_authentication/supporting_passkeys/)を使って登録・取得する
- 
パスキー対応が可能となるのはiOS 16以降になります。
> パスキーを使うには、iOS 16、iPadOS 16、macOS 13、またはtvOS 16以降が必要です。また、iCloudキーチェーンと2ファクタ認証もオンになっている必要があります。
> https://support.apple.com/ja-jp/guide/iphone/iphf538ea8d0/ios

### Android
登録・認証画面でバックエンドのAPIのコールと下記の対応が必要です。
- パスキーを利用するドメイン登録
- [CredentialManager](https://developer.android.com/training/sign-in/passkeys?hl=ja)の導入
- ログイン時・登録時のパスキー対応を[CredentialManager](https://developer.android.com/training/sign-in/passkeys?hl=ja)経由で登録・取得する

パスキー対応が可能となるのはAndroid9以降となります。
> パスキーは Android 9（API レベル 28）以降を搭載しているデバイスでのみサポートされます。Android 4.4（API レベル 19）から Android 8.1（API レベル 27）までのバージョンを搭載したデバイスでは、パスワードと「Google でログイン」のみがサポートされます。
> 引用元：https://developer.android.com/training/sign-in/passkeys

### WebView(iOS/Android)

本来であれば、ネイティブな実装が望ましいですが、既にWebViewを使用して認証を実装しているアプリでは、開発コストの観点から、WebViewの認証のままでパスキー認証を組み込むことがあるかもしれません。

iOSの場合、`SFAuthenticationSession`または`SFSafariViewController`を使用した実装が、パフォーマンス的にもセキュリティ的にも好ましいです。一方で、`WKWebView`は一部機能が対応していない場合があり、処理が遅いことがあるため、特別な理由がない限りは使用を避けるほうが賢明です。

Androidの場合、`Android WebView`はGoogleアカウントでのログインを許可していないため使用できません。代替手段として、`Chrome Custom Tabs`が唯一の選択肢となります。

パスキー認証の追加方法には、以下の2つのパターンが考えられます。

- 既存の認証フローにパスキー認証を組み込むパターン
- 既存の認証フローの直前にパスキー認証を実施するパターン

検討の詳細については、以下のCorbadoの技術者ブログを参照してください。

https://www.corbado.com/blog/native-app-passkeys#recommendation-native-app-passkeys-implementation

## ライブラリ
とはいえ実装を行う際は、ライブラリを利用することが一般的です。下記にライブラリ一覧が掲載されています。Rust、TypeScript、Javaなどで利用可能です。

https://passkeys.dev/docs/tools-libraries/libraries/

# 手軽にパスキーを体験するなら
パスキーとは何かを確認するなら [webauthn.io](https://webauthn.io/)、製品レベルでの作り込みを確認するには GitHubで[パスキーログイン画面](https://github.com/login?passkey=true) にアクセスするのがおすすめです。

# 留意事項
この記事ではパスキーに関する基本的な情報と導入メリット、実装手順、各社の対応状況について紹介しました。しかし、パスキーを導入する際には以下の留意事項も考慮する必要があります。

### ユーザエクスペリエンス（UX）について
ユーザがパスキーを利用する際のエクスペリエンスも検討事項の一つです。下記はFIDOアライアンスが提供しているパスキー認証をサイトに導入する際のUX設計ガイドラインです。

https://fidoalliance.org/ux-guidelines-for-passkey-creation-and-sign-ins/?lang=ja

上記のガイドラインを踏まえGoogleが独自の見解を追加した記事です。

https://developers.google.com/identity/passkeys/ux/user-journeys?hl=ja

### セキュリティとプライバシー
ユーザの生体情報を用いる場合、その取り扱いに関して法的な規制が存在する可能性があります。各国・地域の法令を確認し、遵守することが重要です。

# 最後に
この記事ではパスキーについてざっくりした調査結果をまとめました。従来の認証方法のセキュリティの脆弱性やパスワード管理の煩雑さに悩まされていましたが、これらを解決するパスキーが広く採用される未来に期待しています。

# その他参考
- [passkeys.dev](https://passkeys.dev/)
- [パスキーのすすめ](https://techbookfest.org/product/eiaE1tk3bEcu7iPfZx9ysU)
- Yubikeyによるパスキーライブラリ for Java:　[GitHub](https://github.com/Yubico/java-webauthn-server)
- SpringBootでのPassKeyデモ:[GitHub](https://github.com/mihaita-tinta/webauthn-spring-boot-starter)・[ドキュメント](https://webauthn-spring-boot-starter.glitch.me/#_diagrams)
- iOSのパスキー対応方法:[Apple Developer Documentation](https://developer.apple.com/documentation/authenticationservices/connecting_to_a_service_with_passkeys)
- Androidのパスキー対応方法: [Android Developer Documentation](https://developer.android.com/training/sign-in/passkeys?hl=ja#create-passkey)
- 様々なユースケースに利用できる "パスキー" の導入事例の紹介とUXの課題解説: [DroidKaigi 2023](https://2023.droidkaigi.jp/timetable/493289/)
- [Are Passkeys really the beginning of the end of passwords? I certainly hope not!](https://unixsheikh.com/articles/are-passkeys-really-the-beginning-of-the-end-of-passwords-i-certainly-hope-not.html)