隆重推出适用于 Chrome 中的 WebAuthn 的提示、相关源请求和 JSON 序列化

Chrome 128 和 129 为 WebAuthn(用于构建基于通行密钥的身份验证系统的基础 API)引入了令人兴奋的新功能。

  • 提示:提示可让信赖方 (RP) 更好地控制浏览器中的 WebAuthn 界面。这对于想要使用安全密钥的企业用户来说尤为有用。
  • 相关源请求:通过相关源请求,RP 可以使通行密钥在多个网域上有效。如果您拥有多个网站,现在可以允许用户跨网站重复使用通行密钥,从而消除登录障碍。
  • JSON 序列化:借助 JSON 序列化 API,您可以通过对传递给 WebAuthn API 和从中传递的选项和凭据进行编码和解码,简化 RP 的前端代码。

提示

借助 hints,依赖方 (RP) 现在可以指定用于创建通行密钥或使用通行密钥进行身份验证的界面偏好设置。

以前,当 RP 想要限制用户可以用来创建通行密钥或进行身份验证的身份验证器时,可以使用 authenticatorSelection.authenticatorAttachment 指定 "platform""cross-platform"。它们分别将身份验证器限制为平台内置的身份验证器漫游身份验证器。借助 hints,此规范可以更加灵活。

RP 可以在 PublicKeyCredentialCreationOptionsPublicKeyCredentialRequestOptions 中使用可选的 hints,以便在数组中按优先顺序指定 "security-key""client-device""hybrid"

以下是凭据创建请求示例,该请求会优先使用 "cross-platform" 身份验证器,并将 "security-key" 用作提示。这会指示 Chrome 为企业用户显示以安全密钥为中心的界面。

const credential = await navigator.credentials.create({
  publicKey: {
    challenge: *****,
    hints: ['security-key'],
    authenticatorSelection: {
      authenticatorAttachment: 'cross-platform'
    }
  }
});
通过将“security-key”指定为提示,浏览器会显示一个聚焦于安全密钥的对话框。
通过将“security-key”指定为提示,浏览器会显示一个聚焦于安全密钥的对话框。

如果 RP 希望优先处理跨设备验证场景,则可以发送一个身份验证请求,以 "hybrid" 作为提示,优先使用 "cross-platform" 身份验证器。

const credential = await navigator.credentials.create({
  publicKey: {
    challenge: *****,
    residentKey: true,
    hints: ['hybrid']
    authenticatorSelection: {
      authenticatorAttachment: 'cross-platform'
    }
  }
});
通过指定“混合”作为提示,浏览器会显示一个以跨设备登录为重点的对话框。
通过将“混合”指定为提示,浏览器会显示一个以跨设备登录为重点的对话框。

借助相关来源请求,RP 可以使通行密钥可在多个网域中使用。对于大多数网站,我们仍然建议构建集中式登录体验并使用联合协议。不过,如果您拥有多个网域且无法进行联合,则相关来源可能是一个解决方案。

所有 WebAuthn 请求都必须指定依赖方 ID (RP ID),并且所有通行密钥都与单个 RP ID 相关联。传统上,来源只能根据其网域指定 RP ID,因此在这种情况下,www.example.co.uk 可以指定 RP ID 为 example.co.uk,但不能指定为 example.com。借助相关来源请求,您可以通过从目标网域提取位于 /.well-known/webauthn 的众所周知的 JSON 文件来验证声明的 RP ID。因此,如果 example.com 以以下格式指定它们,example.co.uk(以及 example.inexample.de 等)都可以使用 example.com 的 RP ID:

URL: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 与其服务器交换此类数据,则必须先对二进制数据进行编码,例如使用 Base64网址。对于想要开始在网站上使用通行密钥的开发者,这会增加不必要的复杂性。

WebAuthn 现在提供了一些 API,可直接从 JSON 解析 PublicKeyCredentialCreationOptionsPublicKeyCredentialRequestOptions WebAuthn 请求对象,并将 PublicKeyCredential 响应直接序列化为 JSON。所有携带原始二进制数据的 ArrayBuffer 值字段都会自动转换为或从其 Base64网址 编码值转换。这些 API 从 Chrome 129 开始提供。

在创建通行密钥之前,请从服务器提取 JSON 编码的 PublicKeyCredentialCreationOptions 对象,并使用 PublicKeyCredential.parseCreationOptionsFromJSON() 对其进行解码。

浏览器支持

  • Chrome:129.
  • 边缘: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.
  • 边缘: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 和通行密钥,请查看以下资源: