使用 Signal API 讓密碼金鑰與伺服器上的憑證保持一致

發布日期:2024 年 11 月 12 日,上次更新日期:2024 年 11 月 29 日

WebAuthn Signal API 可讓信賴方傳送現有憑證信號給已連結的密碼金鑰提供者。支援密碼金鑰的提供者就能更新或移除儲存空間中不正確或已撤銷的密碼金鑰,不再提供給使用者。

相容性

Chrome 在所有電腦平台和 Android 上都支援 Signal API。

Safari 支援,但尚未實作。Firefox 尚未分享意見

Google 密碼管理工具可以更新密碼金鑰,以反映信號。電腦上的 Chrome 擴充功能密碼金鑰供應商會決定是否反映信號。

背景

建立密碼金鑰 (可探索的憑證) 時,系統會將使用者名稱和顯示名稱等中繼資料,連同私密金鑰一併儲存至密碼金鑰供應商 (例如密碼管理工具),而公開金鑰憑證則會儲存至信賴方 (RP) 的伺服器。儲存使用者名稱和顯示名稱,有助於使用者在系統提示時,識別要用於登入的密碼金鑰。如果使用者有多個密碼金鑰,且來自不同密碼金鑰供應商,這項功能就特別實用。

不過,在某些情況下,密碼金鑰供應商的密碼金鑰清單與伺服器的憑證清單不一致,可能會造成混淆。

第一種情況是使用者刪除伺服器上的憑證。這樣一來,密碼金鑰供應商就不會受到影響。下次使用者嘗試以密碼金鑰登入時,密碼金鑰提供者仍會向使用者顯示該密碼金鑰。不過,由於伺服器無法驗證已刪除的公開金鑰,因此登入嘗試會失敗。

第二種情況是使用者在伺服器上更新使用者名稱或顯示名稱。下次使用者嘗試登入時,即使伺服器已更新,密碼金鑰供應商的密碼金鑰仍會顯示舊的使用者名稱和顯示名稱。理想情況下,這些資料會同步處理。

信號 API

Signal API 是 WebAuthn API,可讓信賴方將變更信號傳送給密碼金鑰提供者,解決這些不一致的問題。有三種方法:

表示憑證不存在的信號

const credential = await navigator.credentials.get({ ... });
const payload = credential.toJSON();

const result = await fetch('/login', { ... });

// Detect authentication failure due to lack of the credential
if (result.status === 404) {
  // Feature detection
  if (PublicKeyCredential.signalUnknownCredential) {
    await PublicKeyCredential.signalUnknownCredential({
      rpId: "example.com",
      credentialId: "vI0qOggiE3OT01ZRWBYz5l4MEgU0c7PmAA" // base64url encoded credential ID
    });
  } else {
    // Encourage the user to delete the passkey from the password manager nevertheless.
    ...
  }
}

RP 可以使用 RP ID 和憑證 ID 呼叫 PublicKeyCredential.signalUnknownCredential(),通知密碼金鑰提供者指定的憑證已移除或不存在。密碼金鑰提供者會決定如何處理這項信號,但應移除相關聯的密碼金鑰,以免使用者嘗試以沒有相關聯憑證的密碼金鑰登入。

Browser Support

  • Chrome: 132.
  • Edge: 132.
  • Firefox: not supported.
  • Safari: 26.

Source

當系統因缺少憑證而無法透過密碼金鑰登入時,即可叫用這個 API。 這樣一來,RP 就能防止使用者嘗試以沒有相關聯憑證的密碼金鑰登入。與 signalAllAcceptedCredentials 不同,這個方法不需要傳遞整個憑證 ID 清單,因此只要使用者未通過驗證,請一律使用這個方法,以免洩漏特定使用者的密碼金鑰數量。

從 Chrome 上的 Google 密碼管理工具刪除密碼金鑰時顯示的對話方塊。
從 Chrome 的 Google 密碼管理工具刪除密碼金鑰時,系統會顯示對話方塊。

發出已儲存憑證清單的信號

// After a user deletes a passkey or a user is signed in.

// Feature detection
if (PublicKeyCredential.signalAllAcceptedCredentials) {
  await PublicKeyCredential.signalAllAcceptedCredentials({
    rpId: "example.com",
    userId: "M2YPl-KGnA8", // base64url encoded user ID
    allAcceptedCredentialIds: [ // A list of base64url encoded credential IDs
      "vI0qOggiE3OT01ZRWBYz5l4MEgU0c7PmAA",
      ...
    ]
  });
}

使用者登入或管理帳戶設定後,請使用 PublicKeyCredential.signalAllAcceptedCredentials()。您提供該使用者的所有有效憑證 ID 清單。密碼金鑰供應商會將這份清單與該憑證方的本機儲存空間進行比較。如果密碼金鑰提供者在儲存空間中找到不在 allAcceptedCredentialIds 清單中的密碼金鑰,就會將其標示為「隱藏」。系統不會再提供這些隱藏的密碼金鑰用於登入或自動填入,但不會立即永久刪除,因此如有需要,可以還原。 反之,密碼金鑰供應商會還原 allAcceptedCredentialIds 中標示為「隱藏」的密碼金鑰。 這樣一來,網站就能還原因錯誤而隱藏的密碼金鑰。

Browser Support

  • Chrome: 132.
  • Edge: 132.
  • Firefox: not supported.
  • Safari: 26.

Source

使用者在 RP 上刪除密碼金鑰時,以及每次登入時,請呼叫這個 API,讓密碼金鑰提供者維持密碼金鑰清單的同步狀態。

Signal 更新了使用者名稱和顯示名稱

// After a user updated their username and/or display name
// or a user is signed in.

// Feature detection
if (PublicKeyCredential.signalCurrentUserDetails) {
  await PublicKeyCredential.signalCurrentUserDetails({
    rpId: "example.com",
    userId: "M2YPl-KGnA8", // base64url encoded user ID
    name: "a.new.email.address@example.com", // username
    displayName: "J. Doe"
  });
} else {
}

RP 可以透過 RP ID、使用者 ID、使用者名稱和顯示名稱呼叫 PublicKeyCredential.signalCurrentUserDetails(),將更新的使用者資訊告知密碼金鑰供應商。密碼金鑰供應商會決定如何處理這項信號,但應使用新的使用者資訊更新使用者擁有的密碼金鑰。

Browser Support

  • Chrome: 132.
  • Edge: 132.
  • Firefox: not supported.
  • Safari: 26.

Source

使用者更新使用者名稱或顯示名稱時,以及每次登入時,都可以呼叫這個 API,讓密碼金鑰供應商與伺服器保持資訊同步。

在 Chrome 的 Google 密碼管理工具中更新密碼金鑰中繼資料時,系統會顯示這個對話方塊。
在 Chrome 上的 Google 密碼管理工具中更新密碼金鑰中繼資料時,系統會顯示對話方塊。

摘要

Signal API 可協助您消除非預期的登入失敗問題,打造更優質的密碼金鑰體驗。信賴方可透過 Signal API 傳送現有憑證清單及其相關中繼資料,讓密碼金鑰提供者保持密碼金鑰同步。

如要進一步瞭解密碼金鑰,請參閱「使用密碼金鑰登入帳戶,不必輸入密碼」。