Skip to content

MS_WebAuthnImplementation

nishi_74322014 edited this page Sep 1, 2026 · 1 revision

WebAuthnを実装する。

概要

  • WebAuthnを実装する前に理解を深める。
  • spec レベルは上位項を参照のこと。

詳細

以下に、各種、調査結果をサマリーする(まだまだ理解不足です)。

補足(登録と認証は同じ形をしている): 以降の登録フロー・認証フローは、
どちらも 「(1) challenge を受け取る → (2)(3) ブラウザ API を呼ぶ →
(4)(5)(6) サーバで検証する → (7) 保存/更新する」という同じ骨格になっている。
違いは、登録が公開鍵を受け取って保存する
のに対し、
認証は保存済みの公開鍵で署名を検証する点だけである。

登録フロー

(1) challengeの受信

(2) navigator.credentials.create() の param

# パラメタ 必須 / 任意 説明 フォーマット
1 rp 必須 Relying party に関する情報 JSON Object (下記メンバを持つ)
1-1  ・ id FQDN名 String
1-2  ・ name 任意の RP サイト名 String
2 user 必須 Credential が紐づくユーザー情報 JSON Object (下記メンバを持つ)
2-1  ・ id RP 上のユーザ ID ArrayBuffer
2-2  ・ name RP 上のユーザ ID String
2-3  ・ displayName RP 上のユーザ表示名 String
3 challenge 必須 サーバーで生成した乱数 ArrayBuffer
4 pubKeyCredParams 必須 Credential 情報 JSON Object の配列
4-1  ・ type タイプ(public-key 固定) String
4-2  ・ alg アルゴリズムを表す数値 Int
5 timeout 任意 ユーザーの入力待機時間 Int
6 attestation 任意 Authenticator 自体の検証 JSON Object (AttestationConveyancePreference)
7 authenticatorSelection 任意 認証器への要求事項 JSON Object (AuthenticatorSelectionCriteria)
8 excludeCredentials 任意 JSON Object (PublicKeyCredentialDescriptor)

移行メモ(表の体裁): 元ページの表は PukiWiki の
セル結合(|>||~|)を使った階層表現だったが、
GitHub の Markdown はセル結合に対応していないため、
# の採番と  ・ のインデントで階層を表し、
縦方向の結合は に置き換えた(以降の表も同様)。

補足(user.id は個人情報を入れない): 表の 2-1 user.id
認証器の中に保存され、そのまま返ってくる値である。
メール アドレスなど推測・特定が可能な値を入れてはならず、
ランダムなバイト列(内部 ID)を使う、というのが仕様上の要求である。
表で 2-2 name の説明が 2-1 id と同じ「RP 上のユーザ ID」に
なっているのは元ページのままだが、
実際には name表示・識別用の文字列(ログイン名など)である。

(3) navigator.credentials.create() の return

# パラメタ 説明 フォーマット
1 id 割り当てられた id rawId の文字列表現
2 rawId id の ArrayBuffer 版 ArrayBuffer
3 ・ response AuthenticatorAttestationResponse JSON Object (AuthenticatorAttestationResponse)
3-1  ・ attestationObject 公開鍵などを含む CBOR 形式
3-1-1   ・ fmt Attestation format "fmt": "packed"
3-1-2   ・ authData Raw buffer struct containing user info "authData": "{rpIdHash: "..." ,... }"
3-1-2-1    ・ rpIdHash
3-1-2-2    ・ flags
3-1-2-3    ・ flagsBuf
3-1-2-4    ・ counter
3-1-2-5    ・ counterBuf
3-1-2-6    ・ aaguid
3-1-2-7    ・ credID
3-1-2-8    ・ credIDLen
3-1-2-9    ・ credIDLenBuf
3-1-2-10    ・ COSEPublicKey
3-1-3   ・ attStmt Attestation statement data "attStmt": {sig: "", x5c: ""}
3-1-3-1    ・ sig Signature "sig": "..."
3-1-3-2    ・ x5c X.509 Certificate Chain "x5c": ["..."]
3-2  ・ clientDataJSON クライアント・データ CBOR 形式
3-2-1   ・ challenge Random number "challenge": "..."
3-2-2   ・ origin Origin of the website "origin": "http(s)://..."
3-2-3   ・ type Type of the call "type": "webauthn.create"
4 type pubKeyCredParams - type と同じ "type": "public-key"

移行メモ(正誤): clientDataJSON のフォーマットが
CBOR 形式」となっていたが、名前のとおり
UTF-8 の JSON をそのまま入れた ArrayBuffer である
(CBOR なのは同じ階層の attestationObject のほう)。
後述の認証フローの表では ArrayBuffer と書かれており、そちらが正しい。

(4) challenge、origin、typeの検証

(5) flagsの検証

補足(UP と UV の違い): UP は「人がそこにいて操作した」ことの確認
(タッチしただけでも立つ)で、UV は「その人が本人である」ことの確認
(PIN や生体認証を通った)である。
パスワードレス(1 要素で完結)にしたい場合は UV が必須、
2 要素目としてのみ使う場合は UP だけでよい、という使い分けになる。

(6) signatureの検証

(7) 公開鍵の保存

認証フロー

(1) 認証時の challengeの受信

(2) navigator.credentials.get() の param

# パラメタ 必須 / 任意 説明 フォーマット
1 challenge 必須 サーバーで生成した乱数 ArrayBuffer
2 timeout 任意 ユーザーの入力待機時間 Int
3 rpId 任意 rpId の指定(登録時と同じ値を指定) String
4 allowCredentials 任意 ユーザに紐づく Credential のリスト Array (PublicKeyCredentialDescriptor)
5 userVerification 任意 ユーザ検証に関する要件 String (enum UserVerificationRequirement)

(3) navigator.credentials.get() の return

# パラメタ 説明 フォーマット
1 id 割り当てられた id rawId の文字列表現
2 rawId id の ArrayBuffer 版 ArrayBuffer
3 response assertion data JSON Object (AuthenticatorAssertionResponse)
3-1  ・ authenticatorData rpIdHash, flagsBuf, flags, counter, counterBuf ArrayBuffer
3-2  ・ clientDataJSON クライアント・データ ArrayBuffer
3-2-1   ・ challenge Random number "challenge": "..."
3-2-2   ・ origin Origin of the website "origin": "http(s)://..."
3-2-3   ・ type Type of the call "type": "webauthn.get"
3-3  ・ signature 署名の値 ArrayBuffer
3-4  ・ userHandle 認証器が返す値 ArrayBuffer
4 type タイプ(public-key 固定) String
5 getClientExtensionResults extensions results struct

移行メモ(正誤): 上表の type の例が
登録フローと同じ "webauthn.create" になっていたが、
認証(navigator.credentials.get())では "webauthn.get" である。
直後の「(4) challenge、origin、type の検証」でも
同じ写し誤りがあるが、そちらは元ページの記述を残した。

(4) 認証時の challenge、origin、typeの検証

  • fido2-net-lib ... サーバー側で処理

  • techblogyahoo
    clientDataJSON の...

    • challenge
      param.challenge = return.clientDataJSON.challenge みたいな話。
    • origin
      xxxx = return.clientDataJSON.origin みたいな話。
    • type
      "webauthn.create" = return.clientDataJSON.type みたいな話。
      (前掲のとおり、認証時は "webauthn.get" と比較する)

(5) 認証時の flagsの検証

  • fido2-net-lib ... サーバー側で処理
  • techblogyahoo
    authenticatorData.flags
    • UP : User Presence
      ユーザーの存在確認(必須)
    • UV : User Verification
      ユーザーの認証(任意)

(6) 認証時の signatureの検証

実装例

提案されたI/F

FIDO2 サーバ標準は存在しないが、

  • FIDO2 適合テストツールで使用する提案された REST API の I/F は存在する。

  • この I/F は必須で無いが、Server が標準の方法で Message を送受信することで
    適合テストツールによって使用され、機能が自動的に検証されるようにできる。

  • 問題点

    • 登録フローには、認証が必要だと思うのだケド、
      認証実装したらテストツールも通らないんじゃないか?と。

    • 以下のサーバ実装パターン毎、実際の実装は変わってきそう。

      RP & BaaSが実装」に書いたように、
      Resource Server として動作する
      BaaS 上に実装する方式に適合しそう。

  • 参考

Credential Creation Options

Authenticator Attestation

Credential Get Options

Authenticator Assertion

サーバ実装パターン

OIDC の STS/IdP(OP)、Client(RP) のどちらでも
WebAuthn の Relying Party(RP) になれる。

IdP/Stsが実装

  • IdP/Sts に集約可能で楽。

  • 提案された I/Fの実装

    • 登録フロー
      認証アクセスが必要だが、サイト内なので WebAPI よりポストバックがイイ
    • 認証フロー
      認証後に画面遷移が必要なので WebAPI よりポストバックがイイ

RP & BaaSが実装

  • 折衷案

    • RP が WebAuthn を操作し、
    • バックエンドの IDaaS -> BaaS を使用して公開鍵を管理する。
  • 提案された I/Fの実装

    • 登録フロー
      RP は、IdP/Sts と連携し、
      Resource Server として機能する BaaS に公開鍵を登録。
    • 認証フロー
      BaaS に登録した公開鍵を取得するために、
      Client 認証のみのグラント種別を使用し RP の認証をする。

RPが実装

補足(rpId の制約が実装パターンを縛る): WebAuthn の鍵は
rpId(ドメイン)に紐づくため、
登録したドメインと異なるドメインからは使えない。
上記の 3 パターンが分かれるのは、
「どのドメインで navigator.credentials.* を呼ぶか」と
「公開鍵をどこに置くか」を分離できるかどうかの違いによる。

実現できるUX

2FAのUserExperience

2FAのUserExperience

PasswordlessのUserExperience

PasswordlessのUserExperience

参考

fido2-net-lib

fido2-net-lib

techblogyahoo

登録フロー(スライド)

登録フロー

認証フロー(スライド)

認証フロー

パラメタ

Web Authentication API のメソッド

gist.github.com/daisukenishino2

https://gist.github.com/daisukenishino2/f09fb400fa2186aead4b6f8cad59ab38#gistcomment-2852202

Ackermann Yuriy – Medium

Mercari Engineering Blog

enjoy struggling

Qiita(実装例)

ritou

r-weblife

Qiita(実装パターン)

本 Wiki 内


Tags: IT国際標準, 認証基盤

NetDevInfraWiki

マイクロソフト系技術情報 Wiki
Open 棟梁 Wiki

(未着手)

開発基盤部会 Wiki

移行管理: DONETODO

Clone this wiki locally