WebAuthnとは？

一週間も間をおかずアドベントカレンダーの記事を書くのはしんどいですね笑
本当は認証サーバーの実装とかもやりたかったんですが、時間がなくてだいぶざっくりした内容になっちゃってます。概要を掴むのに使っていただければ幸いです。

# Q. WebAuthnとは？
![webauthn-color.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/235997/a92f53f7-07ec-f21d-ac42-973fc95554d5.png)
**A.** **ざっくり言うとパスワードレス認証をwebで行えるようにしたJavascriptAPIです。**

各種ブラウザで実装されています。

経緯などは特に役立つものではないので省きます。
知りたい方は[こちら](https://blog.agektmr.com/2019/03/fido-webauthn.html)が詳しいです。
## 何ができるの？
**A. 認証器と言われるデバイスを通して、パスワードなしで認証が行えます。**

具体的には、webサイトのログイン画面で指紋認証やセキュリティーキーでの認証を使ってログインが出来ます。

↓指紋認証の認証器として使えるMacBook ProのTouch ID
![2019-mbp-touch-id-social-card.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/235997/ffb3953d-cf2f-3892-ce7f-e2b600bb706a.jpeg)


↓セキュリティーキーの一例
![51kq8MNKW1L._AC_SL1000_.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/235997/d1d68518-5910-1f3f-9ffe-52d7f26dda0f.jpeg)

## 何がいいの？
**A. 楽で安全です。**

## なんで楽？
**A. 長く複雑なパスワードをいちいち覚えておく必要がありませんし、入力する必要もありません。**

必要なことは認証器に指を触れたり、短いPINを入力したりすることだけです。

## なんで安全？
**A.** 後述しますが**公開鍵認証**を利用しているのでパスワード認証のように保護すべき情報がネットワークに流れません。

# 閑話休題
**二段階認証**や**二要素認証**の話題がたまにニュースになったりしてますが、違いをご存知でしょうか？

認証の際には、本人であることを確認するためにパスワードや指紋などが用いられますが、これらは以下の３種類に分類され、**認証の三要素**と言われています。

- **知っている要素** : パスワードやPINコードなどの記憶するもの
- **持っている要素** : セキュリティーカードやセキュリティーキーなど所持するもの
- **備えている要素** : 指紋認証や顔認証などの本人の身体的特徴

これらの安全性は"**備えている要素 > 持っている要素 > 知っている要素**"の順に高いです。

二要素認証とはこれら3つの内、2つを認証に用いる認証方式のことです。
二段階認証は、二要素認証も含まれますが、パスワード認証の後にメールアドレスにワンタイムパスワードを送って認証に用いる場合（どちらも知っている要素）なども含みます。

WebAuthnを用いれば、認証器を持っているという要素と指紋という備えている要素（もしくはPINという知っている要素）を一度に満たすことができます。
# 実際の処理
では、実際にはWebAuthnでどのような処理が行われているのか見ていきます。

当たり前ですが、**登録**と**認証**のフローがあります。

## 登録フロー
1 ) ユーザーが登録画面で登録を要求します。Webアプリなどを経由して最後には認証サーバーに要求が届きます。
![wetauthn.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/235997/67f747eb-6dec-dbed-b63a-35d57c1da701.png)

2 ) 認証サーバーから**公開鍵クレデンシャル生成オプション**というものが返され、アプリケーションサーバーを通ってWebアプリに届きます。
![wetauthn (2).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/235997/7d5cd60e-ac81-e814-83cc-9a1778e38c31.png)

公開鍵クレデンシャル生成オプションはWebAuthn APIを使う際に必要になるパラメータです。
オプションの中身については以下に載っています。
https://developer.mozilla.org/ja/docs/Web/API/PublicKeyCredentialCreationOptions

3 ) Webアプリが返ってきたオプションを引数に**`navigator.credentials.create()`**というWebAuthn APIのメソッドを叩きます。
![wetauthn (3).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/235997/1fcf0c9d-44be-fff6-5653-958a2c726f2a.png)

4 ) APIが認証器に**公開鍵クレデンシャル**(後述)を要求します。
![wetauthn (4).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/235997/fe661687-cc9f-9456-32d4-a85752251ac3.png)


5 ) 認証器はユーザーに本人確認を要求します。
![wetauthn (5).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/235997/7dd7282a-9814-5e17-2f08-6ace0b6e0818.png)


6 ) ユーザーが指紋認証・PINなどで本人確認を行います。
![wetauthn (6).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/235997/76bafb6b-ab92-10d7-583a-a1fc85bd8abe.png)

7 ) 認証器が本人情報を元に公開鍵クレデンシャルを生成し、APIなどを経由して最終的に認証サーバーに公開鍵クレデンシャルを渡します。
![wetauthn (9).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/235997/a3e3ef59-17ab-2657-cbc4-f8f1c5fd85e0.png)
公開鍵クレデンシャルには、認証情報を元に生成された公開鍵や認証器自体の正統性を示す情報、送られてきたオプションのデータが含まれています。
詳細については以下に載っています。
https://developer.mozilla.org/ja/docs/Web/API/AuthenticatorAttestationResponse


8 ) 認証サーバーが公開鍵クレデンシャルの検証・登録を行い、OKだったらWebアプリまでOKのレスポンスを返します。
![wetauthn (10).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/235997/284f5b4c-f2b2-d50b-4884-6baca2a4a2f1.png)

### 少し詳細なシーケンス図
![register.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/235997/e5c10283-2d8a-9f1f-74f0-68f4cfdcb3d6.png)

## 認証フロー
1 ) ユーザーがログイン画面で認証を要求します。Webアプリなどを経由して最後には認証サーバーに要求が届きます。
![wetauthn (11).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/235997/e482f72c-1e19-aac3-a65e-2e43e46c51c2.png)

2 ) 認証サーバーから**公開鍵クレデンシャル要求オプション**というものが返され、アプリケーションサーバーを通ってWebアプリに届きます。
![Untitled Diagram.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/235997/ca2e217c-7b0f-e806-35dd-74c6fe70bd0f.png)
公開鍵クレデンシャル要求オプションも公開鍵クレデンシャル生成オプションと同様にWebAuthn APIを使う際に必要になるパラメータです。
オプションの中身については以下に載っています。
https://developer.mozilla.org/ja/docs/Web/API/PublicKeyCredentialRequestOptions

3 ) Webアプリが返ってきたオプションを引数に**`navigator.credentials.get()`**というWebAuthn APIのメソッドを叩きます。
![Untitled Diagram (2).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/235997/fcfa5114-75c3-d5a4-3a1b-76374a3855db.png)

4 ) APIが認証器に公開鍵クレデンシャル（署名）を要求します。
![Untitled Diagram (3).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/235997/0afd1dd9-4bb5-4e00-bb32-145d2c2e8b7a.png)
今回の公開鍵クレデンシャルには登録時と異なり、デジタル署名も含まれています。この情報によって本人である正統性を証明します。
詳細については以下に載っています。
https://developer.mozilla.org/ja/docs/Web/API/AuthenticatorAssertionResponse

5 ) 認証器はユーザーに本人確認を要求します。
![Untitled Diagram (4).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/235997/84364955-7576-3d3d-8e13-3949369534e5.png)

6 ) ユーザーが指紋認証・PINなどで本人確認を行います。
![Untitled Diagram (5).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/235997/2d18104c-3bed-ff62-d3d0-d374e5f6d58f.png)

7 ) 認証器が本人情報を元に公開鍵クレデンシャルを生成し、APIなどを経由して最終的に認証サーバーに公開鍵クレデンシャルを渡します。
![Untitled Diagram (6).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/235997/2c16583b-72a9-77cb-cc26-7471b19d10d9.png)

8 ) 認証サーバーが公開鍵クレデンシャルの検証を行い、OKだったらcookieやトークンを発行しWebアプリまで届けます。
![wetauthn (12).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/235997/9b135f40-945a-88e4-6a2b-4b33aba3cb6b.png)


## 少し詳細なシーケンス図
![register.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/235997/cbd04225-e338-e2e0-cd5a-5c871d2e2416.png)

# さいごに
自分のサービスにパスワードレス認証を組み込みたいという方は以下の参考情報が役に立つと思います。
特にWEB+DB PRESSの記事はフロント・バックエンドの実装のサンプルコードも載っているのでおすすめです。

# 参考にさせて貰った記事
- [WEB+DB PRESS vol.114 「特集2 作って学ぶWebAuthn 生体認証でさよならパスワード」](https://gihyo.jp/magazine/wdpress/archive/2020/vol114)
- https://developer.mozilla.org/ja/docs/Web/API/Web_Authentication_API
- https://techblog.yahoo.co.jp/advent-calendar-2018/webauthn/