使用 Signal API 确保通行密钥与服务器上的凭据保持一致

发布时间:2024 年 11 月 12 日;上次更新时间:2024 年 11 月 29 日

WebAuthn Signal API 允许信赖方向已连接的通行密钥提供方传递与现有凭据相关的信号。借助此功能,提供支持的通行密钥提供方可以更新或移除其存储空间中错误或已撤消的通行密钥,从而不再向用户提供此类通行密钥。

兼容性

从 Chrome 132 开始,桌面版 Chrome 支持 Signal API。Google 密码管理工具可以更新通行密钥,以反映该信号。对于基于 Chrome 扩展程序的通行密钥提供方,是否反映该信号取决于它们。

稍后将支持在 Android 设备上运行的 Chrome 中使用。

Safari 支持,但尚未实现。Firefox 尚未分享其观点

背景

创建通行密钥(可发现的凭据)时,用户名和显示名称等元数据会与私钥一起保存到通行密钥提供方(例如密码管理器),而公钥凭据会保存到信赖方 (RP) 的服务器。保存用户名和显示名有助于用户在系统提示时识别要使用哪个提供的通行密钥进行登录。如果用户拥有来自不同通行密钥提供商的两把以上的通行密钥,此功能尤为有用。

不过,在以下两种情况下,通行密钥提供方的通行密钥列表与服务器的凭据列表之间的不一致可能会导致混淆。

第一种情况是,用户在服务器上删除凭据,但通行密钥提供方中的通行密钥保持不变。用户下次尝试使用通行密钥登录时,通行密钥提供方仍会向用户显示该通行密钥。不过,登录尝试会失败,因为服务器无法使用已删除的公钥进行验证。

第二种情况是用户更新了服务器上的用户名或显示名称。用户下次尝试登录时,即使密钥提供方中的密钥已在服务器上更新,但仍会继续显示旧的用户名和显示名。理想情况下,它们应该保持同步。

Signal API

Signal API 是一种 WebAuthn API,它允许 RP 向通行密钥提供方传递更改信号,从而解决这些困惑。有三种方法:

表明凭据不存在的信号

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 ID 和凭据 ID 调用 PublicKeyCredential.signalUnknownCredential(),RP 可以告知通行密钥提供方指定的凭据已被移除或不存在。通行密钥提供方可以自行决定如何处理此信号,但相关通行密钥应被移除,这样用户就无法使用通行密钥登录,因为相关联的凭据不存在。

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",
      ...
    ]
  });
}

通过使用 RP ID、用户 ID 和存储的凭据的凭据 ID 列表调用 PublicKeyCredential.signalAllAcceptedCredentials(),RP 可以将其存储空间中剩余的凭据告知通行密钥提供方。通行密钥提供方可以自行决定如何处理此信号,但与此列表不匹配的通行密钥预计会被移除,这样用户在登录时就不会看到关联凭据不存在的通行密钥。

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 ID、用户 ID、用户名和显示名称调用 PublicKeyCredential.signalCurrentUserDetails(),RP 可以将更新后的用户信息告知通行密钥提供方。通行密钥提供方可以自行决定如何处理此信号,但用户拥有的通行密钥应使用新的用户信息进行更新。

Browser Support

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

Source

此 API 可在用户更新用户名或显示名时以及每次登录时调用,以便通行密钥提供方能够使此信息与服务器保持同步。

当 Chrome 中的 Google 密码管理工具更新通行密钥元数据时显示的对话框。
在 Chrome 上,当 Google 密码管理工具中的通行密钥元数据更新时显示的对话框。

摘要

Signal API 可帮助您打造更好的通行密钥体验,避免意外登录失败。借助 Signal API,信赖方可以传递现有凭据及其元数据的列表,以便让通行密钥提供方上的通行密钥保持同步。

如需详细了解通行密钥,请先参阅使用通行密钥进行无密码登录