Modern Authentication FIDO2 Web Authentication (WebAuthn) を学ぶ 栗原 淳 兵庫県立大学 大学院応用情報科学研究科 株式会社ゼタント May 25, 2020 Jun Kurihara (U-Hyogo/Zettant) Modern Authentication May 25, 2020 1 / 72
はじめに Jun Kurihara (U-Hyogo/Zettant) Modern Authentication May 25, 2020 2 / 72
はじめに この講義では、 パスワード認証に代わるモダンな認証方式「FIDO」の概要 FIDO の認証を Web ブラウザ経由で利用する「FIDO2 WebAuthn」の利用 のさわりを学ぶ。 Jun Kurihara (U-Hyogo/Zettant) Modern Authentication May 25, 2020 3 / 72
この講義の対象と事前準備 対象: 暗号・セキュリティ技術に興味がある初学者 Web に新しい認証技術を導入したい Web 系のエンジニア ※但し、ある程度の公開鍵暗号・電子署名の知識を前提とする1 必須ではないが触って楽しむのには必要な事前準備: Bash/Zsh, Git が使えるようになっていること Node.js, npm, yarn が使えるようになっていること Google Chrome ブラウザが利用可能なこと 1どういうものか、というのを知っていれば十分。「JavaScript を使って学ぶ End-to-End セキュリ ティ」の資料を読んでいることを推奨 (https://github.com/junkurihara/class-e2e_security_js)。 Jun Kurihara (U-Hyogo/Zettant) Modern Authentication May 25, 2020 4 / 72
パスワード認証からFIDO へ Jun Kurihara (U-Hyogo/Zettant) Modern Authentication May 25, 2020 5 / 72
認証とは 認証 「何らかの手段」で対象の正当性を確認すること。 メッセージの正当性を確認 ⇒ メッセージ認証 サービス利用ユーザの正当性を確認 ⇒ ユーザ認証 etc. ※このスライドで単純に「認証」と呼んだときは、認証対象を「正 規ユーザ本人」としたユーザ認証・本人認証を指すこととする。 Jun Kurihara (U-Hyogo/Zettant) Modern Authentication May 25, 2020 6 / 72
本人認証の 3 つの要素 本人認証において、正当性確認のため検証されるものは大きく 3 要素に分類。 知識 ⇒ 本人しか知らない知識を持っていれば OK (ex. パスワード) 所有物 ⇒ 本人しか持っていない物を提示できれば OK (ex. HW キー) 生体 ⇒ 本人の体の一部を提示できれば OK (ex. 指紋) Jun Kurihara (U-Hyogo/Zettant) Modern Authentication May 25, 2020 7 / 72
オンラインサービスでのパスワード認証 サービスの利用者の識別子 (ID) と対応するパスワードをサー ビス事業者に登録、サービス利用時に利用者が自分の ID とパ スワードを入力する。 パスワードは個人の記憶にのみ存在するため、パスワードを 知っている人はそのサービスに登録してる本人と同一人物と 考えることができる。 おそらく、誰にとっても最も馴染み深い認証方式! Jun Kurihara (U-Hyogo/Zettant) Modern Authentication May 25, 2020 8 / 72
Figure: オンラインでの単純なパスワード認証 Jun Kurihara (U-Hyogo/Zettant) Modern Authentication May 25, 2020 9 / 72
オンラインでのパスワード認証の問題 英数字・記号を組み合わせたパスワード: 攻撃者にとって比較的予測しやすい2 「強い」パスワードを使わせるにはユーザ教育が必要3 覚えられない etc... 予測できず、誰が使っても強力で、確実に認証できる方法が必要 ⇒ ハードウェアセキュリティキーを使った認証が人気に ⇒ FIDO はそのような手法の標準化された方式 2しかもオンラインだと予測→認証トライを繰り返せる 3教育なしだと覚え易く「弱い」ものを利用しがち Jun Kurihara (U-Hyogo/Zettant) Modern Authentication May 25, 2020 10 / 72
FIDO FIDO (Fast IDentity Online) 業界団体 FIDO Alliance4 の策定する、ハードウェアセキュリティ キー+生体認証 5 と公開鍵暗号方式をベースとしたオンラインでの 本人認証技術。 現在は FIDO2 (v2.0) が最新の規格。以降、FIDO2 の内容について 触れていく。 厳密には、FIDO2 はパスワードレス認証をサポートしつつも、パ スワード+デバイス・生体認証の多要素での認証もサポートする。 4 https://fidoalliance.org 5 すなわち、「所有物」と「生体」の二要素を同時に使った認証が可能。 Jun Kurihara (U-Hyogo/Zettant) Modern Authentication May 25, 2020 11 / 72
FIDO 認証概略 FIDO 認証の特徴: 公開鍵暗号を利用した、オンラインでの認証方式の提供 認証器によるローカルでの本人認証 認証器内部に閉じた署名生成 ⇒ 秘密鍵・パスワード等の秘密情報は外部に出ない Figure: FIDO 認証概略 Jun Kurihara (U-Hyogo/Zettant) Modern Authentication May 25, 2020 12 / 72
FIDO2 の要素 FIDO2 は、WebAuthn (Web Authentication)6と、CTAP (Client-to-Authenticator Protocol)7の 2 つの要素で構成される。 WebAuthn: 内部/外部認証器を Call する WebAPI と、WebApp・ サーバ間のデータフローを規定。 CTAP: 外部認証器を Call する API と、クライアント/プラット フォームと認証器の通信プロトコルを規定。 6Spec: https://www.w3.org/TR/webauthn-1/ 7Spec: https://fidoalliance.org/specs/fido2/fido-client-to-authenticator-protocol-v2.1-rd-20191217.html Jun Kurihara (U-Hyogo/Zettant) Modern Authentication May 25, 2020 13 / 72
図で見ると CTAP・WebAuthn は以下のような役割分担。 Jun Kurihara (U-Hyogo/Zettant) Modern Authentication May 25, 2020 14 / 72
FIDO2 CTAP8 USB/BLE/NFC 等で接続された HW セキュリティキーなどの外部認 証器と、クライアントアプリ (ブラウザ等) およびプラットフォー ム (OS) との間の通信プロトコルを規定。以下の要素で構成。 USB/BLE/NFC など物理層の種別に応じた、通信確立のための プロトコル 認証器での処理を Call する API 外部認証器の情報取得 PIN によるローカルでのユーザ認証 9 認証器組込の秘密鍵での、ユーザ秘密鍵・証明書生成 ユーザ秘密鍵による署名の生成、など ブラウザ・OS(のドライバ) は上記を実装した上で、より上位の WebAuthn のプロトコルをサポート。 8 https: //fidoalliance.org/specs/fido-v2.0-ps-20190130/fido-client-to-authenticator-protocol-v2.0-ps-20190130.html 9 指紋認証やジェスチャーなどは認証器のみで完結するので API は用意されない。署名生成などのときに認証器内での認証を要 求するフラグを立てる。 Jun Kurihara (U-Hyogo/Zettant) Modern Authentication May 25, 2020 15 / 72
FIDO2 WebAuthn10 Web ブラウザをプラットフォームとし、内部/外部認証器によって 生成される署名を用いた、オンラインサーバでのユーザ認証のプ ロトコルを規定。より具体的には、以下を規定する。 認証器でのユーザの公開鍵証明書の生成、サーバへの登録プ ロトコル 認証器での署名生成、サーバでの認証プロトコル 認証器とやりとりするためブラウザが具備すべき Web API11 。 大雑把に以下の 2 種類。 ユーザの公開鍵証明書の生成 (Credential Creation) ユーザ秘密鍵による署名の生成 (Assertion Generation) 認証器とのやり取りはブラウザ/プラットフォームがサポート。 ⇒ 基本的に Web App の観点からは、WebAuthn のみを意識する。 10 https://www.w3.org/TR/webauthn-1/ 11 JavaScript で Call される API。ブラウザの内部でさらに認証器の API (CTAP や内部 API) を Call する。 Jun Kurihara (U-Hyogo/Zettant) Modern Authentication May 25, 2020 16 / 72
補足: FIDO1 FIDO1 (v1.x) は、以下の 2 つの要素で構成されている。 UAF (Universal Authentication Framework): 生体認証機能を持つ FIDO 対応端末 (スマートフォン等) でパスワードレス認証を行う機構。 USB 接続などの外部 HW セキュリティキーは利用できない。 U2F (Universal 2nd Factor)12 : ID・パスワード認証に加えた 2 要素認 証を行うのに、外部 HW セキュリティキーを利用可能とする機構。 FIDO2 は、UAF と U2F を統合し、さらに外部 HW キーを用いてもパス ワードレス認証可能な、より利便性の高い規格と見做せる。 12 U2F は FIDO2 規格では CTAP1 と改称。FIDO2 で追加された仕様は CTAP2 と呼ばれる。 Jun Kurihara (U-Hyogo/Zettant) Modern Authentication May 25, 2020 17 / 72
FIDO2 対応の認証器 USB/NFC/BLE 等対応の外部認証器 (External Authenticator)、端末付 属の認証器 (On-device/Internal Authenticator) 共々、様々な対応デバ イスがリリースされつつある。 Security Key by Yubico FIDO2 専用 13 YubiKey 5Ci FIDO2+OpenPGP+etc... MacbookPro TouchID FIDO2 認証可能 14 13 FIDO2 CTAP1=FIDO1 U2F には対応。 14 ブラウザ等が TouchID API を Call できれば FIDO2 の On-device Authenticator として動作。 Chrome 等は対応済。 Jun Kurihara (U-Hyogo/Zettant) Modern Authentication May 25, 2020 18 / 72
FIDO2 標準化状況 FIDO は業界団体の策定した規格ではあるが、 FIDO2 CTAP: ITU-T で勧告として国際標準化15 FIDO2 WebAuthn: W3C で勧告として国際標準化16 と、認証器とプラットフォーム/ブラウザ間の通信プロトコル、 サーバ・ブラウザ間の認証プロトコルの両者共に国際標準として 策定済。 15https://fidoalliance.org/ fido-alliance-specifications-now-adopted-as-itu-international-standards/ 16https://www.w3.org/2019/03/pressrelease-webauthn-rec.html.ja Jun Kurihara (U-Hyogo/Zettant) Modern Authentication May 25, 2020 19 / 72
この後、FIDO2 WebAuthn の内容に実際に触れ、最新の認証技術に ついて理解を深めてみよう。17 17今回は Web 技術から学ぶセキュリティに注力するため、ローレイヤの FIDO2 CTAP については 別の機会で。 Jun Kurihara (U-Hyogo/Zettant) Modern Authentication May 25, 2020 20 / 72
実験環境の準備 Jun Kurihara (U-Hyogo/Zettant) Modern Authentication May 25, 2020 21 / 72
準備 説明を聞きつつ手を動かすため、まず環境準備。 今回は以下の 2 つを WebAuthn の API を Call しながら実験して みる。 認証器を使って「ユーザ登録」 ⇒ 認証器からのメッセージを解してみて実際に証明書および 生の公開鍵を取り出してみる。 認証器を使って「ユーザ認証」 ⇒ 署名を解してみて、登録時に取り出した公開鍵で署名が通 ることを確認してみる。 ⇒ この 2 つが FIDO2 WebAuthn のパスワードレス認証の基礎。 Jun Kurihara (U-Hyogo/Zettant) Modern Authentication May 25, 2020 22 / 72
環境 以下の環境が前提: Node.js LTS (≥ 12) がインストール済で yarn が使える18 ブラウザとして、Google Chrome (系ブラウザ)、もしくは Firefox がインストール済み Visual Studio Code や WebStorm などの統合開発環境がセット アップ済みだとなお良い 18インストールコマンド: npm i -g yarn Jun Kurihara (U-Hyogo/Zettant) Modern Authentication May 25, 2020 23 / 72
JavaScript プロジェクトの準備 1 プロジェクトの GitHub リポジトリを Clone $ git clone https://github.com/junkurihara/class-fido2_webauthn.git $ cd sample 2 依存パッケージのインストール $ yarn install 3 ライブラリのビルド $ yarn build Jun Kurihara (U-Hyogo/Zettant) Modern Authentication May 25, 2020 24 / 72
認証器の準備 実験の前に認証器をセットアップしておく。例えば「Security Key by Yubico」の場合は、「YubiKey Manager」をインストールし、PIN を設定。19 Figure: YubiKey Manager (Mac) 19「PIN+認証器へのタッチ」が生体認証という扱い。PIN 設定はなくても動作するが、タッチだ けで生体認証したことになってしまう。PIN ではなく指紋認証を使うような認証器では、指紋登録 が前もって必要。 Jun Kurihara (U-Hyogo/Zettant) Modern Authentication May 25, 2020 25 / 72
FIDO2 WebAuthn Jun Kurihara (U-Hyogo/Zettant) Modern Authentication May 25, 2020 26 / 72
FIDO2 WebAuthn 事始め Jun Kurihara (U-Hyogo/Zettant) Modern Authentication May 25, 2020 27 / 72
FIDO2 WebAuthn のフローの参加エンティティ WebAuthn の動作フローでは、以下の 3 つの (抽象化された) 参加エ ンティティが存在。 1 Relying Party (RP): サービス提供者の認証サーバ 2 ブラウザ+RP の WebApp: ユーザおよび認証器とやり取り 3 Authenticator: 内部/外部認証器。以下をセキュアに保持。 Attestation Key Pair: 公開鍵・秘密鍵ペア Attestation Certificate: 上記の公開鍵に対し、FIDO2 で承認さ れた製造元が署名した証明書 Jun Kurihara (U-Hyogo/Zettant) Modern Authentication May 25, 2020 28 / 72
WebAPI として用意される WebAuthn API は、ブラウザ経由で WebApp が認証器とやりとりする役割を担う。 Jun Kurihara (U-Hyogo/Zettant) Modern Authentication May 25, 2020 29 / 72
FIDO2 WebAuthn の 2 つのフロー FIDO2 WebAuthn は、2 つの動作フローを規定する。 ユーザ登録フロー: 認証器を使って、Relying Party にユーザの ID や認証情報=公開鍵20を登録する処理 ユーザ認証フロー: 認証器を使って、Relying Party に事前に認 証情報を登録したユーザ自身であることを証明する処理。 以降、この 2 つのフローの中身を見ていくが、その前に FIDO2 WebAuthn において登録・認証の安全性を担保する Attestation と いう概念について解説しよう。 20Credential Public Key/Certificate のこと Jun Kurihara (U-Hyogo/Zettant) Modern Authentication May 25, 2020 30 / 72
FIDO2 における Attestation FIDO2 では、「Attestation」という重要な概念が存在する。 FIDO2 における Attestation 主として、「新しく生成・登録するユーザの公開鍵が、正しく FIDO2 認定を受けている認証器で生成された公開鍵であることを 保証する機構」という意味。すなわち、出生証明。 Relying Party は、出生証明を確認してユーザを登録。 ⇒ 偽造認証器を摑まされたユーザの登録を弾ける。 ⇒ 認証器に基づく FIDO2 認証の安全性は維持。 ※認証器で生成するユーザの鍵ペアを Credential Key Pair、Attest されたその公開鍵を Attested Credential Public Key と呼ぶ。 Jun Kurihara (U-Hyogo/Zettant) Modern Authentication May 25, 2020 31 / 72
Attestation の流れ。Attestation は 2 段階の証明で成立: ユーザ登録時にユーザ公開鍵 (Credential Public Key) を出生証明して登録 ⇒ Attested Credential Public Key の署名を Attestation Certificate で検証 ⇒ Attestation Certificate を FIDO 認証ベンダの公開鍵21で検証 21ルート証明書 Jun Kurihara (U-Hyogo/Zettant) Modern Authentication May 25, 2020 32 / 72
補足: Attestation の種類 Basic: ベンダが認証器モデルごとに特有の Attestation Key Pair を埋込む。 同じモデルの認証器では同じ鍵ペアでも良い。 Self: Attestation Private Key = Credential Private Key として、自分の秘密鍵 で署名して自己 Attest する。 AttCA22 : Attestation Certificate を動的に生成する手法。外部に信頼できる第 三者の認証局を設け、認証器が Attestation (Identity) Key Pair を生成して、 認証局へその公開鍵への署名を依頼。 ECDAA23 : 楕円曲線上の匿名認証 (Direct Anonymous Attestation; DAA) を利 用して、認証器の情報を与えることなく出生証明を実現。 None: Attestation なし。 この資料では Basic 前提。 Basic でも HW 構造的に秘密鍵は認証器から取出せない。AttCA では、認 証器の TPM に埋め込まれた鍵を、証明書生成ではなく認証局との暗号通 信用に用いる。 22 Attestation Certificate Authority 23 Elliptic Curve based Direct Anonymous Attestation; アルゴリズム仕様は現状ドラフト。 Jun Kurihara (U-Hyogo/Zettant) Modern Authentication May 25, 2020 33 / 72
この後やってみること この後は、 ユーザ登録フロー ユーザ認証フロー の両者において、localhostでRPを模擬24しつつ、認証器・ブラウザ間で やりとりされるデータと、認証器内部での処理をコードを見ながら確 認・解説していく。 24ブラウザ・RP とのやりとりは標準がないことと、処理フロー・データフローを理解することに 重点をおくため。しかし Python Flask 等で REST API でやりとりするサーバは簡単に実装可能。 Jun Kurihara (U-Hyogo/Zettant) Modern Authentication May 25, 2020 34 / 72
以下のコマンドをとりあえず叩いてみると、ブラウザ (Google Chrome) が立ち上がって認証器の挿入を求められることが確認で きる。 ユーザ登録→ユーザ認証の一連のテストコードを実行 $ yarn test // sample ディレクトリで実行 この時に行われている動作を解説する。 Jun Kurihara (U-Hyogo/Zettant) Modern Authentication May 25, 2020 35 / 72
FIDO2 WebAuthn ユーザ登録フロー Jun Kurihara (U-Hyogo/Zettant) Modern Authentication May 25, 2020 36 / 72
WebAuthn ユーザ登録フロー 以下のような流れで WebAuthn の認証のための登録を行う。 OK ! 単純に言うと、認証器で Credential Public Key を生成、その出生 証明を RP で確認・登録という処理。 Jun Kurihara (U-Hyogo/Zettant) Modern Authentication May 25, 2020 37 / 72
このユーザ登録の各ステップを、実際のデータを確認しながら 追っていく。 Jun Kurihara (U-Hyogo/Zettant) Modern Authentication May 25, 2020 38 / 72
WebAuthn ユーザ登録: RP へユーザ登録要求 ⓪, ① ユーザ登録のため Credential 生成パラメタを RP から取得。 OK ! WebApp と RP 間の要求・応答フォーマットは規定されていない。 ⇒ RP 側の (REST) API は実装者に任せられている。 Jun Kurihara (U-Hyogo/Zettant) Modern Authentication May 25, 2020 39 / 72
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
WebAuthn ユーザ登録: 認証器へ Credential 生成要求 ②, ③ ブラウザの API を Call して認証器へ Credential 生成を要求。 OK ! PublicKeyCredentialCreationOptions Object をブラウザの window.navigator.credential.create() へ入力。 Jun Kurihara (U-Hyogo/Zettant) Modern Authentication May 25, 2020 41 / 72
②: 認証器に送るオブジェクトの生成 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
③: 認証器へオブジェクト送付 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
この流れは、Shell からサンプルコードのディレクトリで以下を実 行すると確認できる。 ユーザ登録→ユーザ認証の一連のテストコードを実行 $ yarn test ブラウザにダイアログが出たところで認証26を行えば、認証器内 部で Credential が生成&出生証明される。 それでは、次の Credential 生成ステップと、生成した Credential の 中身を覗いてみよう。 26Security Key by Yubico の場合は PIN 入力+タッチ Jun Kurihara (U-Hyogo/Zettant) Modern Authentication May 25, 2020 44 / 72
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
④-1: ローカルでの生体認証 前ステップの後、認証器ローカルでの生体認証27、および FIDO2 WebAuthn の利用確認が求められる。 認証要求 ⇒ FIDO2 利用意思の確認 27Security Key by Yubico の場合、PIN 入力の後にタッチすること。 Jun Kurihara (U-Hyogo/Zettant) Modern Authentication May 25, 2020 46 / 72
④-2: Credential Key Pair の新規生成・署名付与 認証と利用意思確認が完了すると、認証器内部で以下の処理を実行。 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
⑤: ブラウザにて 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
WebAuthn ユーザ登録: Attestation の検証 ⑥, ⑦, ⑧ ブラウザが AuthenticatorAttestationResponse を RP に送って、そこで Attestation の検証とユーザ登録を実行。 OK ! Attestation の検証は RP の行うバックエンドの処理なことに注意。 Jun Kurihara (U-Hyogo/Zettant) Modern Authentication May 25, 2020 49 / 72
⑥: ブラウザにて認証器出力をパース、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
attestationObject は CBOR30で表現され、以下の要素で構成。 attestationObject31 の構造。 ($ yarn test の途中結果) [ { "fmt": "packed", ← フォーマット規定。WebAuthn の場合は"packed"で最適化されている。 "attStmt": { /* fmt="packed"のとき、Attestation Certificate と署名のフィールド */ "alg": -7, ← ECDSA with SHA-256 で作られた署名という意味 (COSE) "sig": { "type": "Buffer", "data": "MEUCIBJog73SH9q+gu...", ← "x5c"の証明書で検証可能な署名 (本当はバイナリ) }, "x5c": [ { "type": "Buffer", "data": "MIICvDCCAaSgAwIB...", ← これこそが Attestation Certificate! } ] }, "authData": { /* 署名対象、つまり Credential Public Key のフィールド */ "type": "Buffer", "data": "SZYN5YgOjGh0NBcPZHZg..." ← Credential Public Key とそのメタ情報 (登録する RP の ID など)、 ローカル生体認証の結果など (本当はバイナリ) } } ]’ fmt=“packed” の場合、署名は、clientDataJSON のハッシュ値と、 attestationObject.authData を連結したデータに対して生成。 30Concise Binary Object Representation。バイナリの JSON のようなもの。 31 clientDataJSON と異なり、登録の時のみ生成されるオブジェクト。 Jun Kurihara (U-Hyogo/Zettant) Modern Authentication May 25, 2020 51 / 72
⑧: RP による検証・登録 RP は attestationObject と clientDataJSON について以下を検証。 1 RP 自身が要求した Credential 生成なのか? ⇒ clientDataJSON 内部と、RP で保持していたチャレンジの比較 2 RP のサービスで登録すべき Credential 生成なのか? ⇒ clientDataJSON 内部の origin のチェック ⇒ attestationObject.authData に含まれる RP ID のチェック 3 FIDO2 で利用可能な正しい認証器を使った登録か? ⇒ clientDataJSON のハッシュ値と authData について、 attStmt.sig (署名) の正しさを attStmt.x5c (Attestation Certificate) を使って検証 ⇒ ルート証明書により、attStmt.x5c の信頼性を検証 上記のチェックが全部 OK であれば authData (内部の Attested Credential Public Key) を保存、ユーザ登録完了! Jun Kurihara (U-Hyogo/Zettant) Modern Authentication May 25, 2020 52 / 72
テストコードで模擬する RP の Attestation 検証動作結果を見てみよう。 RP による PublicKeyCredential の検証結果の例 ($ yarn test の途中出力) LOG: ’------ [Verification result on PublicKeyCredential.AuthenticatorAttestationResponse] ------’ LOG: ’> Verification result: true’ ← Attestation の検証成功 (challenge/origin/署名の検証成功) LOG: ’> Attested Credential Public Key: ← 検証が成功した Attested Credential Public Key (毎回変化; これを登録) -----BEGIN PUBLIC KEY----- MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEt11IqJnVr2Wi4nIip57LPhoAejRG TH86zg3S7CUYSFibLqVOQrbQ00ADz9IpYHoKzQCbbHcl3o8Zj7WgHUy1yQ== -----END PUBLIC KEY-----’ LOG: ’> Attestation Certificate: ← 認証器が送ってきた Attestation Certificate (固定) -----BEGIN CERTIFICATE----- MIICvDCCAaSgAwIBAgIEBMX+/DANBgkqhkiG9w0BAQsFADAuMSwwKgYDVQQDEyNZ dWJpY28gVTJGIFJvb3QgQ0EgU2VyaWFsIDQ1NzIwMDYzMTAgFw0xNDA4MDEwMDAw MDBaGA8yMDUwMDkwNDAwMDAwMFowbTELMAkGA1UEBhMCU0UxEjAQBgNVBAoMCVl1 YmljbyBBQjEiMCAGA1UECwwZQXV0aGVudGljYXRvciBBdHRlc3RhdGlvbjEmMCQG A1UEAwwdWXViaWNvIFUyRiBFRSBTZXJpYWwgODAwODQ3MzIwWTATBgcqhkjOPQIB BggqhkjOPQMBBwNCAAQc2Np2EaP17x+IXpULpl2A4zSFU5FYS9R/W3GcUyNcJCHk 45m9tXNngkGQk1dmYUk8kUwuZyTfk5T8+n3qixgEo2wwajAiBgkrBgEEAYLECgIE FTEuMy42LjEuNC4xLjQxNDgyLjEuMTATBgsrBgEEAYLlHAIBAQQEAwIFIDAhBgsr BgEEAYLlHAEBBAQSBBD4oBHzjApNFYAGFxEfntx9MAwGA1UdEwEB/wQCMAAwDQYJ KoZIhvcNAQELBQADggEBAHcYTO91LRoF8wpThdwthvj6wGNxcLAiYqUZXPX+0Db+ AGVODSkVvEVSmj+JXmrBzNQel3FW4AupOgbgrJmmcWWEBZyXSpRQtYcl2LTNU0+I z9WbyHNN1wQJ9ybFwj608xBuoNRC0rG8wgYbMC4usyRadt3dYOVdQi0cfaksVB2V NKnw+ttQUWKoZsPHtuzFx8NlazLQBep1W2T0FCONFEG7x/l+ZcfNhT13azAbaurJ 2J0/ff6H0PXJP6h+Obne4xfz0+8ujftWDUSh9oaiVRYf+tgam/tzOKyEU38V2liV 11zMyHKWrXiK0AfyDgb58ky2HSrn/AgE5MW/oXg/CXc= -----END CERTIFICATE-----’ 署名検証のソースコード解説は、ただのフォーマット解説のため省略。 Jun Kurihara (U-Hyogo/Zettant) Modern Authentication May 25, 2020 53 / 72
FIDO2 WebAuthn ユーザ認証フロー Jun Kurihara (U-Hyogo/Zettant) Modern Authentication May 25, 2020 54 / 72
WebAuthn ユーザ認証フロー 以下のような流れで、RP に登録されたユーザに対し、認証を行う。 OK ! RP で生成した Challenge に対して認証器内部で署名させ、その検 証結果で事前に登録したユーザかどうかを判別・認証する処理。 Jun Kurihara (U-Hyogo/Zettant) Modern Authentication May 25, 2020 55 / 72
登録処理の場合同様、ユーザ認証の各ステップを実際のデータを 確認しながら追っていく。 “Assertion” について ユーザ登録の時、Credential (Key Pair) の「認証器による出生証明」 を “Attestation” と呼んだ。これと同様に FIDO2 WebAuthn では、 ユーザ認証において「認証器による正当性の主張」を “Assertion” と呼ぶ。すなわち、Assertion の検証を行うことで、RP は正当性 の主張を受入れ認証 OK とする。 Jun Kurihara (U-Hyogo/Zettant) Modern Authentication May 25, 2020 56 / 72
WebAuthn ユーザ認証: RP へユーザ認証要求 ⓪, ① Challenge と署名させる Credential の ID を RP から取得。 OK ! 登録同様、WebApp・RP 間のやりとりは規定されておらず、実装 者に任されている。 Jun Kurihara (U-Hyogo/Zettant) Modern Authentication May 25, 2020 57 / 72
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
WebAuthn ユーザ認証: 認証器へ Assertion 生成要求 ②, ③ ブラウザの API を通して認証器へ Assertion を要求。 OK ! PublicKeyCredentialRequestOptions Object をブラウザの window.navigator.credential.get() へ入力。 Jun Kurihara (U-Hyogo/Zettant) Modern Authentication May 25, 2020 59 / 72
②: 認証器に送るオブジェクトの生成 実際に 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
③: 認証器へオブジェクト送付 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
補足: Client-side Discoverable Credential について 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
WebAuthn ユーザ認証: Assertion 生成・取り出し ④, ⑤ 認証器で Challenge へ署名し、Assertion を取得。 OK ! 前ステップの get() の返り値として、署名 (signature) やメタ情報 (authenticatorData) を格納した PublicKeyCredential Object を取得。 Jun Kurihara (U-Hyogo/Zettant) Modern Authentication May 25, 2020 63 / 72
④: ローカルでの生体認証・認証器での Assertion 生成 認証器にタッチすることで生体認証を完了させると、認証器内部 で Assertion = Challenge への署名生成が行われる。 PIN 入力要求 ⇒ 認証要求 Jun Kurihara (U-Hyogo/Zettant) Modern Authentication May 25, 2020 64 / 72
⑤: ブラウザにて 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
WebAuthn ユーザ認証: Assertion の検証 ⑥, ⑦, ⑧ ブラウザが AutehtncatorAssertionResponse を RP へ送っ て、そこで Assertion の検証と認証可否判断を行う。 OK ! Assertion の検証は RP の行うバックエンドの処理なことに注意。 Jun Kurihara (U-Hyogo/Zettant) Modern Authentication May 25, 2020 66 / 72
⑥: ブラウザにて認証器出力をパース、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
⑧: 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
テストコードで模擬する 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
まとめ Jun Kurihara (U-Hyogo/Zettant) Modern Authentication May 25, 2020 70 / 72
この資料では以下を行った。 認証の基礎と、FIDO2 の概要の紹介 FIDO2 WebAuthn の概要の紹介 FIDO2 WebAuthn のユーザ登録・認証についてコードレベルで 動作解説 ただし、今回触ってみたことが WebAuthn の全体像ではないことに 注意。仕様は日々進化しており、またパラメタもここで掲載した もの以外にも多く存在する。あくまで 1 つの例と考えてほしい。 Jun Kurihara (U-Hyogo/Zettant) Modern Authentication May 25, 2020 71 / 72
参考資料: WebAuthn の標準文書・仕様書 Web Authentication (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

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
  • 2.
    はじめに Jun Kurihara (U-Hyogo/Zettant)Modern Authentication May 25, 2020 2 / 72
  • 3.
    はじめに この講義では、 パスワード認証に代わるモダンな認証方式「FIDO」の概要 FIDO の認証を Webブラウザ経由で利用する「FIDO2 WebAuthn」の利用 のさわりを学ぶ。 Jun Kurihara (U-Hyogo/Zettant) Modern Authentication May 25, 2020 3 / 72
  • 4.
    この講義の対象と事前準備 対象: 暗号・セキュリティ技術に興味がある初学者 Web に新しい認証技術を導入したい Web系のエンジニア ※但し、ある程度の公開鍵暗号・電子署名の知識を前提とする1 必須ではないが触って楽しむのには必要な事前準備: Bash/Zsh, Git が使えるようになっていること Node.js, npm, yarn が使えるようになっていること Google Chrome ブラウザが利用可能なこと 1どういうものか、というのを知っていれば十分。「JavaScript を使って学ぶ End-to-End セキュリ ティ」の資料を読んでいることを推奨 (https://github.com/junkurihara/class-e2e_security_js)。 Jun Kurihara (U-Hyogo/Zettant) Modern Authentication May 25, 2020 4 / 72
  • 5.
    パスワード認証からFIDO へ Jun Kurihara(U-Hyogo/Zettant) Modern Authentication May 25, 2020 5 / 72
  • 6.
    認証とは 認証 「何らかの手段」で対象の正当性を確認すること。 メッセージの正当性を確認 ⇒ メッセージ認証 サービス利用ユーザの正当性を確認⇒ ユーザ認証 etc. ※このスライドで単純に「認証」と呼んだときは、認証対象を「正 規ユーザ本人」としたユーザ認証・本人認証を指すこととする。 Jun Kurihara (U-Hyogo/Zettant) Modern Authentication May 25, 2020 6 / 72
  • 7.
    本人認証の 3 つの要素 本人認証において、正当性確認のため検証されるものは大きく3 要素に分類。 知識 ⇒ 本人しか知らない知識を持っていれば OK (ex. パスワード) 所有物 ⇒ 本人しか持っていない物を提示できれば OK (ex. HW キー) 生体 ⇒ 本人の体の一部を提示できれば OK (ex. 指紋) Jun Kurihara (U-Hyogo/Zettant) Modern Authentication May 25, 2020 7 / 72
  • 8.
    オンラインサービスでのパスワード認証 サービスの利用者の識別子 (ID) と対応するパスワードをサー ビス事業者に登録、サービス利用時に利用者が自分のID とパ スワードを入力する。 パスワードは個人の記憶にのみ存在するため、パスワードを 知っている人はそのサービスに登録してる本人と同一人物と 考えることができる。 おそらく、誰にとっても最も馴染み深い認証方式! Jun Kurihara (U-Hyogo/Zettant) Modern Authentication May 25, 2020 8 / 72
  • 9.
    Figure: オンラインでの単純なパスワード認証 Jun Kurihara(U-Hyogo/Zettant) Modern Authentication May 25, 2020 9 / 72
  • 10.
  • 11.
    FIDO FIDO (Fast IDentityOnline) 業界団体 FIDO Alliance4 の策定する、ハードウェアセキュリティ キー+生体認証 5 と公開鍵暗号方式をベースとしたオンラインでの 本人認証技術。 現在は FIDO2 (v2.0) が最新の規格。以降、FIDO2 の内容について 触れていく。 厳密には、FIDO2 はパスワードレス認証をサポートしつつも、パ スワード+デバイス・生体認証の多要素での認証もサポートする。 4 https://fidoalliance.org 5 すなわち、「所有物」と「生体」の二要素を同時に使った認証が可能。 Jun Kurihara (U-Hyogo/Zettant) Modern Authentication May 25, 2020 11 / 72
  • 12.
    FIDO 認証概略 FIDO 認証の特徴: 公開鍵暗号を利用した、オンラインでの認証方式の提供 認証器によるローカルでの本人認証 認証器内部に閉じた署名生成 ⇒秘密鍵・パスワード等の秘密情報は外部に出ない Figure: FIDO 認証概略 Jun Kurihara (U-Hyogo/Zettant) Modern Authentication May 25, 2020 12 / 72
  • 13.
    FIDO2 の要素 FIDO2 は、WebAuthn(Web Authentication)6と、CTAP (Client-to-Authenticator Protocol)7の 2 つの要素で構成される。 WebAuthn: 内部/外部認証器を Call する WebAPI と、WebApp・ サーバ間のデータフローを規定。 CTAP: 外部認証器を Call する API と、クライアント/プラット フォームと認証器の通信プロトコルを規定。 6Spec: https://www.w3.org/TR/webauthn-1/ 7Spec: https://fidoalliance.org/specs/fido2/fido-client-to-authenticator-protocol-v2.1-rd-20191217.html Jun Kurihara (U-Hyogo/Zettant) Modern Authentication May 25, 2020 13 / 72
  • 14.
    図で見ると CTAP・WebAuthn は以下のような役割分担。 JunKurihara (U-Hyogo/Zettant) Modern Authentication May 25, 2020 14 / 72
  • 15.
    FIDO2 CTAP8 USB/BLE/NFC 等で接続されたHW セキュリティキーなどの外部認 証器と、クライアントアプリ (ブラウザ等) およびプラットフォー ム (OS) との間の通信プロトコルを規定。以下の要素で構成。 USB/BLE/NFC など物理層の種別に応じた、通信確立のための プロトコル 認証器での処理を Call する API 外部認証器の情報取得 PIN によるローカルでのユーザ認証 9 認証器組込の秘密鍵での、ユーザ秘密鍵・証明書生成 ユーザ秘密鍵による署名の生成、など ブラウザ・OS(のドライバ) は上記を実装した上で、より上位の WebAuthn のプロトコルをサポート。 8 https: //fidoalliance.org/specs/fido-v2.0-ps-20190130/fido-client-to-authenticator-protocol-v2.0-ps-20190130.html 9 指紋認証やジェスチャーなどは認証器のみで完結するので API は用意されない。署名生成などのときに認証器内での認証を要 求するフラグを立てる。 Jun Kurihara (U-Hyogo/Zettant) Modern Authentication May 25, 2020 15 / 72
  • 16.
    FIDO2 WebAuthn10 Web ブラウザをプラットフォームとし、内部/外部認証器によって 生成される署名を用いた、オンラインサーバでのユーザ認証のプ ロトコルを規定。より具体的には、以下を規定する。 認証器でのユーザの公開鍵証明書の生成、サーバへの登録プ ロトコル 認証器での署名生成、サーバでの認証プロトコル 認証器とやりとりするためブラウザが具備すべきWeb API11 。 大雑把に以下の 2 種類。 ユーザの公開鍵証明書の生成 (Credential Creation) ユーザ秘密鍵による署名の生成 (Assertion Generation) 認証器とのやり取りはブラウザ/プラットフォームがサポート。 ⇒ 基本的に Web App の観点からは、WebAuthn のみを意識する。 10 https://www.w3.org/TR/webauthn-1/ 11 JavaScript で Call される API。ブラウザの内部でさらに認証器の API (CTAP や内部 API) を Call する。 Jun Kurihara (U-Hyogo/Zettant) Modern Authentication May 25, 2020 16 / 72
  • 17.
    補足: FIDO1 FIDO1 (v1.x)は、以下の 2 つの要素で構成されている。 UAF (Universal Authentication Framework): 生体認証機能を持つ FIDO 対応端末 (スマートフォン等) でパスワードレス認証を行う機構。 USB 接続などの外部 HW セキュリティキーは利用できない。 U2F (Universal 2nd Factor)12 : ID・パスワード認証に加えた 2 要素認 証を行うのに、外部 HW セキュリティキーを利用可能とする機構。 FIDO2 は、UAF と U2F を統合し、さらに外部 HW キーを用いてもパス ワードレス認証可能な、より利便性の高い規格と見做せる。 12 U2F は FIDO2 規格では CTAP1 と改称。FIDO2 で追加された仕様は CTAP2 と呼ばれる。 Jun Kurihara (U-Hyogo/Zettant) Modern Authentication May 25, 2020 17 / 72
  • 18.
    FIDO2 対応の認証器 USB/NFC/BLE 等対応の外部認証器(External Authenticator)、端末付 属の認証器 (On-device/Internal Authenticator) 共々、様々な対応デバ イスがリリースされつつある。 Security Key by Yubico FIDO2 専用 13 YubiKey 5Ci FIDO2+OpenPGP+etc... MacbookPro TouchID FIDO2 認証可能 14 13 FIDO2 CTAP1=FIDO1 U2F には対応。 14 ブラウザ等が TouchID API を Call できれば FIDO2 の On-device Authenticator として動作。 Chrome 等は対応済。 Jun Kurihara (U-Hyogo/Zettant) Modern Authentication May 25, 2020 18 / 72
  • 19.
    FIDO2 標準化状況 FIDO は業界団体の策定した規格ではあるが、 FIDO2CTAP: ITU-T で勧告として国際標準化15 FIDO2 WebAuthn: W3C で勧告として国際標準化16 と、認証器とプラットフォーム/ブラウザ間の通信プロトコル、 サーバ・ブラウザ間の認証プロトコルの両者共に国際標準として 策定済。 15https://fidoalliance.org/ fido-alliance-specifications-now-adopted-as-itu-international-standards/ 16https://www.w3.org/2019/03/pressrelease-webauthn-rec.html.ja Jun Kurihara (U-Hyogo/Zettant) Modern Authentication May 25, 2020 19 / 72
  • 20.
    この後、FIDO2 WebAuthn の内容に実際に触れ、最新の認証技術に ついて理解を深めてみよう。17 17今回はWeb 技術から学ぶセキュリティに注力するため、ローレイヤの FIDO2 CTAP については 別の機会で。 Jun Kurihara (U-Hyogo/Zettant) Modern Authentication May 25, 2020 20 / 72
  • 21.
    実験環境の準備 Jun Kurihara (U-Hyogo/Zettant)Modern Authentication May 25, 2020 21 / 72
  • 22.
    準備 説明を聞きつつ手を動かすため、まず環境準備。 今回は以下の 2 つをWebAuthn の API を Call しながら実験して みる。 認証器を使って「ユーザ登録」 ⇒ 認証器からのメッセージを解してみて実際に証明書および 生の公開鍵を取り出してみる。 認証器を使って「ユーザ認証」 ⇒ 署名を解してみて、登録時に取り出した公開鍵で署名が通 ることを確認してみる。 ⇒ この 2 つが FIDO2 WebAuthn のパスワードレス認証の基礎。 Jun Kurihara (U-Hyogo/Zettant) Modern Authentication May 25, 2020 22 / 72
  • 23.
    環境 以下の環境が前提: Node.js LTS (≥12) がインストール済で yarn が使える18 ブラウザとして、Google Chrome (系ブラウザ)、もしくは Firefox がインストール済み Visual Studio Code や WebStorm などの統合開発環境がセット アップ済みだとなお良い 18インストールコマンド: npm i -g yarn Jun Kurihara (U-Hyogo/Zettant) Modern Authentication May 25, 2020 23 / 72
  • 24.
    JavaScript プロジェクトの準備 1 プロジェクトのGitHub リポジトリを Clone $ git clone https://github.com/junkurihara/class-fido2_webauthn.git $ cd sample 2 依存パッケージのインストール $ yarn install 3 ライブラリのビルド $ yarn build Jun Kurihara (U-Hyogo/Zettant) Modern Authentication May 25, 2020 24 / 72
  • 25.
    認証器の準備 実験の前に認証器をセットアップしておく。例えば「Security Key by Yubico」の場合は、「YubiKeyManager」をインストールし、PIN を設定。19 Figure: YubiKey Manager (Mac) 19「PIN+認証器へのタッチ」が生体認証という扱い。PIN 設定はなくても動作するが、タッチだ けで生体認証したことになってしまう。PIN ではなく指紋認証を使うような認証器では、指紋登録 が前もって必要。 Jun Kurihara (U-Hyogo/Zettant) Modern Authentication May 25, 2020 25 / 72
  • 26.
    FIDO2 WebAuthn Jun Kurihara(U-Hyogo/Zettant) Modern Authentication May 25, 2020 26 / 72
  • 27.
    FIDO2 WebAuthn 事始め JunKurihara (U-Hyogo/Zettant) Modern Authentication May 25, 2020 27 / 72
  • 28.
    FIDO2 WebAuthn のフローの参加エンティティ WebAuthnの動作フローでは、以下の 3 つの (抽象化された) 参加エ ンティティが存在。 1 Relying Party (RP): サービス提供者の認証サーバ 2 ブラウザ+RP の WebApp: ユーザおよび認証器とやり取り 3 Authenticator: 内部/外部認証器。以下をセキュアに保持。 Attestation Key Pair: 公開鍵・秘密鍵ペア Attestation Certificate: 上記の公開鍵に対し、FIDO2 で承認さ れた製造元が署名した証明書 Jun Kurihara (U-Hyogo/Zettant) Modern Authentication May 25, 2020 28 / 72
  • 29.
    WebAPI として用意される WebAuthnAPI は、ブラウザ経由で WebApp が認証器とやりとりする役割を担う。 Jun Kurihara (U-Hyogo/Zettant) Modern Authentication May 25, 2020 29 / 72
  • 30.
    FIDO2 WebAuthn の2 つのフロー FIDO2 WebAuthn は、2 つの動作フローを規定する。 ユーザ登録フロー: 認証器を使って、Relying Party にユーザの ID や認証情報=公開鍵20を登録する処理 ユーザ認証フロー: 認証器を使って、Relying Party に事前に認 証情報を登録したユーザ自身であることを証明する処理。 以降、この 2 つのフローの中身を見ていくが、その前に FIDO2 WebAuthn において登録・認証の安全性を担保する Attestation と いう概念について解説しよう。 20Credential Public Key/Certificate のこと Jun Kurihara (U-Hyogo/Zettant) Modern Authentication May 25, 2020 30 / 72
  • 31.
    FIDO2 における Attestation FIDO2では、「Attestation」という重要な概念が存在する。 FIDO2 における Attestation 主として、「新しく生成・登録するユーザの公開鍵が、正しく FIDO2 認定を受けている認証器で生成された公開鍵であることを 保証する機構」という意味。すなわち、出生証明。 Relying Party は、出生証明を確認してユーザを登録。 ⇒ 偽造認証器を摑まされたユーザの登録を弾ける。 ⇒ 認証器に基づく FIDO2 認証の安全性は維持。 ※認証器で生成するユーザの鍵ペアを Credential Key Pair、Attest されたその公開鍵を Attested Credential Public Key と呼ぶ。 Jun Kurihara (U-Hyogo/Zettant) Modern Authentication May 25, 2020 31 / 72
  • 32.
    Attestation の流れ。Attestation は2 段階の証明で成立: ユーザ登録時にユーザ公開鍵 (Credential Public Key) を出生証明して登録 ⇒ Attested Credential Public Key の署名を Attestation Certificate で検証 ⇒ Attestation Certificate を FIDO 認証ベンダの公開鍵21で検証 21ルート証明書 Jun Kurihara (U-Hyogo/Zettant) Modern Authentication May 25, 2020 32 / 72
  • 33.
    補足: Attestation の種類 Basic:ベンダが認証器モデルごとに特有の Attestation Key Pair を埋込む。 同じモデルの認証器では同じ鍵ペアでも良い。 Self: Attestation Private Key = Credential Private Key として、自分の秘密鍵 で署名して自己 Attest する。 AttCA22 : Attestation Certificate を動的に生成する手法。外部に信頼できる第 三者の認証局を設け、認証器が Attestation (Identity) Key Pair を生成して、 認証局へその公開鍵への署名を依頼。 ECDAA23 : 楕円曲線上の匿名認証 (Direct Anonymous Attestation; DAA) を利 用して、認証器の情報を与えることなく出生証明を実現。 None: Attestation なし。 この資料では Basic 前提。 Basic でも HW 構造的に秘密鍵は認証器から取出せない。AttCA では、認 証器の TPM に埋め込まれた鍵を、証明書生成ではなく認証局との暗号通 信用に用いる。 22 Attestation Certificate Authority 23 Elliptic Curve based Direct Anonymous Attestation; アルゴリズム仕様は現状ドラフト。 Jun Kurihara (U-Hyogo/Zettant) Modern Authentication May 25, 2020 33 / 72
  • 34.
  • 35.
    以下のコマンドをとりあえず叩いてみると、ブラウザ (Google Chrome) が立ち上がって認証器の挿入を求められることが確認で きる。 ユーザ登録→ユーザ認証の一連のテストコードを実行 $yarn test // sample ディレクトリで実行 この時に行われている動作を解説する。 Jun Kurihara (U-Hyogo/Zettant) Modern Authentication May 25, 2020 35 / 72
  • 36.
    FIDO2 WebAuthn ユーザ登録フロー JunKurihara (U-Hyogo/Zettant) Modern Authentication May 25, 2020 36 / 72
  • 37.
    WebAuthn ユーザ登録フロー 以下のような流れで WebAuthnの認証のための登録を行う。 OK ! 単純に言うと、認証器で Credential Public Key を生成、その出生 証明を RP で確認・登録という処理。 Jun Kurihara (U-Hyogo/Zettant) Modern Authentication May 25, 2020 37 / 72
  • 38.
  • 39.
    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
  • 46.
    ④-1: ローカルでの生体認証 前ステップの後、認証器ローカルでの生体認証27、および FIDO2 WebAuthnの利用確認が求められる。 認証要求 ⇒ FIDO2 利用意思の確認 27Security Key by Yubico の場合、PIN 入力の後にタッチすること。 Jun Kurihara (U-Hyogo/Zettant) Modern Authentication May 25, 2020 46 / 72
  • 47.
    ④-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
  • 51.
    attestationObject は CBOR30で表現され、以下の要素で構成。 attestationObject31 の構造。($ yarn test の途中結果) [ { "fmt": "packed", ← フォーマット規定。WebAuthn の場合は"packed"で最適化されている。 "attStmt": { /* fmt="packed"のとき、Attestation Certificate と署名のフィールド */ "alg": -7, ← ECDSA with SHA-256 で作られた署名という意味 (COSE) "sig": { "type": "Buffer", "data": "MEUCIBJog73SH9q+gu...", ← "x5c"の証明書で検証可能な署名 (本当はバイナリ) }, "x5c": [ { "type": "Buffer", "data": "MIICvDCCAaSgAwIB...", ← これこそが Attestation Certificate! } ] }, "authData": { /* 署名対象、つまり Credential Public Key のフィールド */ "type": "Buffer", "data": "SZYN5YgOjGh0NBcPZHZg..." ← Credential Public Key とそのメタ情報 (登録する RP の ID など)、 ローカル生体認証の結果など (本当はバイナリ) } } ]’ fmt=“packed” の場合、署名は、clientDataJSON のハッシュ値と、 attestationObject.authData を連結したデータに対して生成。 30Concise Binary Object Representation。バイナリの JSON のようなもの。 31 clientDataJSON と異なり、登録の時のみ生成されるオブジェクト。 Jun Kurihara (U-Hyogo/Zettant) Modern Authentication May 25, 2020 51 / 72
  • 52.
    ⑧: RP による検証・登録 RPは attestationObject と clientDataJSON について以下を検証。 1 RP 自身が要求した Credential 生成なのか? ⇒ clientDataJSON 内部と、RP で保持していたチャレンジの比較 2 RP のサービスで登録すべき Credential 生成なのか? ⇒ clientDataJSON 内部の origin のチェック ⇒ attestationObject.authData に含まれる RP ID のチェック 3 FIDO2 で利用可能な正しい認証器を使った登録か? ⇒ clientDataJSON のハッシュ値と authData について、 attStmt.sig (署名) の正しさを attStmt.x5c (Attestation Certificate) を使って検証 ⇒ ルート証明書により、attStmt.x5c の信頼性を検証 上記のチェックが全部 OK であれば authData (内部の Attested Credential Public Key) を保存、ユーザ登録完了! Jun Kurihara (U-Hyogo/Zettant) Modern Authentication May 25, 2020 52 / 72
  • 53.
    テストコードで模擬する RP のAttestation 検証動作結果を見てみよう。 RP による PublicKeyCredential の検証結果の例 ($ yarn test の途中出力) LOG: ’------ [Verification result on PublicKeyCredential.AuthenticatorAttestationResponse] ------’ LOG: ’> Verification result: true’ ← Attestation の検証成功 (challenge/origin/署名の検証成功) LOG: ’> Attested Credential Public Key: ← 検証が成功した Attested Credential Public Key (毎回変化; これを登録) -----BEGIN PUBLIC KEY----- MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEt11IqJnVr2Wi4nIip57LPhoAejRG TH86zg3S7CUYSFibLqVOQrbQ00ADz9IpYHoKzQCbbHcl3o8Zj7WgHUy1yQ== -----END PUBLIC KEY-----’ LOG: ’> Attestation Certificate: ← 認証器が送ってきた Attestation Certificate (固定) -----BEGIN CERTIFICATE----- MIICvDCCAaSgAwIBAgIEBMX+/DANBgkqhkiG9w0BAQsFADAuMSwwKgYDVQQDEyNZ dWJpY28gVTJGIFJvb3QgQ0EgU2VyaWFsIDQ1NzIwMDYzMTAgFw0xNDA4MDEwMDAw MDBaGA8yMDUwMDkwNDAwMDAwMFowbTELMAkGA1UEBhMCU0UxEjAQBgNVBAoMCVl1 YmljbyBBQjEiMCAGA1UECwwZQXV0aGVudGljYXRvciBBdHRlc3RhdGlvbjEmMCQG A1UEAwwdWXViaWNvIFUyRiBFRSBTZXJpYWwgODAwODQ3MzIwWTATBgcqhkjOPQIB BggqhkjOPQMBBwNCAAQc2Np2EaP17x+IXpULpl2A4zSFU5FYS9R/W3GcUyNcJCHk 45m9tXNngkGQk1dmYUk8kUwuZyTfk5T8+n3qixgEo2wwajAiBgkrBgEEAYLECgIE FTEuMy42LjEuNC4xLjQxNDgyLjEuMTATBgsrBgEEAYLlHAIBAQQEAwIFIDAhBgsr BgEEAYLlHAEBBAQSBBD4oBHzjApNFYAGFxEfntx9MAwGA1UdEwEB/wQCMAAwDQYJ KoZIhvcNAQELBQADggEBAHcYTO91LRoF8wpThdwthvj6wGNxcLAiYqUZXPX+0Db+ AGVODSkVvEVSmj+JXmrBzNQel3FW4AupOgbgrJmmcWWEBZyXSpRQtYcl2LTNU0+I z9WbyHNN1wQJ9ybFwj608xBuoNRC0rG8wgYbMC4usyRadt3dYOVdQi0cfaksVB2V NKnw+ttQUWKoZsPHtuzFx8NlazLQBep1W2T0FCONFEG7x/l+ZcfNhT13azAbaurJ 2J0/ff6H0PXJP6h+Obne4xfz0+8ujftWDUSh9oaiVRYf+tgam/tzOKyEU38V2liV 11zMyHKWrXiK0AfyDgb58ky2HSrn/AgE5MW/oXg/CXc= -----END CERTIFICATE-----’ 署名検証のソースコード解説は、ただのフォーマット解説のため省略。 Jun Kurihara (U-Hyogo/Zettant) Modern Authentication May 25, 2020 53 / 72
  • 54.
    FIDO2 WebAuthn ユーザ認証フロー JunKurihara (U-Hyogo/Zettant) Modern Authentication May 25, 2020 54 / 72
  • 55.
    WebAuthn ユーザ認証フロー 以下のような流れで、RP に登録されたユーザに対し、認証を行う。 OK! RP で生成した Challenge に対して認証器内部で署名させ、その検 証結果で事前に登録したユーザかどうかを判別・認証する処理。 Jun Kurihara (U-Hyogo/Zettant) Modern Authentication May 25, 2020 55 / 72
  • 56.
    登録処理の場合同様、ユーザ認証の各ステップを実際のデータを 確認しながら追っていく。 “Assertion” について ユーザ登録の時、Credential (KeyPair) の「認証器による出生証明」 を “Attestation” と呼んだ。これと同様に FIDO2 WebAuthn では、 ユーザ認証において「認証器による正当性の主張」を “Assertion” と呼ぶ。すなわち、Assertion の検証を行うことで、RP は正当性 の主張を受入れ認証 OK とする。 Jun Kurihara (U-Hyogo/Zettant) Modern Authentication May 25, 2020 56 / 72
  • 57.
    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
  • 70.
    まとめ Jun Kurihara (U-Hyogo/Zettant)Modern Authentication May 25, 2020 70 / 72
  • 71.
    この資料では以下を行った。 認証の基礎と、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