WEBベース生体認証調査第１弾

[KINTO Technologies Advent Calendar 2021 - Qiita](https://qiita.com/advent-calendar/2021/kinto-technologies) の5日目の記事です。

#### ネーティブアプリの生体認証は数年前から普通に色んなアプリに装備されて活用していますが、Webから端末の生体認証機能を活かしてユーザー認証を済ませるサービスはまだそんなに多くないようです。 今回、生体認証をWEBベースの認証システムに標準装備してアプリ毎に組み込まなくても使えるようにしたくて調査したところ、WebAuthn（Web Authentication）で実現可能ではないかと考えています。

WebAuthn：ブラウザ経由でパスワードレス認証を行うための仕組み。
WebAuthnを実現するために用意されているJavaScript APIをWebAuthn APIと呼ぶ。

### 生体認証を有効にしてWebAuthnにユーザ登録

#####仕組み：
ユーザがログイン済の状態で生体認証を有効化すると、サーバーがユーザ情報やRP（Relying Party）情報を提供して、今後パスワードに代わり認証用鍵（public鍵）を求めます。
ブラウザが、サーバーから発行してもらったchallengeと取得したユーザ情報やRP情報を元に、Webauthn Api経由で認証機に鍵ペアを作ってもらって、public鍵をサーバーに返す。
また、サーバーは発行したchallengeを確認して正しければ今後認証用public鍵を保管する。

Webauthn API呼び出すサンプルコード：

```clent.js
const optionsFromServer = {
        "challenge" : "random_string", // ArrayBufferに変換
        "rp" : {
            "name" : "My website",
            "id" : "mywebsite.com"
        },
        "user": {                      // ユーザー情報
            "name": "anthony@email.com",
            "displayName": "Anthony",
            "id": "USER_ID_1234567890",
        },
        "pubKeyCredParams": [
            {                      
            "type": "public-key",
            "alg": -7,
            }
        ],
        "authenticatorSelection": {
            authenticatorAttachment: "platform",
        },
        "timeout" : 60000              // ms単位
    }
  
   const credential = await navigator.credentials.create({
      publicKey: optionsFromServer
    });
```
レスポンスサンプル：

```
PublicKeyCredential {
        id: 'ABCDEFGa23adfas09w0eFb',
        rawId: ArrayBuffer(59),
        response: AuthenticatorAssertionResponse {
            clientDataJSON: ArrayBuffer(121),
            attestationObject: ArrayBuffer(306),
        }
        type: 'public-key'
    }
```

### ユーザは生体認証を使ってRPにログインする

#####仕組み：
ユーザが生体認証ログイン要求するとサーバーがchallengeを発行してユーザーに署名を求める。
ブラウザがWebauthn Api経由で認証機に認証データを用意してもらう。
生体認証成功した場合署名した認証データブラウザに返却して、ブラウザがその認証データをさらにサーバーに渡す。
サーバーが保管したpublicキーを使って正当性確認して認証する。

Webauthn API呼び出すサンプルコード：

```clent.js
const optionFromServer =  {
    "challenge": 'somerandomstring',
    "timeout": 60000,
    "allowCredentials": [
      {                      
      "type": "public-key",
      "id": "AdPc7AjUmsefw37...",
      }
  ],
    type: 'public-key'
}

  const assertion = await navigator.credentials.get({
    publicKey: optionFromServer
  });
```

レスポンスサンプル：

```
PublicKeyCredential {
    id: 'ABCDEFGa23adfas09w0eFb...',     // WebAuthn ID
    rawId: ArrayBuffer(59),
    response: AuthenticatorAssertionResponse {
        authenticatorData: ArrayBuffer(191),
        clientDataJSON: ArrayBuffer(118),
        signature: ArrayBuffer(70),      //  認証必要な署名  
        userHandle: ArrayBuffer(10),
    }
    type: 'public-key'
}
```

# 以下のブラウザが対応

Safari に対応 ( macOS Big Sur から)
Google Chrome
Microsoft Edge
Vivaldi
Brave
Firefox ではまだ使えない
Chromium 系ブラウザでも Opera やオープンソースの Chromium 等では使えない
セキュリティキー認証であれば Firefox を含む大概のブラウザで対応している
# iOS での対応状況
Touch ID / Face ID でログイン可能
iOS/iPadOS 14 から Safari で対応
iOS/iPadOS 14.6 から認証画面がリニューアルし、他のブラウザでも WebAuthn に対応した

#####Windows, Android では Chrome, Edge, Firefox 共に Windows Hello や指紋認証などに対応しているらしい 

当社では、トヨタ車のサブスク「KINTO」等の企画/開発を行っており、エンジニアを募集中です。
[KINTO Technologies コーポレートサイト](https://www.kinto-technologies.com/)