本文档介绍了 WebAuthn 中的 userVerification
,以及在通行密钥创建或身份验证期间指定 userVerification
时产生的浏览器行为。
WebAuthn 中的“用户验证”是什么?
通行密钥基于公钥加密技术构建。创建通行密钥后,系统会生成公钥私钥对,通行密钥提供程序存储私钥,并将公钥返回给依赖方 (RP) 服务器进行存储。服务器可以使用已配对的公钥来验证由同一通行密钥签名的签名,从而对用户进行身份验证。公钥凭据上的“用户存在”(UP) 标记用于证明有人在身份验证期间与设备进行了互动。
用户验证是一道可选的安全防线,旨在声明身份验证期间存在的是正确的人员,而不是像用户在线状态声明的那样,这只是某个人。在智能手机上,通常使用屏幕锁定机制(无论是生物识别还是 PIN 码或密码)完成此操作。在通行密钥注册和身份验证期间,系统会通过身份验证器数据返回的“UV”标记报告是否进行了用户验证
![显示 macOS 上 iCloud 钥匙串的用户验证对话框的屏幕截图。该对话框会提示用户使用触控 ID 登录,并显示请求身份验证的来源以及用户名。对话框右上角有一个标记为“Cancel”(取消)的按钮。](https://web.developers.google.cn/static/articles/webauthn-user-verification/image/fig-1.png?authuser=5&hl=sv)
![Android 版 Chrome 中用户验证对话框的屏幕截图。该对话框会提示用户使用人脸识别或指纹检测来验证自己的身份,并显示请求身份验证的来源。左下角有一个使用 PIN 码进行验证的选项。](https://web.developers.google.cn/static/articles/webauthn-user-verification/image/fig-2.png?authuser=5&hl=sv)
如何在服务器上验证 UP 和 UV
用户在线状态 (UP) 和用户已验证 (UV) 布尔值标志会在身份验证器数据字段中向服务器发送信号。在身份验证过程中,可以使用存储的公钥验证签名,从而验证身份验证器数据字段的内容。只要签名有效,服务器即可认为标记是真实的。
![身份验证数据结构的描绘。该数据结构的每一部分从左到右依次为“RP ID HASH”(32 个字节)、“FLAGS”(1 字节)、“COUNTER”(4 个字节,big-endian uint32)、“ATTESTE CRED”。DATA”(如果存在可变长度)和“EXTENSIONS”(如果存在可变长度 (CBOR))。“FLAGS”部分已展开,显示可能的标志列表,从左到右依次为:“ED”、“AT”、“0”、“BS”、“BE”、“UV”、“0”和“UP”。](https://web.developers.google.cn/static/articles/webauthn-user-verification/image/fig-3.png?authuser=5&hl=sv)
在通行密钥注册和身份验证时,服务器应检查 UP 标志是否为 true
,以及 UV 标志是 true
还是 false
,具体取决于要求。
指定 userVerification
参数
根据 WebAuthn 规范,RP 可以在凭据创建和断言时使用 userVerification
参数请求用户验证。它接受 'preferred'
、'required'
或 'discouraged'
,分别表示:
'preferred'
(默认):首选在设备上使用用户验证方法,但如果无法使用该方法,则可以跳过。如果执行了用户验证,响应凭据包含 UV 标志值为true
;如果未执行 UV,则包含false
。'required'
:必须调用设备上可用的用户验证方法。如果一个不可用,请求将在本地失败。这意味着,响应凭据始终会在 UV 标志设置为true
的情况下返回。'discouraged'
:不建议使用用户验证方法。不过,根据设备,无论如何,系统都可能会执行用户验证,并且 UV 标志可以包含true
或false
。
用于创建通行密钥的示例代码:
const publicKeyCredentialCreationOptions = {
// ...
authenticatorSelection: {
authenticatorAttachment: 'platform',
residentKey: 'required',
requireResidentKey: true,
userVerification: 'preferred'
}
};
const credential = await navigator.credentials.create({
publicKey: publicKeyCredentialCreationOptions
});
通行密钥身份验证的示例代码:
const publicKeyCredentialRequestOptions = {
challenge: /* Omitted challenge data... */,
rpId: 'example.com',
userVerification: 'preferred'
};
const credential = await navigator.credentials.get({
publicKey: publicKeyCredentialRequestOptions
});
您应该为userVerification
选择哪个选项?
您应该使用的 userVerification
值取决于您的应用要求以及您的用户体验需求。
何时使用 userVerification='preferred'
如果您优先考虑用户体验而非保护,请使用 userVerification='preferred'
。
在有些环境中,用户验证会比保护更麻烦。例如,在无法使用触控 ID 的 macOS 上(由于设备不支持触控 ID、已停用或设备处于翻盖模式),系统会要求用户输入系统密码。这会产生阻碍,并且用户可能会完全放弃身份验证。如果消除阻力对您来说更重要,请使用 userVerification='preferred'
。
![macOS 上通行密钥对话框的屏幕截图,当触控 ID 不可用时显示。该对话框包含请求身份验证的来源以及用户名等信息。对话框右上角有一个标记为“Cancel”(取消)的按钮。](https://web.developers.google.cn/static/articles/webauthn-user-verification/image/fig-4.png?authuser=5&hl=sv)
使用 userVerification='preferred'
时,如果成功执行了用户验证,UV 标志为 true
;如果跳过用户验证,则 UV 标志为 false
。例如,在不支持触控 ID 的 macOS 上,它会要求用户点击按钮以跳过用户验证,并且公钥凭据包含 false
UV 标志。
然后,紫外线标记便会成为风险分析中的一个信号。如果登录尝试因其他因素而存在风险,您可能需要要求用户进行额外的登录验证(如果未执行用户验证)。
何时使用 userVerification='required'
如果您认为 UP 和 UV 都是绝对必要的,请使用 userVerification='required'
。
这种方法的缺点是,用户在登录时可能会遇到更多障碍。例如,在不支持触控 ID 的 macOS 上,系统会要求用户输入系统密码。
借助 userVerification='required'
,您可以确保在设备上执行用户验证。确保服务器验证 UV 标志是否为 true
。
总结
通过利用用户验证,依赖通行密钥的各方可以衡量设备所有者登录的可能性。用户可以自行选择是需要用户验证,还是允许验证,具体取决于后备登录机制对用户流的影响程度。确保服务器针对通行密钥用户身份验证检查 UP 标志和 UV 标志。