证明和断言
WebAuthn 中用于注册和身份验证的证书有两种不同的类型。它们名称和用途相似,但理解其中的差异可能是最初的困惑点。以下部分描述了在注册期间发生的证明和在身份验证期间发生的断言。
证明
当身份验证器向服务注册新的密钥对时,身份验证器会使用证明证书对公钥进行签名。证明证书在制造时内置于身份验证器中,并且特定于设备型号。也就是说,在特定时间或特定生产批次制造的所有“Samsung Galaxy S8”手机都具有相同的证明证书。
证明通过 WebAuthn API 作为 AuthenticatorAttestationResponse 返回。证明格式包含两个基本的 ArrayBuffer
对象
- clientDataJSON - 一个包含浏览器在被要求进行身份验证时所看到内容的 JSON 表示形式的 ArrayBuffer。
- attestationObject - 新生成的密钥对由该身份验证器创建的加密证明。这包含
- 身份验证器数据 包含一个
attestedCredentialData
字段,该字段依次包含credentialId
和credentialPublicKey
。attestedCredentialData
是证明中使用的可选字段。在 AuthenticatorAssertionResponse 中使用时不包含它。 - 证明语句,它根据依赖方是否请求证明而可选存在。通常,不鼓励依赖方请求证明,因此该语句更有可能不存在。
- 身份验证器数据 包含一个
不同的设备具有不同的证明格式。WebAuthn 中 预定义的证明格式 为
- Packed - 一种通用的证明格式,通常由其唯一功能是作为 WebAuthn 身份验证器的设备(例如安全密钥)使用。
- TPM - 可信平台模块 (TPM) 是一组来自可信平台组 (TPG) 的规范。这种证明格式通常存在于台式计算机中,并且 Windows Hello 使用它作为其首选证明格式。
- Android 密钥证明 - Android O 中添加的功能之一是 Android 密钥证明,它使 Android 操作系统能够证明密钥。
- Android SafetyNet - 在 Android 密钥证明之前,Android 设备的唯一选择是创建 Android SafetyNet 证明。
- FIDO U2F - 实现 FIDO U2F 标准的安全密钥使用此格式。
- none - 如果
navigator.credentials.create()
中的attestation
参数设置为none
,则浏览器可能会提示用户是否允许站点查看其证明数据和/或可能会从身份验证器的响应中删除证明数据。
证明的目的是以加密方式证明新生成的密钥对来自特定设备。这为新生成的密钥对提供了信任根,并且能够识别正在使用的设备的属性(私钥是如何保护的;是否/使用哪种生物识别方法;设备是否已获得认证;等等)。需要注意的是,虽然证明提供了信任根的功能,但验证信任根通常不是必需的。注册新帐户的身份验证器时,通常适用“首次使用信任”(TOFU)模型;而将身份验证器添加到现有帐户时,用户已通过身份验证并已建立安全会话。
断言
当用户选择登录服务时,服务器会发送一个挑战,身份验证器会使用先前注册到该服务的密钥对对其进行签名。这会创建一个断言。与证明不同,无论使用哪种设备,断言的格式始终相同。
断言通过 WebAuthn API 作为 AuthenticatorAssertionResponse 返回。断言格式相当简单,因为它包含四个基本的 ArrayBuffers
- clientDataJSON - 与证明相同。一个包含浏览器在被要求进行身份验证时所看到内容的 JSON 表示形式的 ArrayBuffer。
- authenticatorData - 由身份验证器创建和/或使用的数据(另请参见 身份验证器数据)。
- signature - 对 clientDataJSON 和 authenticatorData 的签名,可以使用注册期间创建的公钥进行验证。
- userHandle - 可选。(可为空)用户标识符。这可能是用户名或用户名的哈希值等。服务使用它来为凭据提供范围。最大长度为 64 字节。较旧的身份验证器 (U2F) 不支持此输出。
需要重点说明的是,断言的签名使用与证明不同的密钥对。断言使用服务密钥对进行签名,该密钥对是在注册期间生成的。证明使用刻录到同一设备所有型号中的证明私钥和证明证书进行签名。(自证明情况除外。)