Modern Authentication -- FIDO2 Web Authentication (WebAuthn) を学ぶ --
1.
Modern Authentication FIDO2 WebAuthentication (WebAuthn) を学ぶ 栗原 淳 兵庫県立大学 大学院応用情報科学研究科 株式会社ゼタント May 25, 2020 Jun Kurihara (U-Hyogo/Zettant) Modern Authentication May 25, 2020 1 / 72
WebAuthn ユーザ登録フロー 以下のような流れで WebAuthnの認証のための登録を行う。 OK ! 単純に言うと、認証器で Credential Public Key を生成、その出生 証明を RP で確認・登録という処理。 Jun Kurihara (U-Hyogo/Zettant) Modern Authentication May 25, 2020 37 / 72
WebAuthn ユーザ登録: RPへユーザ登録要求 ⓪, ① ユーザ登録のため Credential 生成パラメタを RP から取得。 OK ! WebApp と RP 間の要求・応答フォーマットは規定されていない。 ⇒ RP 側の (REST) API は実装者に任せられている。 Jun Kurihara (U-Hyogo/Zettant) Modern Authentication May 25, 2020 39 / 72
40.
WebApp が RPから取得するパラメタは以下の通り。25 Challenge: 暗号学的にランダムな使い捨ての binary string (最 低 16bytes, 通常 32bytes 程度) User Info: ユーザ情報。ID、メールアドレス、名前。 Relying Party Info: RP(すなわちサービス) の名前、FQDN、 サービスアイコンの URL (ico ファイル)。 ブラウザは、これらを PublicKeyCredentialCreationOptions Object にし、WebAuthn API 経由で認証器へ Credential 生成を要求。 25UserInfo, RP Info は WebApp すなわちユーザが自分で定めることも (一応) できる。 Jun Kurihara (U-Hyogo/Zettant) Modern Authentication May 25, 2020 40 / 72
41.
WebAuthn ユーザ登録: 認証器へCredential 生成要求 ②, ③ ブラウザの API を Call して認証器へ Credential 生成を要求。 OK ! PublicKeyCredentialCreationOptions Object をブラウザの window.navigator.credential.create() へ入力。 Jun Kurihara (U-Hyogo/Zettant) Modern Authentication May 25, 2020 41 / 72
42.
②: 認証器に送るオブジェクトの生成 PublicKeyCredentialCreationOptions の構造(./test/credential-params.ts) const createCredentialDefaultArgs: CredentialCreationOptions = { publicKey: { // Challenge 本当はサーバーで生成した暗号学的に安全な乱数をセット (16bytes 以上) challenge: new Uint8Array([0x8C, 0x0A, 0x26, 0xFF, 0x22, ...]).buffer, // Relying Party Info (a.k.a. - Service) rp: { id: ’localhost’, // テストコードはローカルで走るため name: ’Example RP’ }, // User Info user: { id: new Uint8Array(16), name: ’john.p.smith@example.com’, displayName: ’John P. Smith’, }, // 利用したい Public Key Credential Params のリスト (認証器は先頭から試行): pubKeyCredParams: [{ type: ’public-key’, // As of March 2019, only ’public-key’ is accepted. alg: -7 // Signature Algorithm (ECDSA with SHA-256) }], // Attestation Type (optional, default は’none’ (RP による attestation 検証なし)) attestation: ’direct’, // ’direct’ は認証器の生成した Attestation を直接 RP に送るタイプ // Time Out (optional, in msec) timeout: 60000, // 認証器からの応答をブラウザはどれくらい待つか。 } }; Jun Kurihara (U-Hyogo/Zettant) Modern Authentication May 25, 2020 42 / 72
43.
③: 認証器へオブジェクト送付 PublicKeyCredentialCreationOptions Objectを使ってブラウザの WebAuthn API を以下のように Call すると、認証器の挿入・接続要求、 PIN 入力要求がブラウザ通知される。 window.navigator.credential.create() の Call (./test/test.spec.ts) const cred: Credential|null = await window.navigator.credentials.create(createCredentialDefaultArgs); 認証器挿入・接続要求 ⇒ PIN の入力要求 Jun Kurihara (U-Hyogo/Zettant) Modern Authentication May 25, 2020 43 / 72
44.
この流れは、Shell からサンプルコードのディレクトリで以下を実 行すると確認できる。 ユーザ登録→ユーザ認証の一連のテストコードを実行 $ yarntest ブラウザにダイアログが出たところで認証26を行えば、認証器内 部で Credential が生成&出生証明される。 それでは、次の Credential 生成ステップと、生成した Credential の 中身を覗いてみよう。 26Security Key by Yubico の場合は PIN 入力+タッチ Jun Kurihara (U-Hyogo/Zettant) Modern Authentication May 25, 2020 44 / 72
45.
WebAuthn ユーザ登録: Credential生成・取り出し ④, ⑤ 認証器で Credential 新規生成、Credential Public Key と署名を取得。 OK ! 前ステップの create() の返り値として、Attestation Certifiate や Credential Public Key (attestationObject) を格納した PublicKeyCredential Object をブラウザが取得。 Jun Kurihara (U-Hyogo/Zettant) Modern Authentication May 25, 2020 45 / 72
④-2: Credential KeyPair の新規生成・署名付与 認証と利用意思確認が完了すると、認証器内部で以下の処理を実行。 1 ローカルでの生体認証結果の確認 2 create() で入力されたパラメタに応じて、ユーザの新しい鍵ペア ‘Credential Key Pair’ を生成 3 認証器内部の Attestation Private Key で Credential Public Key に署名 4 (Attested) Credential Public Key とその署名を出力28 28Attestation Type: direct の場合は Attestation Certificate も出力 Jun Kurihara (U-Hyogo/Zettant) Modern Authentication May 25, 2020 47 / 72
48.
⑤: ブラウザにて PublicKeyCredentialの取得 create() の返り値 PublicKeyCredential Object は単純に以下の 4 つの 要素で構成されている。 PublicKeyCredential の構造 ($ yarn test の途中出力) ’------ [Response from Authenticator: PublicKeyCredential] ------’ ’> Credential ID: HfM8J_xY7mn7bfiHxF7f7MLxf...’ ← 生成した公開鍵の ID ’> Credential Raw ID: [object ArrayBuffer]’ ← 生成した公開鍵の ID のバイナリ版 ’> Credential Type: public-key’ ← 公開鍵証明書なので’public-key’ ’> AuthenticatorAttestationResponse.clientDataJSON: [object ArrayBuffer]’ ← RP の Challenge の情報 (バイナ リ) ’> AuthenticatorAttestationResponse.attestationObject: [object ArrayBuffer]’ ← ここが Credential Public Key と署名が含まれる本体 (バイナリ) このうち、「clientDataJSON」と「attestationObject」からなる AuthenticatorAttestationResponse を RP に送って検証・登録する。 次のステップでその検証について解説する。 Jun Kurihara (U-Hyogo/Zettant) Modern Authentication May 25, 2020 48 / 72
49.
WebAuthn ユーザ登録: Attestationの検証 ⑥, ⑦, ⑧ ブラウザが AuthenticatorAttestationResponse を RP に送って、そこで Attestation の検証とユーザ登録を実行。 OK ! Attestation の検証は RP の行うバックエンドの処理なことに注意。 Jun Kurihara (U-Hyogo/Zettant) Modern Authentication May 25, 2020 49 / 72
50.
⑥: ブラウザにて認証器出力をパース、RP への応答を作成 ⑦:attestationObject と clientdataJSON を RP へ送付 clientDataJSON はバイナリにエンコードされた JSON で、以下 の要素で構成。 clientDataJSON29 の構造。 ($ yarn test の途中結果) LOG: ’------ [Decoding result of elements of AuthenticatorAttestationResponse] ------’ LOG: ’> Decoded clientDataJSON: { "challenge": "o9sKvn8ls2QAMFNyiv_g...", ← 登録処理開始の際、RP が送付した challenge (base64url)。 "origin": "http://localhost:9876", ← Relying party の ID。今回の例だと localhost。 "type": "webauthn.create" ← ユーザ登録のときは webauthn.create 固定。 }’ 他、tokenBindingId という RP との通信セッションとの紐付けを行うパラメタ (Optional)。 これは、後述する attstationObject がどういうパラメタに対し て生成されたのかを示す一覧という位置づけ。 29 WebAuthn の認証の時もパラメータの異なるこのオブジェクトが生成される。 https://developer.mozilla.org/en-US/docs/Web/API/AuthenticatorResponse/clientDataJSON Jun Kurihara (U-Hyogo/Zettant) Modern Authentication May 25, 2020 50 / 72
WebAuthn ユーザ認証: RPへユーザ認証要求 ⓪, ① Challenge と署名させる Credential の ID を RP から取得。 OK ! 登録同様、WebApp・RP 間のやりとりは規定されておらず、実装 者に任されている。 Jun Kurihara (U-Hyogo/Zettant) Modern Authentication May 25, 2020 57 / 72
58.
WebApp が RPから取得する必要があるパラメタは以下の通り。 Challenge: 暗号学的にランダムな使い捨ての binary string (最 低 16bytes, 通常 32bytes 程度) Credential Info: ユーザの Credential Public Key の ID。認証器に 対応する Credential Private Key (署名鍵) を指定するのに必要。 規格上は Optional だが認証器が非対応の場合は指定が必須。32 ブラウザはこれらを PublicKeyCredentialRequestOptions Object にし、WebAuthn API 経由で認証器へ Assertion を要求。 32Client-side Discoverable Credential (後述) に対応していることが必要。Security Key by Yubico は 非対応。 Jun Kurihara (U-Hyogo/Zettant) Modern Authentication May 25, 2020 58 / 72
59.
WebAuthn ユーザ認証: 認証器へAssertion 生成要求 ②, ③ ブラウザの API を通して認証器へ Assertion を要求。 OK ! PublicKeyCredentialRequestOptions Object をブラウザの window.navigator.credential.get() へ入力。 Jun Kurihara (U-Hyogo/Zettant) Modern Authentication May 25, 2020 59 / 72
60.
②: 認証器に送るオブジェクトの生成 実際に JavaScriptのコードを見ていく。 PublicKeyCredentialRequestOptions の構造 (./test/credential-params.ts) export const getCredentialDefaultArgs: CredentialRequestOptions = { publicKey: { // Challenge 本当はサーバーで生成した暗号学的に安全な乱数をセット (16bytes 以上) challenge: new Uint8Array([ 0x79, 0x50, ... ]).buffer, // Info of credential public keys allowed to use authentication (optional) // 認証器次第ではここを RP が指定しなくても OK // (RP ID に応じてユーザが鍵を選べる, Client-side Discoverable Credential と呼ぶ) allowCredentials: [{ id: new Uint8Array([0xA1, 0x55, ...]).buffer, transports: [’usb’, ’nfc’, ’ble’], type: ’public-key’ }], // rpId indicating Relying Party ID (optional, default = current domain) rpId: ’localhost’, // テストコードはローカルで走るため // User verification (biometrics authentication, optional, default = ’preferred’) // PIN が未指定の場合などは、’required’ にすると検証不可として認証エラー userVerification: ’required’, // Time out (optional, in msec) timeout: 60000, }, }; Jun Kurihara (U-Hyogo/Zettant) Modern Authentication May 25, 2020 60 / 72
61.
③: 認証器へオブジェクト送付 PublicKeyCredentialRequestOptions Objectを使ってブラウザの WebAuthn API を以下のように Call すると、登録の時と同様に認証器の挿 入・接続要求、PIN 入力要求、認証要求がブラウザ通知される。 window.navigator.credential.get() の Call (./test/test.spec.ts) const cred: Credential|null = await window.navigator.credentials.get(getCredentialDefaultArgs); Jun Kurihara (U-Hyogo/Zettant) Modern Authentication May 25, 2020 61 / 72
62.
補足: Client-side DiscoverableCredential について PublicKeyCredentialRequestOptions において、allowCredentials なしとする Client-side Discoverable Credential33 が利用できる。この機能 は、以下の特徴を持つ。 認証時に RP から Credential ID を取得する必要がなく、ユーザ自身 が RP ID に応じて Credential を切り替え可能 RP 側でユーザ名などと Credential ID の紐付け管理が不要 ただし、利用には認証器がこの機能に対応している必要がある。 33 現在の仕様 (ver. 4 Mar. 2019) 上は Resident Credential と呼ばれているが、Working Draft で名称 が変わった。https://w3c.github.io/webauthn/#client-side-discoverable-credential Jun Kurihara (U-Hyogo/Zettant) Modern Authentication May 25, 2020 62 / 72
63.
WebAuthn ユーザ認証: Assertion生成・取り出し ④, ⑤ 認証器で Challenge へ署名し、Assertion を取得。 OK ! 前ステップの get() の返り値として、署名 (signature) やメタ情報 (authenticatorData) を格納した PublicKeyCredential Object を取得。 Jun Kurihara (U-Hyogo/Zettant) Modern Authentication May 25, 2020 63 / 72
64.
④: ローカルでの生体認証・認証器での Assertion生成 認証器にタッチすることで生体認証を完了させると、認証器内部 で Assertion = Challenge への署名生成が行われる。 PIN 入力要求 ⇒ 認証要求 Jun Kurihara (U-Hyogo/Zettant) Modern Authentication May 25, 2020 64 / 72
65.
⑤: ブラウザにて PublicKeyCredentialObjectの取得 get() の返り値 PulicKeyCredential Object は以下の要素で構成され る。create() では AuthenticatorAttestationResponse が入ってい たが、AuthenticationAssertionResponse が入ることに注意。 PublicKeyCredential の構造 ($ yarn test の途中出力) LOG: ’------ [Response from Authenticator: PublicKeyCredential] ------’ LOG: ’> Credential ID: jsQqwn1tT5C-I01ELUVq7m...’ ← 署名検証に用いる公開鍵の ID = Credential Public Key ID LOG: ’> Credential Raw ID: [object ArrayBuffer]’ ← ID のバイナリ版 LOG: ’> Credential Type: public-key’ ← 署名は公開鍵で検証されるものなので’public-key’ LOG: ’> AuthenticatorAssertionResponse.clientDataJSON: [object ArrayBuffer]’ ← RP の Challenge の情報 LOG: ’> AuthenticatorAssertionResponse.authenticatorData: [object ArrayBuffer]’ ← 認証器の情報や RP の ID など LOG: ’> AuthenticatorAssertionResponse.signature: [object ArrayBuffer]’ ← RP の Challenge に対する応答= 署名! LOG: ’> AuthenticatorAssertionResponse.userHandle: null’ ← Create 時に入力したユーザ ID が入ることが多い このうち、AuthenticatorAssertionResponse 内部の 4 要素を RP に 送って検証 (Assertion の検証)、認証可否を判断する。次ステップでその 手順を解説する。 Jun Kurihara (U-Hyogo/Zettant) Modern Authentication May 25, 2020 65 / 72
66.
WebAuthn ユーザ認証: Assertionの検証 ⑥, ⑦, ⑧ ブラウザが AutehtncatorAssertionResponse を RP へ送っ て、そこで Assertion の検証と認証可否判断を行う。 OK ! Assertion の検証は RP の行うバックエンドの処理なことに注意。 Jun Kurihara (U-Hyogo/Zettant) Modern Authentication May 25, 2020 66 / 72
67.
⑥: ブラウザにて認証器出力をパース、RP への応答を作成 ⑦:clientDataJSON・authenticatorData・signature を RP へ送付 AuthenticatorAssertionResponse の要素の構造は以下の通り。 clientDataJSON の構造, authenticatorData, signature ($ yarn test の途中結果) LOG: ’------ [Decoding result of elements of AuthenticatorAssertionResponse] ------’ LOG: ’> Decoded clientDataJSON: { "challenge": "rHNRQ6copASyNLyFv0Ja...", ← 認証処理開始の際、RP が送付した challenge (base64url) "origin": "http://localhost:9876", ← RP ID "type": "webauthn.get" ← ユーザ認証の時は webauthn.get 固定。 }’ LOG: ’> Base64 authenticatorData: SZYN5YgOj...’ ← 認証器の情報や Credential が紐付けられている RP ID などのデータ LOG: ’> Base64 signature: MEYCIQDI0cKyqpksA...’ ← clientDataJSON と authenticatorData に対して作られた署名 clientDataJSON のハッシュ値と authenticatorData を連結したデータに 対して Credential Private Key で署名生成されている。 ⇒ RP はこの連結データに対して signature が正しいものかどうかを検証。 Jun Kurihara (U-Hyogo/Zettant) Modern Authentication May 25, 2020 67 / 72
68.
⑧: RP による検証・認証可否の決定RP は authenticatorData、 signature、clientDataJSON に対して以下を検証する。(=Assertion の 検証) 1 RP 自身が要求した Assertion 作成なのか? ⇒ clientDataJSON 内部と、RP で保持していたチャレンジの比較 2 RP のサービスで認証すべき要求なのか? ⇒ clientDataJSON 内部の origin のチェック ⇒ authenticatorData に含まれる RP ID のチェック 3 事前登録したユーザ・認証器によって作られた Assertion か? ⇒ Credential ID が紐づいている Attested Credential Public Key を登録 ユーザの DB から取得。clientDataJSON のハッシュ値と authenticatorData について、signature (署名) の正しさを、 Credential Public Key で検証。 Jun Kurihara (U-Hyogo/Zettant) Modern Authentication May 25, 2020 68 / 72
69.
テストコードで模擬する RP のAssertion 検証結果を見てみよう。 assertion 検証結果 ($ yarn test の途中結果) LOG: ’------ [Verification result on PublicKeyCredential.AuthenticatorAssertionResponse] ------’ LOG: ’> Verification result: true’ ← Assertion の検証成功 (challenge/origin/署名の検証成功) Assertion 検証のソースコード解説は、ただのフォーマット解説の ため省略。 Jun Kurihara (U-Hyogo/Zettant) Modern Authentication May 25, 2020 69 / 72
この資料では以下を行った。 認証の基礎と、FIDO2 の概要の紹介 FIDO2 WebAuthnの概要の紹介 FIDO2 WebAuthn のユーザ登録・認証についてコードレベルで 動作解説 ただし、今回触ってみたことが WebAuthn の全体像ではないことに 注意。仕様は日々進化しており、またパラメタもここで掲載した もの以外にも多く存在する。あくまで 1 つの例と考えてほしい。 Jun Kurihara (U-Hyogo/Zettant) Modern Authentication May 25, 2020 71 / 72
72.
参考資料: WebAuthn の標準文書・仕様書 WebAuthentication (W3C 勧告) https://www.w3.org/TR/webauthn-1 Web Authentication (W3C Working Draft) https://w3c.github.io/webauthn Web Authentication API (MDN) https://developer.mozilla.org/en-US/docs/Web/API/Web_ Authentication_API Jun Kurihara (U-Hyogo/Zettant) Modern Authentication May 25, 2020 72 / 72