Chrome 推出 WebAuthn 的提示、相關來源要求和 JSON 序列化功能

Chrome 128 和 129 為 WebAuthn 導入了令人興奮的新功能,這是用來建構以密碼金鑰為基礎的驗證系統的基礎 API。

  • 提示:提示可讓依賴方 (RP) 進一步控管瀏覽器的 WebAuthn UI。這對於想使用安全金鑰的企業使用者來說特別實用。
  • 相關來源要求:透過相關來源要求,RP 可讓密碼金鑰在多個網域中有效。如果您擁有多個網站,現在可以讓使用者在各個網站重複使用密碼金鑰,消除登入時的摩擦感。
  • JSON 序列化:透過 JSON 序列化 API,您可以編碼及解碼選項和憑證,並將這些項目傳遞至 WebAuthn API 和從中取得。

提示

有了 hints,依賴方 (RP) 現在可以指定 UI 偏好設定,用於建立密碼金鑰或透過密碼金鑰驗證。

過去,RP 要限制使用者可以用來建立密碼金鑰或進行驗證的驗證器時,可以使用 authenticatorSelection.authenticatorAttachment 指定 "platform""cross-platform"。他們會分別將驗證器限制為平台驗證器漫遊驗證器。有了 hints,這項規格就能更具彈性。

RP 可在 PublicKeyCredentialCreationOptionsPublicKeyCredentialRequestOptions 中使用選用的 hints,在陣列中依偏好順序指定 "security-key""client-device""hybrid"

以下是憑證建立要求範例,會以 "security-key" 做為提示,優先使用 "cross-platform" 驗證器。這會指示 Chrome 向企業使用者顯示以安全金鑰為重點的 UI。

const credential = await navigator.credentials.create({
  publicKey: {
    challenge: *****,
    hints: ['security-key'],
    authenticatorSelection: {
      authenticatorAttachment: 'cross-platform'
    }
  }
});
指定「security-key」做為提示,瀏覽器就會顯示以安全金鑰為焦點的對話方塊。
指定「security-key」做為提示,瀏覽器就會顯示以安全金鑰為焦點的對話方塊。

如果 RP 想要優先處理跨裝置驗證情境,可以傳送驗證要求,以便優先使用 "cross-platform" 驗證器,並以 "hybrid" 做為提示。

const credential = await navigator.credentials.create({
  publicKey: {
    challenge: *****,
    residentKey: true,
    hints: ['hybrid']
    authenticatorSelection: {
      authenticatorAttachment: 'cross-platform'
    }
  }
});
指定「hybrid」做為提示後,瀏覽器會顯示以跨裝置登入為主軸的對話方塊。
指定「hybrid」做為提示,瀏覽器就會顯示跨裝置登入專注對話方塊。

透過相關來源要求,RP 可讓密碼金鑰可從多個網域使用。對於大多數網站,建立集中式登入體驗並使用聯合通訊協定,仍是建議的解決方案。但是,如果您擁有多個網域且無法建立聯盟,相關來源或許是可行的解決方案。

所有 WebAuthn 要求都必須指定依賴方 ID (RP ID),且所有密碼金鑰都會與單一 RP ID 建立關聯。傳統上,來源只能根據其網域指定 RP ID,因此在這種情況下,www.example.co.uk 可以指定 example.co.uk 的 RP ID,但不能指定 example.com。透過相關來源要求,您可以從目標網域擷取位於 /.well-known/webauthn 的知名 JSON 檔案,藉此驗證已聲明擁有權的 RP ID。因此,如果 example.com 以以下格式指定 RP ID,example.co.uk (以及 example.inexample.de 等) 都會使用 example.com 的 RP ID:

網址:https://example.com/.well-known/webauthn

{
  "origins": [
    "https://example.co.uk",
    "https://example.de",
    "https://example.sg",
    "https://example.net",
    "https://exampledelivery.com",
    "https://exampledelivery.co.uk",
    "https://exampledelivery.de",
    "https://exampledelivery.sg",
    "https://myexamplerewards.com",
    "https://examplecars.com"
  ]
}

如要瞭解如何設定相關來源要求,請參閱「允許在多個網站上使用相關來源要求的密碼金鑰重複使用」。

JSON 序列化

WebAuthn 要求和回應物件包含多個欄位,這些欄位會在 ArrayBuffer 中包含原始二進位資料,例如憑證 ID、使用者 ID 或挑戰。如果網站想要使用 JSON 與伺服器交換這類資料,則必須先對二進位資料進行編碼,例如使用 Base64URL。這會為想在網站上開始使用密碼金鑰的開發人員帶來不必要的複雜性。

WebAuthn 現在提供 API,可直接從 JSON 剖析 PublicKeyCredentialCreationOptionsPublicKeyCredentialRequestOptions WebAuthn 要求物件,並將 PublicKeyCredential 回應直接序列化為 JSON。所有攜帶原始二進位資料的 ArrayBuffer 值欄位,都會自動從或轉換為 Base64URL 編碼值。這些 API 可在 Chrome 129 以上版本使用。

建立密碼金鑰前,請先從伺服器擷取 JSON 編碼的 PublicKeyCredentialCreationOptions 物件,然後使用 PublicKeyCredential.parseCreationOptionsFromJSON() 解碼。

瀏覽器支援

  • Chrome:129。
  • Edge:129。
  • Firefox:119。
  • Safari:不支援。

資料來源

export async function registerCredential() {

  // Fetch encoded `PublicKeyCredentialCreationOptions`
  // and JSON decode it.
  const options = await fetch('/auth/registerRequest').json();

  // Decode `PublicKeyCredentialCreationOptions` JSON object
  const decodedOptions = PublicKeyCredential.parseCreationOptionsFromJSON(options);  

  // Invoke the WebAuthn create() function.
  const cred = await navigator.credentials.create({
    publicKey: decodedOptions,
  });
  ...

建立密碼金鑰後,請使用 toJSON() 對產生的憑證進行編碼,以便傳送至伺服器。

瀏覽器支援

  • Chrome:129。
  • Edge:129。
  • Firefox:119。
  • Safari:不支援。

資料來源

  ...
  const cred = await navigator.credentials.create({
    publicKey: options,
  });

  // Encode the credential to JSON and stringify
  const credential = JSON.stringify(cred.toJSON());

  // Send the encoded credential to the server
  await fetch('/auth/registerResponse', credential);
  ...

使用密碼金鑰進行驗證之前,請從伺服器擷取 JSON 編碼的 PublicKeyRequestCreationOptions,並使用 PublicKeyCredential.parseRequestOptionsFromJSON() 進行解碼。

瀏覽器支援

  • Chrome:129。
  • Edge:129。
  • Firefox:119。
  • Safari:不支援。

資料來源

export async function authenticate() {

  // Fetch encoded `PublicKeyCredentialRequestOptions`
  // and JSON decode it.
  const options = await fetch('/auth/signinRequest').json();

  // Decode `PublicKeyCredentialRequestOptions` JSON object
  const decodedOptions = PublicKeyCredential.parseRequestOptionsFromJSON(options);

  // Invoke the WebAuthn get() function.
  const cred = await navigator.credentials.get({
    publicKey: options
  });
  ...

使用密碼金鑰驗證後,請使用 toJSON() 方法對產生的憑證進行編碼,以便傳送至伺服器。

瀏覽器支援

  • Chrome:129。
  • Edge:129。
  • Firefox:119。
  • Safari:不支援。

資料來源

  ...
  const cred = await navigator.credentials.get({
    publicKey: options
  });

  // Encode the credential to JSON and stringify
  const credential = JSON.stringify(cred.toJSON());

  // Send the encoded credential to the server
  await fetch(`/auth/signinResponse`, credential);
  ...

瞭解詳情

如要進一步瞭解 WebAuthn 和密碼金鑰,請參閱下列資源: