1. 简介
本节不具有规范性。
本规范定义了一个 API,使得 Web 应用程序能够创建和使用强大的、经认证的、限定作用域的、基于公钥的凭据,旨在对用户进行强身份验证。公钥凭据由 WebAuthn 验证器 在 WebAuthn 依赖方 的指令下创建并存储,并受 用户同意 约束。随后,该公钥凭据仅能被属于该依赖方的 来源 (origins) 访问。这种作用域限定由 符合要求的用户代理 和 验证器 共同强制执行。此外,跨依赖方的隐私也得以维护;依赖方无法检测到任何限定作用域于其他依赖方的凭据的任何属性,甚至无法检测其存在。
依赖方在涉及用户的两个不同但相关的仪式 (ceremonies) 中使用 Web 身份验证 API。第一种是注册,即在验证器上创建公钥凭据,并将其限定作用域于与当前用户账户相关的依赖方(账户可能已存在,也可能此时创建)。第二种是身份验证,即向依赖方出示一份 身份验证断言,证明注册该公钥凭据的用户的在场和同意。从功能上讲,Web 身份验证 API 包含一个 PublicKeyCredential,它扩展了凭据管理 API [CREDENTIAL-MANAGEMENT-1],以及允许这些凭据与 navigator.credentials.create() 和 navigator.credentials.get() 一起使用的基础设施。前者用于注册,后者用于身份验证。
总的来说,合规的验证器保护公钥凭据,并与用户代理交互以实现 Web 身份验证 API。在以下环境中执行软件可以实现合规验证器:(a) 通用计算设备,(b) 设备上的安全执行环境、可信平台模块 (TPM) 或安全元件 (SE),或 (c) 设备外部。在设备上实现的验证器称为平台验证器。在设备外部实现的验证器(漫游验证器)可以通过通用串行总线 (USB)、低功耗蓝牙 (BLE) 或近场通信 (NFC) 等传输方式进行访问。
1.1. 规范路线图
虽然许多 W3C 规范主要针对用户代理开发人员以及 Web 应用程序开发人员(即“Web 作者”),但 Web 身份验证的性质要求本规范能够被多个受众正确使用,具体如下所述。
所有受众都应从 § 1.2 用例、§ 1.3 API 使用场景示例 和 § 4 术语 开始,并应参阅 [WebAuthnAPIGuide] 以获取全面指南。除此之外,本文档的目标受众是以下主要群体:
-
依赖方 Web 应用程序开发人员,特别是负责依赖方 Web 应用程序登录流程、账户恢复流程、用户账户数据库内容等的开发人员。
-
Web 框架开发人员
-
上述两类受众尤其应参阅 § 7 WebAuthn 依赖方操作。§ 5 Web 身份验证 API 的介绍可能有所帮助,尽管读者应该意识到 § 5 Web 身份验证 API 部分专门针对用户代理开发人员,而非 Web 应用程序开发人员。此外,如果他们打算验证验证器的认证,那么 § 6.5 认证 和 § 8 定义的认证语句格式 也将与之相关。如果他们希望利用扩展,那么 § 9 WebAuthn 扩展 和 § 10 定义的扩展 将会引起他们的兴趣。最后,他们应阅读 § 13.4 依赖方的安全性考虑 和 § 14.6 依赖方的隐私考虑,并考虑哪些挑战适用于他们的应用程序和用户。
-
-
用户代理开发人员
-
操作系统平台开发人员,负责与平台特定验证器 API、平台 WebAuthn 客户端实例化等相关的操作系统平台 API 设计和实现。
-
上述两类受众应非常仔细地阅读 § 5 Web 身份验证 API,如果他们打算支持扩展,还应阅读 § 9 WebAuthn 扩展。他们还应仔细阅读 § 14.5 客户端的隐私考虑。
-
-
验证器开发人员。这些读者将需要特别注意 § 6 WebAuthn 验证器模型、§ 8 定义的认证语句格式、§ 9 WebAuthn 扩展 和 § 10 定义的扩展。他们还应仔细阅读 § 13.3 验证器的安全性考虑 和 § 14.4 验证器的隐私考虑。
对于 Web 身份验证部署的端到端安全性而言,至关重要的是每个组件的角色——依赖方服务器、客户端和验证器——以及 § 13 安全性考虑 和 § 14 隐私考虑,都必须被所有受众所理解。
1.2. 用例
以下用例场景说明了两种截然不同的验证器的使用,并概述了更多场景。包括示例代码在内的更多场景在稍后的 § 1.3 API 使用场景示例 中给出。
1.2.1. 注册
-
在手机上
-
用户在浏览器中导航到 example.com,并使用他们一直使用的任何方法(可能是一个传统方法,如密码)登录现有账户,或创建一个新账户。
-
手机提示:“您想将此设备注册到 example.com 吗?”
-
用户同意。
-
手机提示用户进行预先配置的授权手势(PIN、生物识别等);用户提供该手势。
-
网站显示消息:“注册完成。”
-
1.2.2. 身份验证
-
在笔记本电脑或台式机上
-
用户通过蓝牙将手机与笔记本电脑或台式机配对。
-
用户在浏览器中导航到 example.com 并发起登录。
-
用户收到浏览器的消息:“请在您的手机上完成此操作。”
-
-
接着,在他们的手机上
-
用户看到一个不显眼的提示或通知:“登录到 example.com。”
-
用户选择此提示/通知。
-
用户看到其 example.com 身份列表,例如:“以 Mohamed 身份登录 / 以张三身份登录”。
-
用户选择一个身份,被提示进行授权手势(PIN、生物特征等)并提供该手势。
-
-
现在,回到笔记本电脑上
-
网页显示所选用户已登录,并导航到登录后的页面。
-
1.2.3. 新设备注册
该用例场景说明了依赖方如何利用漫游验证器(例如 USB 安全密钥钥匙扣)和平台验证器(例如内置指纹传感器)的组合,以便用户拥有
注意:这种为一个账户注册多个验证器的方法在账户恢复用例中也很有用。
-
首先,在台式电脑上(缺少平台验证器)
-
用户在浏览器中导航到
example.com,并使用他们一直使用的方法(可能是旧方法,如密码)登录现有账户,或创建一个新账户。 -
用户导航到账户安全设置并选择“注册安全密钥”。
-
网站提示用户插入 USB 安全密钥钥匙扣;用户插入。
-
USB 安全密钥闪烁,指示用户应按下其上的按钮;用户按下。
-
网站显示消息:“注册完成。”
注意:由于此计算机缺少平台验证器,网站可能要求用户不时或在每次与网站交互时出示其 USB 安全密钥。这由网站自行决定。
-
-
后来,在他们的笔记本电脑上(具有平台验证器)
-
用户在浏览器中导航到 example.com 并发起登录。
-
网站提示用户插入 USB 安全密钥。
-
用户插入先前注册的 USB 安全密钥并按下按钮。
-
网站显示用户已登录,并导航到登录后页面。
-
网站提示:“您想将此电脑注册到 example.com 吗?”
-
用户同意。
-
笔记本电脑提示用户输入先前配置的授权手势(PIN、生物特征等);用户提供该手势。
-
网站显示消息:“注册完成。”
-
用户注销。
-
-
后来,再次在他们的笔记本电脑上
-
用户在浏览器中导航到 example.com 并发起登录。
-
网站显示消息:“请按照您电脑的提示完成登录。”
-
笔记本电脑提示用户进行授权手势(PIN、生物特征等);用户提供该手势。
-
网站显示用户已登录,并导航到登录后页面。
-
1.2.4. 其他用例和配置
各种其他用例和配置也是可能的,包括(但不限于):
-
用户在笔记本电脑上导航到 example.com,并被引导完成在手机上创建并注册凭据的流程。
-
用户获得一个离散的漫游验证器,例如带有 USB 或 USB+NFC/BLE 连接选项的“钥匙扣”,在笔记本电脑或手机上的浏览器中加载 example.com,并被引导完成在钥匙扣上创建和注册凭据的流程。
1.3. API 使用场景示例
本节不具有规范性。
在本节中,我们将介绍公钥凭据生命周期中的一些事件,以及使用此 API 的相应示例代码。请注意,这是一个示例流程,并不限制 API 的使用范围。
与前面的部分一样,此流程侧重于涉及带有自身显示器的第一因素漫游验证器的用例。此类验证器的一个例子是智能手机。此 API 也支持其他验证器类型,但受限于客户端平台的实现。例如,对于嵌入在客户端设备中的验证器,此流程也无需修改即可工作。对于没有自身显示器的验证器(类似于智能卡),该流程在特定实现考虑下也适用。具体而言,客户端平台需要显示原本由验证器显示的任何提示,并且验证器需要允许客户端平台枚举所有验证器的凭据,以便客户端能够获得信息来显示适当的提示。
1.3.1. 注册
这是首次流程,其中创建了一个新凭据并将其注册到服务器。在此流程中,WebAuthn 依赖方没有对平台验证器或漫游验证器的偏好。
-
用户访问 example.com,该网站提供脚本。此时,用户可能已经使用旧有的用户名和密码、额外验证器或其他依赖方可接受的方式登录,或者用户可能正在创建新账户的过程中。
-
依赖方脚本运行以下代码片段。
-
客户端平台搜索并定位验证器。
-
客户端连接到验证器,如有必要,执行任何配对操作。
-
验证器显示适当的 UI,供用户提供生物特征或其他授权手势。
-
如果创建了新凭据,则:
生成并注册新密钥的示例代码如下
if ( ! window. PublicKeyCredential) { /* Client not capable. Handle error. */ } var publicKey= { // The challenge is produced by the server; see the Security Considerations challenge: new Uint8Array([ 21 , 31 , 105 /* 29 more random bytes generated by the server */ ]), // Relying Party: rp: { name: "ACME Corporation" }, // User: user: { id: Uint8Array. from( window. atob( "MIIBkzCCATigAwIBAjCCAZMwggE4oAMCAQIwggGTMII=" ), c=> c. charCodeAt( 0 )), name: "alex.mueller@example.com" , displayName: "Alex Müller" , }, // This Relying Party will accept either an ES256 or RS256 credential, but // prefers an ES256 credential. pubKeyCredParams: [ { type: "public-key" , alg: - 7 // "ES256" as registered in the IANA COSE Algorithms registry }, { type: "public-key" , alg: - 257 // Value registered by this specification for "RS256" } ], authenticatorSelection: { // Try to use UV if possible. This is also the default. userVerification: "preferred" }, timeout: 360000 , // 6 minutes excludeCredentials: [ // Don’t re-register any authenticator that has one of these credentials { "id" : Uint8Array. from( window. atob( "ufJWp8YGlibm1Kd9XQBWN1WAw2jy5In2Xhon9HAqcXE=" ), c=> c. charCodeAt( 0 )), "type" : "public-key" }, { "id" : Uint8Array. from( window. atob( "E/e1dhZc++mIsz4f9hb6NifAzJpF1V4mEtRlIPBiWdY=" ), c=> c. charCodeAt( 0 )), "type" : "public-key" } ], // Make excludeCredentials check backwards compatible with credentials registered with U2F extensions: { "appidExclude" : "https://acme.example.com" } }; // Note: The following call will cause the authenticator to display UI. navigator. credentials. create({ publicKey}) . then( function ( newCredentialInfo) { // Send new credential info to server for verification and registration. }). catch ( function ( err) { // No acceptable authenticator or user refused consent. Handle appropriately. });
1.3.2. 使用用户验证平台验证器的特殊注册
这是一个示例流程,适用于 WebAuthn 依赖方专门有兴趣使用用户验证平台验证器创建公钥凭据的情况。
-
用户访问 example.com 并点击登录按钮,这会将用户重定向到 login.example.com。
-
用户输入用户名和密码进行登录。登录成功后,用户被重定向回 example.com。
-
依赖方脚本运行以下代码片段。
if ( ! window. PublicKeyCredential) { /* Client not capable of the API. Handle error. */ } PublicKeyCredential. isUserVerifyingPlatformAuthenticatorAvailable() . then( function ( uvpaAvailable) { // If there is a user-verifying platform authenticator if ( uvpaAvailable) { // Render some RP-specific UI and get a Promise for a Boolean value return askIfUserWantsToCreateCredential(); } }). then( function ( userSaidYes) { // If there is a user-verifying platform authenticator // AND the user wants to create a credential if ( userSaidYes) { var publicKeyOptions= { /* Public key credential creation options. */ }; return navigator. credentials. create({ "publicKey" : publicKeyOptions}); } }). then( function ( newCredentialInfo) { if ( newCredentialInfo) { // Send new credential info to server for verification and registration. } }). catch ( function ( err) { // Something went wrong. Handle appropriately. });
1.3.3. 身份验证
这是具有已注册凭据的用户访问网站并希望使用该凭据进行身份验证时的流程。
-
用户访问 example.com,后者提供一个脚本。
-
脚本向客户端请求身份验证断言,提供尽可能多的信息以缩小用户可接受的凭据选择范围。这可以从注册后本地存储的数据中获得,或者通过其他方式(例如提示用户输入用户名)获得。
-
依赖方脚本运行以下代码片段之一。
-
客户端平台搜索并定位验证器。
-
客户端连接到验证器,如有必要,执行任何配对操作。
-
验证器向用户发出需要其注意的通知。打开通知后,用户会看到一个友好的选择菜单,显示可接受的凭据(使用创建凭据时提供的账户信息),以及有关请求这些密钥的 来源 的一些信息。
-
验证器从用户处获得生物特征或其他授权手势。
-
如果成功生成并返回了断言:
如果依赖方脚本没有任何可用的提示(例如从本地存储的数据中)来帮助其缩小凭据列表范围,则执行此类身份验证的示例代码可能如下所示。
if ( ! window. PublicKeyCredential) { /* Client not capable. Handle error. */ } // credentialId is generated by the authenticator and is an opaque random byte array var credentialId= new Uint8Array([ 183 , 148 , 245 /* more random bytes previously generated by the authenticator */ ]); var options= { // The challenge is produced by the server; see the Security Considerations challenge: new Uint8Array([ 4 , 101 , 15 /* 29 more random bytes generated by the server */ ]), timeout: 120000 , // 2 minutes allowCredentials: [{ type: "public-key" , id: credentialId}] }; navigator. credentials. get({ "publicKey" : options}) . then( function ( assertion) { // Send assertion to server for verification }). catch ( function ( err) { // No acceptable credential or user refused consent. Handle appropriately. });
另一方面,如果依赖方脚本有一些提示来帮助其缩小凭据列表范围,则执行此类身份验证的示例代码可能如下所示。请注意,此示例还演示了如何使用凭据属性扩展。
if ( ! window. PublicKeyCredential) { /* Client not capable. Handle error. */ } var encoder= new TextEncoder(); var acceptableCredential1= { type: "public-key" , id: encoder. encode( "BA44712732CE" ) }; var acceptableCredential2= { type: "public-key" , id: encoder. encode( "BG35122345NF" ) }; var options= { // The challenge is produced by the server; see the Security Considerations challenge: new Uint8Array([ 8 , 18 , 33 /* 29 more random bytes generated by the server */ ]), timeout: 120000 , // 2 minutes allowCredentials: [ acceptableCredential1, acceptableCredential2], extensions: { 'credProps' : true } }; navigator. credentials. get({ "publicKey" : options}) . then( function ( assertion) { // Send assertion to server for verification }). catch ( function ( err) { // No acceptable credential or user refused consent. Handle appropriately. });
1.3.4. 中止身份验证操作
下面的示例显示了开发人员如何使用 AbortSignal 参数中止凭据注册操作。身份验证操作也有类似的程序。
const authAbortController= new AbortController(); const authAbortSignal= authAbortController. signal; authAbortSignal. onabort= function () { // Once the page knows the abort started, inform user it is attempting to abort. } var options= { // A list of options. } navigator. credentials. create({ publicKey: options, signal: authAbortSignal}) . then( function ( attestation) { // Register the user. }). catch ( function ( error) { if ( error== "AbortError" ) { // Inform user the credential hasn’t been created. // Let the server know a key hasn’t been created. } }); // Assume widget shows up whenever authentication occurs. if ( widget== "disappear" ) { authAbortController. abort(); }
1.3.5. 停用
以下是可能需要停用凭据的情况。请注意,所有这些都在服务器端处理,不需要此处指定的 API 的支持。
-
可能性 #1 —— 用户报告凭据丢失。
-
可能性 #2 —— 服务器由于不活动而注销凭据。
-
服务器在维护活动期间从其数据库中删除凭据。
-
未来,依赖方脚本不会在任何可接受凭据列表中指定此凭据,并且由此凭据签名的断言将被拒绝。
-
-
可能性 #3 -- 用户从验证器中删除凭据。
-
用户使用验证器特定的方法(例如,设备设置 UI)从他们的验证器中删除凭据。
-
从这时起,此凭据将不会出现在任何选择提示中,并且无法使用它生成任何断言。
-
一段时间后,服务器由于不活动而注销此凭据。
-
1.4. 特定平台的实现指南
本规范定义了在一般情况下如何使用 Web 身份验证。当结合特定的平台支持(例如 App)使用 Web 身份验证时,建议查看特定平台的文档和指南以获取额外的指导和限制。
2. 合规性
本规范定义了三个一致性类别。规定了这些类别中的每一个,以便该类别的合规成员能够抵御来自其他类别的不合规或敌对成员的攻击。
2.1. 用户代理
用户代理必须按照 § 5 Web 身份验证 API 的描述行事,才能被视为合规。合规用户代理可以以任何期望的方式实现本规范中给出的算法,只要最终结果与规范算法所获得的结果无法区分即可。
合规的用户代理也必须是本规范 IDL 片段的合规实现,如“Web IDL”规范中所述。[WebIDL]
2.1.1. 作为 DOMString 类型的枚举
Web IDL 的其他部分不引用枚举类型,因为这会妨碍在不更新本规范及其实现的情况下使用其他值。对于向后兼容性而言,重要的是客户端平台和依赖方处理未知值。本规范的枚举在这里存在是为了文档和作为注册表。在其他地方表示枚举时,它们被键入为 DOMString,例如在 transports 中。
2.2. 验证器
一个 WebAuthn 验证器必须提供 § 6 WebAuthn 验证器模型 定义的操作,并且这些操作必须按照那里的描述进行行事。这是一组功能和安全要求,以便验证器能够被 合规用户代理所使用。
如 § 1.2 用例 中所述,验证器可以在用户代理底层的操作系统中实现,也可以在外部硬件中实现,或者是两者的结合。
2.2.1. 与 FIDO U2F 的向后兼容性
仅支持 § 8.6 FIDO U2F 认证语句格式 的验证器没有存储用户句柄的机制,因此返回的 userHandle 将始终为 null。
2.3. WebAuthn 依赖方
一个 WebAuthn 依赖方必须按照 § 7 WebAuthn 依赖方操作 中的描述行事,以获得本规范提供的所有安全优势。有关此内容的进一步讨论,请参阅 § 13.4.1 WebAuthn 依赖方的安全优势。
2.4. 所有合规类别
上述合规类别的成员执行的所有 CBOR 编码必须使用 CTAP2 规范化 CBOR 编码形式。上述合规类别的所有解码器应拒绝未以 CTAP2 规范化 CBOR 编码形式有效编码的 CBOR,并应拒绝包含重复映射键的消息。
3. 依赖项
本规范依赖于其他几个基础规范,这些规范列在下方和通过引用定义的术语中。
- Base64url 编码
-
术语 Base64url 编码 指的是使用 [RFC4648] 第 5 节中定义的 URL 和文件名安全字符集的 base64 编码,省略所有尾随的 '=' 字符(如第 3.2 节所允许),且不包含任何换行符、空白或其他附加字符。
- CBOR
-
本规范中的许多结构,包括认证语句和扩展,都是使用紧凑二进制对象表示 (CBOR) [RFC8949] 的 CTAP2 规范化 CBOR 编码形式进行编码的,如 [FIDO-CTAP] 中定义。
- CDDL
- COSE
-
CBOR 对象签名和加密 (COSE) [RFC8152]。本规范建立的 IANA COSE 算法注册表 [IANA-COSE-ALGS-REG] 也被使用。
- 凭据管理
-
本文档中描述的 API 是 [CREDENTIAL-MANAGEMENT-1] 中定义的
Credential概念的扩展。 - DOM
-
DOMException以及本规范中使用的 DOMException 值在 [DOM4] 中定义。 - ECMAScript
-
%ArrayBuffer% 在 [ECMAScript] 中定义。
- HTML
-
浏览上下文 (browsing context)、来源 (origin)、不透明来源 (opaque origin)、元组来源 (tuple origin)、相关设置对象 (relevant settings object) 以及 是...的可注册域名后缀或等于... 的概念在 [HTML] 中定义。
- URL
-
同站 (same site) 的概念在 [URL] 中定义。
- Web IDL
-
本规范中的许多接口定义和所有 IDL 都依赖于 [WebIDL]。Web IDL 标准的这个更新版本增加了对
Promise的支持,这现在是所有新 Web API 中异步交互的首选机制。 - FIDO AppID
-
确定调用应用程序的 FacetID 和 确定调用者的 FacetID 是否被 AppID 授权(仅在 AppID 扩展中使用)的算法由 [FIDO-APPID] 定义。
本文档中的关键字 "MUST"、"MUST NOT"、"REQUIRED"、"SHALL"、"SHALL NOT"、"SHOULD"、"SHOULD NOT"、"RECOMMENDED"、"MAY" 和 "OPTIONAL" 应按照 [RFC2119] 中的描述进行解释。
4. 术语
- 证明(Attestation)
-
通常,认证 (attestation) 是一份用作见证、确认或验证的声明。在 WebAuthn 上下文中,认证用于证明 (attest) 验证器及其发出的数据的来源 (provenance);包括,例如:凭据 ID、凭据密钥对、签名计数器等。在注册期间,通过认证对象传达认证语句。另请参阅 § 6.5 认证 和 图 6。客户端如何将认证对象的认证语句和 AAGUID 部分传达给依赖方,由认证传输 (attestation conveyance) 描述。
- 证明证书(Attestation Certificate)
-
一个用于验证器进行自身制造和能力证明的 认证密钥对 (attestation key pair) 的 X.509 证书。在注册时,验证器使用 认证私钥 来签署其生成并通过 authenticatorMakeCredential 操作返回的依赖方特定的凭据公钥(及额外数据)。依赖方使用认证证书中传达的 认证公钥 来验证认证签名。注意,在自认证的情况下,验证器既没有独立的认证密钥对也没有认证证书,详情请参阅自认证。
- 身份验证(Authentication)
- 身份验证仪式(Authentication Ceremony)
-
用户及其客户端(包含至少一个验证器)协作向依赖方以密码学方式证明用户控制了先前注册的公钥凭据的凭据私钥的仪式(参见注册)。注意,这包括用户在场测试或用户验证。
WebAuthn 身份验证仪式定义在 § 7.2 验证身份验证断言 中,由依赖方调用
navigator.credentials.get()且带有publicKey参数来发起。有关入门概述,请参阅 § 5 Web 身份验证 API,有关实现示例,请参阅 § 1.3.3 身份验证。 - 身份验证断言(Authentication Assertion)
- 断言(Assertion)
-
作为 authenticatorGetAssertion 操作的结果,由验证器返回的经过加密签名的
AuthenticatorAssertionResponse对象。这对应于 [CREDENTIAL-MANAGEMENT-1] 规范的一次性凭据。
- 验证器(Authenticator)
- WebAuthn 验证器 (WebAuthn Authenticator)
-
一种以硬件或软件形式存在的加密实体,当依赖方请求时,可以向给定的依赖方注册用户,稍后断言拥有 (assert possession) 已注册的公钥凭据,并可选择验证用户。验证器可以在注册期间通过认证报告有关其类型和安全特性的信息。
一个 WebAuthn 验证器可以是一个漫游验证器、一个集成到客户端设备中的专用硬件子系统,或是客户端或客户端设备的软件组件。
通常,一个验证器被假定只有一个用户。如果多个自然人共享对一个验证器的访问权限,则在那个验证器的上下文中,他们被视为同一个用户。如果一个验证器实现支持在隔离的分区中拥有多个用户,那么每个分区都被视为一个具有单个用户的独立验证器,且无法访问其他用户的凭据。
- 授权手势(Authorization Gesture)
-
授权手势是用户作为仪式(如注册或身份验证)的一部分与验证器进行的物理交互。通过进行这样的授权手势,用户提供同意(即授权)仪式继续进行。如果所使用的验证器具备相应能力,这可能涉及用户验证,或者可能仅涉及简单的用户在场测试。
- 生物识别(Biometric Recognition)
-
基于个体生物和行为特征的自动化识别 [ISOBiometricVocabulary]。
- 生物特征认证器
- 绑定凭据
-
一个公钥凭据源 (public key credential source) 或公钥凭据被称为被绑定 (bound) 到其管理验证器。这意味着只有管理验证器可以为绑定到它的公钥凭据源生成断言。
- 仪式
-
仪式 (ceremony) [Ceremony] 的概念是网络协议概念的扩展,包括人类节点和计算机节点,以及包含用户界面、人际沟通以及传输携带数据的物理对象的通信链路。协议之外的是仪式的范畴。在本规范中,注册和身份验证是仪式,而授权手势通常是这些仪式的一个组成部分。
- 客户端
- WebAuthn 客户端
-
本文中也简称为客户端。另请参阅合规用户代理。一个 WebAuthn 客户端是一个中间实体,通常在用户代理中(全部或部分)实现。从概念上讲,它是 Web 身份验证 API 的基础,体现了
[[Create]](origin, options, sameOriginWithAncestors)和[[DiscoverFromExternalSource]](origin, options, sameOriginWithAncestors)内部方法的实现。它负责为底层的验证器操作整理输入,并将这些操作的结果返回给 Web 身份验证 API 的调用者。WebAuthn 客户端在 WebAuthn 客户端设备上运行,并且与该设备是分开的。
- 客户端设备
- WebAuthn 客户端设备
-
WebAuthn 客户端在其上运行的硬件设备,例如智能手机、笔记本电脑或台式计算机,以及在该硬件上运行的操作系统。
WebAuthn 客户端设备和客户端之间的区别在于:
- 客户端平台
-
客户端设备和客户端共同组成客户端平台。单个硬件设备可以通过运行不同的操作系统和/或客户端,在不同时间成为多个不同客户端平台的一部分。
- 客户端侧
- 客户端可发现公钥凭据源 (Client-side discoverable Public Key Credential Source)
- 客户端可发现凭据 (Client-side discoverable Credential)
- 可发现凭据 (Discoverable Credential)
- [已弃用] 驻留凭据 (Resident Credential)
- [已弃用] 驻留密钥 (Resident Key)
-
注意:历史上,客户端可发现凭据被称为驻留凭据或驻留密钥。由于短语
ResidentKey和residentKey在 WebAuthn API 以及 验证器模型(例如,在字典成员名称、算法变量名称和操作参数中)中被广泛使用,因此为了向后兼容,它们名称中resident的用法并未更改。此外,术语驻留密钥在此处定义为等同于客户端可发现凭据。客户端可发现公钥凭据源,简称可发现凭据,是一种公钥凭据源,它是 可发现的 且可用于身份验证仪式,在这种仪式中,依赖方不提供任何凭据 ID,即依赖方在调用
navigator.credentials.get()时带有 空 的allowCredentials参数。这意味着依赖方不一定需要首先识别用户。因此,一个具有可发现凭据能力的验证器仅需提供依赖方 ID (RP ID) 即可为可发现凭据生成断言签名,这反过来要求公钥凭据源存储在验证器或客户端平台中。这与服务器端公钥凭据源形成对比,后者要求向验证器提供依赖方 ID 和凭据 ID,但不要求客户端存储公钥凭据源。
注意:客户端可发现凭据也适用于在身份验证仪式中提供凭据 ID 的情况,即调用
navigator.credentials.get()时带有非空的allowCredentials参数。 - 符合规范的用户代理
-
一个用户代理,它与底层客户端设备协作,实现 Web 身份验证 API 和本规范中给出的算法,并处理验证器与依赖方之间的通信。
- 凭据 ID
-
凭据 ID 由验证器以两种形式生成:
- 凭据密钥对 (Credential Key Pair)
- 凭据私钥 (Credential Private Key)
- 凭据公钥
- 用户公钥
-
一个凭据密钥对是由验证器生成并限定作用域于特定 WebAuthn 依赖方的非对称加密密钥对。它是公钥凭据的核心部分。
一个凭据公钥是凭据密钥对的公钥部分。凭据公钥在注册仪式期间返回给依赖方。
一个凭据私钥是凭据密钥对的私钥部分。凭据私钥被绑定到特定的验证器(即其管理验证器),并且预期绝不会暴露给任何其他方,即使是验证器的所有者。
注意,在自认证的情况下,凭据密钥对也用作认证密钥对,详情请参阅自认证。
注意:凭据公钥在 FIDO UAF [UAFProtocol] 以及 FIDO U2F [FIDO-U2F-Message-Formats] 和本规范中与此相关的部分中被称为用户公钥 (user public key)。
- 凭据属性 (Credential Properties)
- 人类可读性
-
一个人类可读的标识符,旨在让普通用户易于记忆和复现,这与例如随机生成的比特序列 [EduPersonObjectClassSpec] 等标识符形成对比。
- 不可发现凭据 (Non-Discoverable Credential)
-
这是一种凭据,当调用
navigator.credentials.get()时,必须在allowCredentials中提供其凭据 ID,因为它不是客户端可发现的。另请参阅服务器端凭据。 - 公钥凭据源
-
由验证器用于生成身份验证断言的凭据源([CREDENTIAL-MANAGEMENT-1])。公钥凭据源由包含以下项的结构体组成:
- type
-
其值为
PublicKeyCredentialType,默认为public-key。 - id
-
一个凭据 ID。
- privateKey
-
凭据私钥。
- rpId
- userHandle
- otherUI
-
可选的其它信息,供验证器用于呈现其 UI。例如,这可能包括用户的
displayName。otherUI 是一个可变项,不应以阻止 otherUI 更新的方式绑定到公钥凭据源。
authenticatorMakeCredential 操作会创建一个绑定到管理验证器的公钥凭据源,并返回与其凭据私钥关联的凭据公钥。依赖方可以使用此凭据公钥来验证由该公钥凭据源创建的身份验证断言。
- 公钥凭据
-
通常,凭据是实体向另一实体提供的数据,旨在将前者认证给后者 [RFC4949]。术语公钥凭据指代以下之一:公钥凭据源、对应于公钥凭据源且可能经过认证的凭据公钥,或身份验证断言。具体指代哪一个通常由上下文决定。
注意:这是对 [RFC4949] 的故意违背。在英语中,“credential”既指代 a) 为证明某声明而提交的事物,也指代 b) 旨在被多次使用的事物。在公钥系统中,无法用单一数据安全地同时实现这两个标准。[RFC4949] 选择将凭据定义为可以多次使用的东西(公钥),而本规范赋予了“credential”一词英语层面的灵活性。本规范使用更具体的术语来标识与 [RFC4949] 凭据相关的数据。在注册时,验证器会创建一个非对称密钥对,并将其私钥部分和来自依赖方的信息存储到公钥凭据源中。公钥部分会被返回给依赖方,由其连同当前用户的账户一并存储。随后,只有通过其RP ID标识的该依赖方能够通过
get()方法在身份验证仪式中使用该公钥凭据。依赖方使用其存储的凭据公钥副本,来验证由此产生的身份验证断言。 - 速率限制
-
验证器通过限制在特定时间内连续失败的身份验证尝试次数,来实现针对暴力破解攻击的控制过程(也称为节流)。如果达到限制,验证器应施加随每次后续尝试呈指数增长的延迟,或者禁用当前的身份验证模式,并在可用时提供另一种身份验证因素。速率限制通常作为用户验证的一个方面来实现。
- 注册
- 注册仪式
-
一种仪式,其中用户、依赖方和用户的客户端(包含至少一个验证器)协同工作,以创建一个公钥凭据并将其与用户的依赖方账户关联。注意,这包括采用用户在场测试或用户验证。在成功的注册仪式后,用户可以通过身份验证仪式进行认证。
WebAuthn 注册仪式定义在 § 7.1 注册新凭据 中,由依赖方调用带有
publicKey参数的发起。请参阅 § 5 Web Authentication API 获取入门概述,以及 § 1.3.1 注册 获取实现示例。navigator.credentials.create() - 依赖方
-
请参阅 WebAuthn 依赖方。
- 依赖方标识符
- RP ID
-
在 WebAuthn API 的上下文中,依赖方标识符是一个有效域名字符串,用于标识正在为其执行给定注册或身份验证仪式的 WebAuthn 依赖方。公钥凭据只能与注册它的同一实体(由RP ID标识)进行身份验证。
默认情况下,WebAuthn 操作的RP ID被设置为调用者的源 (origin)的有效域名。调用者可以覆盖此默认值,只要调用者指定的RP ID值是调用者源的有效域名的可注册域名后缀或与之相等即可。另请参阅 § 5.1.3 创建新凭据 - PublicKeyCredential 的 [[Create]](origin, options, sameOriginWithAncestors) 方法 和 § 5.1.4 使用现有凭据进行断言 - PublicKeyCredential 的 [[Get]](options) 方法。
注意:RP ID 基于主机 (host)的域名。它本身不包含协议方案或端口,这与源 (origin)不同。公钥凭据的RP ID决定了其作用域 (scope)。即,它确定了公钥凭据可在其上使用的源的集合,具体如下:例如,给定一个源为
https://login.example.com:1337的依赖方,以下RP ID是有效的:login.example.com(默认)和example.com,但m.login.example.com和com无效。这样做是为了匹配普遍部署的周边凭据(如 Cookie,[RFC6265])的行为。请注意,这比 document.domain 的 setter 所提供的“同源”限制放宽程度更大。
这些对源值的限制适用于 WebAuthn 客户端。
其他模仿 WebAuthn API 以在非 Web 平台(如原生移动应用)上启用 WebAuthn 公钥凭据的规范,可能定义不同的规则来将调用者绑定到依赖方标识符。不过,RP ID 语法必须符合有效域名字符串或 URI [RFC3986] [URL]。
- 服务器端公钥凭据源 (Server-side Public Key Credential Source)
- 服务器端凭据 (Server-side Credential)
- [已弃用] 非驻留凭据 (Non-Resident Credential)
-
注意: 在历史上,服务器端凭据被称为非驻留凭据。为了向后兼容,各种名称中包含
resident形式的 WebAuthn API 和 验证器模型组件并未更改。服务器端公钥凭据源(简称服务器端凭据)是一种公钥凭据源,仅当依赖方在
navigator.credentials.get()的allowCredentials参数中提供其凭据 ID 时,才能在身份验证仪式中使用。这意味着依赖方必须管理凭据的存储和发现,并且必须能够先识别用户,以便发现要在navigator.credentials.get()调用中提供的凭据 ID。服务器端凭据不需要客户端存储公钥凭据源。这与客户端可发现凭据形成对比,后者不需要用户先被识别即可向
navigator.credentials.get()调用提供用户的凭据 ID。另请参阅:服务器端凭据存储模式 和 不可发现凭据。
- 用户在场测试
-
用户在场测试是一种简单的授权手势和技术过程,用户通过(通常是)简单触摸验证器(也可能存在其他方式)与验证器进行交互,并返回布尔结果。注意,这不构成用户验证,因为根据定义,用户在场测试无法进行生物特征识别,也不涉及提交密码或 PIN 等共享密钥。
- 用户同意
- 用户句柄
-
用户句柄由依赖方指定,作为
的值,用于将特定的公钥凭据映射到依赖方的特定用户账户。验证器进而将 RP ID 和用户句柄对映射到公钥凭据源。user.id用户句柄是一个不透明的字节序列,最大长度为 64 字节,不打算向用户显示。
- 用户验证
-
验证器本地授权调用 authenticatorMakeCredential 和 authenticatorGetAssertion 操作的技术过程。用户验证可以通过各种授权手势模式发起;例如,通过触摸加 PIN 码、输入密码或生物特征识别(如提供指纹)[ISOBiometricVocabulary]。其目的是区分个体用户。
注意,用户验证并不向依赖方提供用户的具体身份,但当使用该凭据完成了 2 次或更多次用户验证仪式时,它表示所有这些操作都是由同一用户执行的。然而,如果多个自然人共享对同一个验证器的访问权限,同一个用户可能并不总是同一个自然人。
注意: 区分自然人在很大程度上取决于客户端平台和验证器的功能。例如,有些设备旨在由个人使用,但它们可能允许多个自然人注册指纹或知道同一个 PIN,从而使用该设备访问同一个依赖方账户。
注意:调用 authenticatorMakeCredential 和 authenticatorGetAssertion 操作意味着使用由验证器管理的密钥材料。 - 用户在场
- UP
- 用户已验证
- UV
-
成功完成用户验证过程后,用户被称为“已验证 (verified)”。
- WebAuthn 依赖方
-
其实体Web 应用程序利用 Web Authentication API 来注册和认证用户。
依赖方实现通常由在客户端调用 Web Authentication API 的客户端脚本,以及执行依赖方操作和其他应用逻辑的服务器端组件组成。两个组件之间的通信必须使用 HTTPS 或等效的传输安全协议,但这超出了本规范的范围。
注意: 虽然术语依赖方也常用于其他上下文(例如 X.509 和 OAuth),但在一个上下文中作为依赖方行动的实体,并不一定在其他上下文中也是依赖方。在本规范中,术语 WebAuthn 依赖方常被简称为依赖方,明确指代 WebAuthn 上下文中的依赖方。注意,在任何具体实例化中,WebAuthn 上下文都可能嵌入在更广泛的整体上下文中,例如基于 OAuth 的上下文。
5. Web Authentication API
本节规范性地规定了创建和使用公钥凭据的 API。基本思想是凭据属于用户,并由 WebAuthn 验证器管理,WebAuthn 依赖方通过客户端平台与验证器交互。依赖方脚本可以(经用户同意)请求浏览器为依赖方的未来使用创建一个新凭据。请参阅下方的 图 。
脚本还可以请求用户的许可,以使用现有凭据执行身份验证操作。请参阅下方的 图 。
所有此类操作均在验证器中执行,并由客户端平台代表用户调解。脚本在任何时候都无法访问凭据本身;它仅能以对象的形式获得有关凭据的信息。
除了上述脚本接口外,认证器还可以实现(或附带实现该功能的客户端软件)用于管理的用户界面。例如,此类界面可用于将认证器重置为干净状态或检查认证器的当前状态。换言之,此类界面类似于浏览器提供的用于管理用户状态(如历史记录、保存的密码和 cookie)的用户界面。诸如凭据删除之类的认证器管理操作被认为属于此类用户界面的职责,并在向脚本开放的 API 中刻意省略。
此 API 的安全属性由客户端和验证器共同提供。持有并管理凭据的验证器通过在响应中加入源,确保所有操作均作用于特定的源,且不能针对不同的源重放。具体而言,如 § 6.3 验证器操作 中定义,请求者的完整源被包含在创建新凭据时生成的认证对象中,并在此上进行签名,WebAuthn 凭据生成的所有断言中也包含此源。
此外,为了维护用户隐私并防止恶意依赖方探测属于其他依赖方的公钥凭据的存在,每个凭据也作用于一个依赖方标识符,即 RP ID。此 RP ID 由客户端在所有操作中提供给验证器,而验证器确保由依赖方创建的凭据只能在由相同 RP ID 请求的操作中使用。通过这种方式将源与 RP ID 分离,使得 API 可用于单一依赖方维护多个源的情况。
客户端通过为每次操作向验证器提供依赖方的源和 RP ID 来促进这些安全措施。由于这是 WebAuthn 安全模型不可或缺的一部分,用户代理仅在安全上下文中向调用者公开此 API。对于 Web 上下文,这仅包括通过无错误的、已建立的安全传输协议(如 TLS)访问的上下文。
Web Authentication API 是由以下各节中介绍的 Web IDL 片段合并定义的。合并后的 IDL 列表在 IDL 索引中给出。
5.1. PublicKeyCredential 接口
在所有当前引擎中。
Opera无Edge79+
Edge (旧版)18IE无
Firefox for Android60+iOS Safari13.3+Chrome for Android70+Android WebView70+Samsung Internet无Opera Mobile无
PublicKeyCredential 接口继承自 Credential [CREDENTIAL-MANAGEMENT-1],并包含在创建新凭据或请求新断言时返回给调用者的属性。
PublicKeyCredential/getClientExtensionResults
在所有当前引擎中。
Opera无Edge79+
Edge (旧版)18IE无
Firefox for Android60+iOS Safari13.3+Chrome for Android70+Android WebView70+Samsung Internet无Opera Mobile无
在所有当前引擎中。
Opera无Edge79+
Edge (旧版)18IE无
Firefox for Android60+iOS Safari13.3+Chrome for Android70+Android WebView70+Samsung Internet无Opera Mobile无
[SecureContext ,Exposed =Window ]interface PublicKeyCredential :Credential { [SameObject ]readonly attribute ArrayBuffer ; [rawId SameObject ]readonly attribute AuthenticatorResponse response ;AuthenticationExtensionsClientOutputs (); };getClientExtensionResults
id-
此属性继承自
Credential,尽管PublicKeyCredential覆盖了Credential的 getter,转而返回对象[[identifier]]内部槽中所含数据的base64url 编码。 rawId-
此属性返回
[[identifier]]内部槽中所含的ArrayBuffer。 -
在所有当前引擎中。
Firefox60+Safari13+Chrome67+
Opera无Edge79+
Edge (旧版)18IE无
Firefox for Android60+iOS Safari13.3+Chrome for Android70+Android WebView70+Samsung Internet无Opera Mobile无response,类型为 AuthenticatorResponse,只读 -
此属性包含验证器对客户端创建公钥凭据或生成身份验证断言的请求的响应。如果
PublicKeyCredential是为了响应create()而创建,则该属性的值将为AuthenticatorAttestationResponse;否则,PublicKeyCredential是为了响应get()而创建,该属性的值将为AuthenticatorAssertionResponse。 getClientExtensionResults()-
此操作返回
[[clientExtensionsResults]]的值,这是一个由扩展程序的客户端扩展程序处理生成的、包含扩展程序标识符 → 客户端扩展输出条目的映射。 [[type]]-
PublicKeyCredential接口对象的[[type]]内部槽的值为字符串 "public-key"。注意: 这通过继承自
Credential的type属性 getter 反映出来。 [[discovery]][[identifier]]-
此内部槽包含由验证器选择的凭据 ID。凭据 ID 用于查找可使用的凭据,因此预期其在所有相同类型的凭据中,以及所有验证器之间,具有很高的全局唯一性概率。
注意: 本 API 不约束此标识符的格式或长度,只要它足以让验证器唯一选择密钥即可。例如,没有内置存储的验证器可能会创建包含凭据私钥的标识符,该私钥由刻录在验证器中的对称密钥包裹。
[[clientExtensionsResults]]-
此内部槽包含依赖方在调用
navigator.credentials.create()或navigator.credentials.get()时,处理请求的客户端扩展的结果。
PublicKeyCredential 的接口对象继承 Credential 对 [[CollectFromCredentialStore]](origin, options, sameOriginWithAncestors) 的实现,并定义了自己的 [[Create]](origin, options, sameOriginWithAncestors)、[[DiscoverFromExternalSource]](origin, options, sameOriginWithAncestors) 和 [[Store]](credential, sameOriginWithAncestors) 实现。
5.1.1. CredentialCreationOptions 字典扩展
为支持通过 navigator.credentials.create() 进行注册,本文档对 CredentialCreationOptions 字典进行了如下扩展:
partial dictionary CredentialCreationOptions {PublicKeyCredentialCreationOptions ; };publicKey
5.1.2. CredentialRequestOptions 字典扩展
为支持通过 navigator.credentials.get() 获取断言,本文档对 CredentialRequestOptions 字典进行了如下扩展:
partial dictionary CredentialRequestOptions {PublicKeyCredentialRequestOptions ; };publicKey
5.1.3. 创建新凭据 - PublicKeyCredential 的 [[Create]](origin, options, sameOriginWithAncestors) 方法
PublicKeyCredential 的接口对象对 [[Create]](origin, options, sameOriginWithAncestors) 内部方法 [CREDENTIAL-MANAGEMENT-1] 的实现,允许 WebAuthn 依赖方脚本调用 navigator.credentials.create() 以请求创建新的公钥凭据源,并将其绑定到验证器。此 navigator.credentials.create() 操作可以利用 AbortController 中止;有关详细说明,请参阅 DOM §3.3 在 API 中使用 AbortController 和 AbortSignal 对象。此内部方法接收三个参数:
originoptions-
此参数是一个
CredentialCreationOptions对象,其options.成员包含一个publicKeyPublicKeyCredentialCreationOptions对象,用于指定待创建公钥凭据的所需属性。 sameOriginWithAncestors-
此参数是一个布尔值,当且仅当调用者的环境设置对象与其祖先同源时,其值为
true。如果调用者是跨源的,则为false。注意: 调用此内部方法表示它已获得权限策略的许可,该策略在 [CREDENTIAL-MANAGEMENT-1] 层级进行评估。请参阅 § 5.9 权限策略集成。
注意: 此算法是同步的: Promise 的解析/拒绝由 navigator.credentials.create() 处理。
注意: 此算法中使用的所有 BufferSource 对象必须在算法开始时进行快照,以避免潜在的同步问题。算法实现应获取由缓冲区源持有的字节副本,并使用该副本进行算法的相关部分。
当调用此方法时,用户代理必须执行以下算法:
-
断言:
options.存在。publicKey -
如果 sameOriginWithAncestors 为
false,则返回 "NotAllowedError"DOMException。注意: 此 "sameOriginWithAncestors" 限制旨在解决在 Issue #1336 中提出的跟踪问题。这可能会在本规范的未来版本中进行修订。
-
令 options 为
options.的值。publicKey -
如果 options 的
timeout成员存在,检查其值是否在客户端定义的合理范围内,如果不在,将其修正为该范围内最接近的值。设置一个计时器 lifetimeTimer 为此调整后的值。如果 options 的timeout成员不存在,则将 lifetimeTimer 设置为客户端特定的默认值。options 的
timeout成员的推荐范围和默认值如下。如果options.authenticatorSelection.userVerification- 被设置为
discouraged -
推荐范围:30000 毫秒至 180000 毫秒。
-
推荐默认值:120000 毫秒(2 分钟)。
- 被设置为
required或preferred -
推荐范围:30000 毫秒至 600000 毫秒。
-
推荐默认值:300000 毫秒(5 分钟)。
注意: 用户代理在考虑有特殊需求用户的超时设置时,应参考认知指南。
- 被设置为
-
令 callerOrigin 为
origin。如果 callerOrigin 是一个不透明源,则返回一个名为 "NotAllowedError" 的DOMException,并终止此算法。 -
令 effectiveDomain 为 callerOrigin 的有效域名。如果有效域名不是一个有效域名,则返回一个名为 "
SecurityError" 的DOMException并终止此算法。注意: 有效域名可能解析为一个主机,它可以通过多种方式表示,例如域名、IPv4 地址、IPv6 地址、不透明主机或空主机。此处仅允许域名格式的主机。这是为了简化,也是为了认识到将直接 IP 地址标识与基于 PKI 的安全结合使用时存在的各种问题。
-
- 存在
-
如果
options.既不是 effectiveDomain 的可注册域名后缀,也不与之相等,则返回一个名为 "rp.idSecurityError" 的DOMException,并终止此算法。 - 不存在
注意:
options.代表调用者的RP ID。RP ID 默认为调用者的源的有效域名,除非调用者在调用rp.idcreate()时明确设置了options.。rp.id -
令 credTypesAndPubKeyAlgs 为一个新的列表,其项为
PublicKeyCredentialType和COSEAlgorithmIdentifier的配对。 -
如果
options.的大小pubKeyCredParams- 为零
-
追加以下
PublicKeyCredentialType和COSEAlgorithmIdentifier值对到 credTypesAndPubKeyAlgs:-
public-key和-7("ES256")。 -
public-key和-257("RS256")。
-
- 非零
-
对于每个
options.中的 currentpubKeyCredParams-
如果
current.不包含本实现支持的typePublicKeyCredentialType,则继续。 -
令 alg 为
current.。alg
如果 credTypesAndPubKeyAlgs 为空,则返回一个名为 "
NotSupportedError" 的DOMException,并终止此算法。 -
-
令 clientExtensions 为一个新的映射 (map),令 authenticatorExtensions 为一个新的映射 (map)。
-
如果 options 的
extensions成员存在,则对于每个options.中的 extensionId → clientExtensionInputextensions-
将 clientExtensions[extensionId] 设置为 clientExtensionInput。
-
如果 extensionId 不是一个验证器扩展 (authenticator extension),则跳过并继续。
-
令 authenticatorExtensionInput 为对 clientExtensionInput 执行 extensionId 的客户端扩展处理算法后的 (CBOR) 结果。如果算法返回错误,则跳过并继续。
-
设置 authenticatorExtensions[extensionId] 为 authenticatorExtensionInput 的base64url 编码。
-
令 collectedClientData 为一个新的
CollectedClientData实例,其字段为type-
字符串 "webauthn.create"。
challenge (挑战)-
options.
challenge的base64url 编码。 origin-
callerOrigin 的序列化。
crossOrigin-
传递给此内部方法的
sameOriginWithAncestors参数值的反值。 tokenBinding-
客户端与 callerOrigin 之间的令牌绑定状态,以及与 callerOrigin 关联的令牌绑定 ID(如果可用)。
-
令 clientDataJSON 为由 collectedClientData 构建的客户端数据的 JSON 兼容序列化。
-
令 clientDataHash 为 clientDataJSON 所代表的序列化客户端数据的哈希值。
-
如果
options.存在且其中止标志被设置为signaltrue,则返回一个名为 "AbortError" 的DOMException并终止此算法。 -
令 issuedRequests 为一个新的有序集合。
-
令 authenticators 表示一个值,该值在任何瞬间都是客户端平台特定句柄的集合,其中每个项标识了在该瞬间当前可用于此客户端平台上的验证器。
注意: 何谓“可用”验证器并未指定;这旨在表示验证器如何通过各种机制(例如通过 USB 热插拔,或通过 NFC 或蓝牙发现)被客户端发现,或者永久内置于客户端中。
-
启动 lifetimeTimer。
-
当 lifetimeTimer 未过期时,根据 lifetimeTimer,以及 authenticators 中每个 authenticator 的状态和响应,执行以下操作:
- 如果 lifetimeTimer 过期:
-
对于 issuedRequests 中的每个 authenticator,在 authenticator 上调用 authenticatorCancel 操作,并将 authenticator 从 issuedRequests 中移除。
- 如果用户通过用户代理界面选项取消了该过程:
-
对于每个 issuedRequests 中的 authenticator,调用其 authenticatorCancel 操作,并从 issuedRequests 中移除该 authenticator。返回一个名为 "
NotAllowedError" 的DOMException。 - 如果
options.存在且其中止标志被设置为signaltrue, -
对于每个 issuedRequests 中的 authenticator,调用其 authenticatorCancel 操作,并从 issuedRequests 中移除该 authenticator。然后返回一个名为 "
AbortError" 的DOMException并终止此算法。 - 如果一个 authenticator 在此客户端设备上变得可用,
-
注意: 这包括 authenticator 在 lifetimeTimer 初始化时已可用的情况。
-
该 authenticator 现在是候选验证器。
-
如果
options.存在authenticatorSelection-
如果
options.存在且其值不等于 authenticator 的验证器附件模式,则继续。authenticatorSelection.authenticatorAttachment -
如果
options.authenticatorSelection.residentKey- 存在并被设置为
required -
如果该 authenticator 没有能力存储客户端可发现的公钥凭据源,则继续。
- 存在并被设置为
preferred或discouraged -
无影响。
- 不存在
-
如果
options.被设置为authenticatorSelection.requireResidentKeytrue且该 authenticator 没有能力存储客户端可发现的公钥凭据源,则继续。
- 存在并被设置为
-
如果
options.被设置为authenticatorSelection.userVerificationrequired且该 authenticator 没有能力进行用户验证,则继续。
-
-
令 requireResidentKey 为凭据创建的有效驻留密钥要求,一个布尔值,具体如下:
如果
options.authenticatorSelection.residentKey- 存在并被设置为
required -
令 requireResidentKey 为
true。 - 存在并被设置为
preferred -
如果该 authenticator
- 存在并设置为
discouraged -
令 requireResidentKey 为
false。 - 不存在
-
令 requireResidentKey 为
options.的值。authenticatorSelection.requireResidentKey
- 存在并被设置为
-
令 userVerification 为下述的凭据创建的有效用户验证要求(一个布尔值)。如果
options.authenticatorSelection.userVerification- 被设置为
required -
令 userVerification 为
true。 - 设置为
preferred -
如果该 authenticator
- 设置为
discouraged -
令 userVerification 为
false。
- 被设置为
-
令 enterpriseAttestationPossible 为一个布尔值,如下所示。如果
options.attestation- 被设置为
enterprise -
如果用户代理希望为
options.支持企业级证明(enterprise attestation),则令 enterpriseAttestationPossible 为rp.idtrue(见上述 第 8 步)。否则为false。 - 否则
-
令 enterpriseAttestationPossible 为
false。
- 被设置为
-
令 excludeCredentialDescriptorList 为一个新的列表。
-
对于
options.中的每个凭据描述符 CexcludeCredentials-
如果
C.不为空,且 authenticator 通过transportsC.中未提及的传输方式连接,则客户端可以 继续。transports注意: 如果客户端选择 继续,如果
C.中的传输提示不准确,可能会导致无意中注册多个 绑定到 同一个 身份验证器 的凭据。例如,由于软件升级增加了新的连接选项,已存储的传输提示可能会变得不准确。transports -
否则,将 C 追加到 excludeCredentialDescriptorList。
-
在 authenticator 上调用 authenticatorMakeCredential 操作,参数包括 clientDataHash、
options.、rpoptions.、requireResidentKey、userVerification、credTypesAndPubKeyAlgs、excludeCredentialDescriptorList、enterpriseAttestationPossible 和 authenticatorExtensions。user
-
-
将 authenticator 追加到 issuedRequests。
-
- 如果 authenticator 在此 客户端设备 上变得不可用,
-
将 authenticator 从 issuedRequests 中移除。
- 如果任何 authenticator 返回的状态表明用户取消了操作:
-
-
将 authenticator 从 issuedRequests 中移除。
-
对于 issuedRequests 中剩余的每个 authenticator,调用 authenticatorCancel 操作,并将其从 issuedRequests 中移除。
注意: 身份验证器 可能会返回“用户取消了整个操作”的指示。用户代理如何向用户展示此状态未作指定。
-
- 如果任何 authenticator 返回等同于 "
InvalidStateError" 的错误状态, -
-
将 authenticator 从 issuedRequests 中移除。
-
对于 issuedRequests 中剩余的每个 authenticator,调用 authenticatorCancel 操作,并将其从 issuedRequests 中移除。
-
返回一个名称为 "
InvalidStateError" 的DOMException并终止此算法。
注意: 此错误状态被单独处理,因为 authenticator 仅在 excludeCredentialDescriptorList 标识了一个 绑定到 该 authenticator 的凭据且用户已 同意 操作时才会返回它。鉴于这种明确的同意,对于 信赖方 而言,能够区分这种情况是可以接受的。
-
- 如果任何 authenticator 返回不等同于 "
InvalidStateError" 的错误状态, -
将 authenticator 从 issuedRequests 中移除。
注意: 此情况并不暗示用户已 同意 该操作,因此错误详情对 信赖方 是隐藏的,以防止泄露潜在的识别信息。详情请参阅 § 14.5.1 注册仪式隐私。
- 如果任何 authenticator 表明成功:
-
-
从 issuedRequests 中移除 authenticator。该身份验证器现在是 选定的身份验证器。
-
令 credentialCreationData 为一个 结构体,其 项 为
attestationObjectResult (鉴证对象结果)-
其值为成功的 authenticatorMakeCredential 操作所返回的字节。
注意: 该值是
attObj,定义见 § 6.5.4 生成证明对象。 clientDataJSONResult (客户端数据 JSON 结果)-
其值为 clientDataJSON 的字节。
attestationConveyancePreferenceOption (鉴证传送偏好选项)-
其值为 options.
attestation的值。 clientExtensionResults (客户端扩展结果)-
其值为一个包含 扩展标识符 → 客户端扩展输出 条目的
AuthenticationExtensionsClientOutputs对象。这些条目是通过为options.中的每个 客户端扩展 运行其 客户端扩展处理 算法来创建的,以生成 客户端扩展输出。extensions
-
令 constructCredentialAlg 为一个算法,它接收一个全局对象 (global object) global,其步骤如下:
-
如果
credentialCreationData.attestationConveyancePreferenceOption的值是:- "none" (无)
-
将潜在的唯一标识信息替换为同类信息的非标识版本:
-
如果 已认证凭据数据 中的 AAGUID 为 16 个零字节,
credentialCreationData.attestationObjectResult.fmt为 "packed",且credentialCreationData.attestationObjectResult中不存在 "x5c",则正在使用 自证明,无需进一步操作。 -
否则
-
将
credentialCreationData.attestationObjectResult.fmt的值设置为 "none",并将credentialCreationData.attestationObjectResult.attStmt的值设置为一个空的 CBOR 映射。(见 § 8.7 None 证明语句格式 和 § 6.5.4 生成证明对象)。
-
- "indirect"
- "direct" 或 "enterprise"
-
令 attestationObject 为一个新的
ArrayBuffer,使用 global 的 %ArrayBuffer% 创建,其中包含credentialCreationData.attestationObjectResult的值字节。 -
令 id 为
attestationObject.authData.attestedCredentialData.credentialId。 -
令 pubKeyCred 为一个新的与 global 关联的
PublicKeyCredential对象,其字段为[[identifier]]-
id
response (响应)-
一个新的与 global 关联的
AuthenticatorAttestationResponse对象,其字段为:clientDataJSON (客户端数据 JSON)-
一个新的
ArrayBuffer,使用 global 的 %ArrayBuffer% 创建,其中包含credentialCreationData.clientDataJSONResult的字节。 attestationObject (鉴证对象)-
attestationObject (鉴证对象)
[[transports]]-
零个或多个唯一的
DOMString序列(按字典顺序排列),据信该 authenticator 支持这些传输方式。这些值应当是AuthenticatorTransport的成员,但 客户端平台 必须忽略未知值。如果用户代理不希望泄露此信息,它可以替换为一个旨在保护隐私的任意序列。此序列必须仍然有效,即按字典顺序排序且无重复。例如,它可以使用空序列。无论哪种情况,在这种情况下,用户代理都承担 信赖方 行为可能不是最佳的风险。
如果用户代理没有任何传输信息,它应当将此字段设置为空序列。
注意: 用户代理如何发现给定的 身份验证器 所支持的传输方式超出了本规范的范围,但可能包括来自 证明证书 的信息(例如 [FIDO-Transports-Ext])、在 身份验证器 协议(如 CTAP2)中传达的元数据,或关于 平台身份验证器 的特例知识。
[[clientExtensionsResults]]-
一个新的
ArrayBuffer,使用 global 的 %ArrayBuffer% 创建,其中包含credentialCreationData.clientExtensionResults的字节。
-
返回 pubKeyCred。
-
-
对于 issuedRequests 中剩余的每个 authenticator,调用 authenticatorCancel 操作,并将其从 issuedRequests 中移除。
-
返回 constructCredentialAlg 并终止此算法。
-
-
返回一个名称为 "
NotAllowedError" 的DOMException。为了防止在没有 同意 的情况下泄露可能识别用户的信息,此步骤不得在 lifetimeTimer 到期之前执行。详情请参阅 § 14.5.1 注册仪式隐私。
在上述过程中,用户代理应当向用户显示一些 UI,以指导他们完成选择和授权身份验证器的过程。
5.1.4. 使用现有凭据进行断言 - PublicKeyCredential 的 [[Get]](options) 方法
WebAuthn 信赖方 调用 navigator.credentials.get({publicKey:..., ...}) 以发现并使用现有的 公钥凭据,并获得 用户的同意。信赖方 脚本可选择指定一些准则,以指示哪些 凭据来源 是其可接受的。客户端平台 定位符合指定准则的 凭据来源,并引导用户选择一个脚本允许使用的凭据。用户可以选择拒绝整个交互,即使存在 凭据来源,例如为了保持隐私。如果用户选择了 凭据来源,用户代理随后使用 § 6.3.3 The authenticatorGetAssertion 操作 对 信赖方 提供的挑战和其他收集的数据进行签名,并将其转换为断言,作为 凭据 使用。
get() 实现 [CREDENTIAL-MANAGEMENT-1] 调用 PublicKeyCredential. 来收集任何无需 用户中介(大致为本规范的 授权手势)即可使用的 凭据;如果没有找到其中确切的一个,它会随后调用 [[CollectFromCredentialStore]]()PublicKeyCredential. 让用户选择一个 凭据来源。[[DiscoverFromExternalSource]]()
由于本规范要求 授权手势 才能创建任何 凭据,PublicKeyCredential. 内部方法 继承了 [[CollectFromCredentialStore]](origin, options, sameOriginWithAncestors)Credential.[[CollectFromCredentialStore]]() 的默认行为,即返回空集。
此 navigator.credentials.get() 操作可以通过利用 AbortController 中止;有关详细说明,请参阅 DOM §3.3 在 API 中使用 AbortController 和 AbortSignal 对象。
5.1.4.1. PublicKeyCredential 的 [[DiscoverFromExternalSource]](origin, options, sameOriginWithAncestors) 方法
[[DiscoverFromExternalSource]](origin, options, sameOriginWithAncestors)此 内部方法 接受三个参数
origin-
此参数是 相关设置对象 的 源(origin),由调用的
get()实现确定,即CredentialsContainer的 请求Credential抽象操作。 options-
此参数是一个
CredentialRequestOptions对象,其options.成员包含一个publicKeyPublicKeyCredentialRequestOptions对象,指定了要发现的 公钥凭据 的期望属性。 sameOriginWithAncestors-
此参数是一个布尔值,当且仅当调用者的 环境设置对象 与其 祖先同源 时为
true。如果调用者是跨源的,则为false。注意: 此 内部方法 的调用表明它已获得 权限策略 的允许,该策略在 [CREDENTIAL-MANAGEMENT-1] 层面进行评估。请参阅 § 5.9 权限策略集成。
注意: 此算法是同步的:Promise 的解析/拒绝由 navigator.credentials.get() 处理。
注意: 在此算法中使用的所有 BufferSource 对象必须在算法开始时进行快照,以避免潜在的同步问题。算法实现应当 获取缓冲区源所持有的字节的副本,并将其用于算法的相关部分。
当调用此方法时,用户代理必须执行以下算法:
-
断言:
options.存在。publicKey -
令 options 为
options.的值。publicKey -
如果 options 的
timeout成员存在,检查其值是否在 客户端 定义的合理范围内,如果不在,将其修正为该范围内最接近的值。将定时器 lifetimeTimer 设置为该调整后的值。如果 options 的timeout成员不存在,则将 lifetimeTimer 设置为 客户端 特定的默认值。options 的
timeout成员的推荐范围和默认值如下。如果options.userVerification- 被设置为
discouraged -
推荐范围:30000 毫秒至 180000 毫秒。
-
推荐默认值:120000 毫秒(2 分钟)。
- 被设置为
required或preferred -
推荐范围:30000 毫秒至 600000 毫秒。
-
推荐默认值:300000 毫秒(5 分钟)。
注意: 用户代理在考虑有特殊需求用户的超时设置时,应参考认知指南。
- 被设置为
-
令 callerOrigin 为
origin。如果 callerOrigin 是一个 不透明源,则返回一个名称为 "NotAllowedError" 的DOMException,并终止此算法。 -
令 effectiveDomain 为 callerOrigin 的 有效域(effective domain)。如果 有效域 不是一个 有效域,则返回一个名称为 "
SecurityError" 的DOMException并终止此算法。注意: 有效域 可以解析为 主机(host),可以以多种方式表示,例如 域、ipv4 地址、ipv6 地址、不透明主机 或 空主机。此处仅允许 主机 的 域 格式。这是为了简化,同时也考虑到在结合基于 PKI 的安全性使用直接 IP 地址识别时出现的各种问题。
-
如果 options.
rpId不存在,则将 rpId 设置为 effectiveDomain。否则
-
如果 options.
rpId不是 effectiveDomain 的可注册域后缀且不等于 effectiveDomain,则返回一个名称为 "SecurityError" 的DOMException,并终止此算法。 -
将 rpId 设置为 options.
rpId。注意: rpId 代表调用者的 RP ID。RP ID 默认为调用者的 源(origin) 的 有效域,除非调用者在调用
get()时明确设置了 options.rpId。
-
-
令 clientExtensions 为一个新的映射,令 authenticatorExtensions 为一个新的映射。
-
如果 options 的
extensions成员存在,则 对于options.中的每个 extensionId → clientExtensionInputextensions -
令 collectedClientData 为一个新的
CollectedClientData实例,其字段为:type-
字符串 "webauthn.get"。
challenge (挑战)-
options.
challenge的 base64url 编码 origin-
callerOrigin 的 序列化。
crossOrigin-
传递给此 内部方法 的
sameOriginWithAncestors参数值的倒数。 tokenBinding-
客户端与 callerOrigin 之间的 令牌绑定(Token Binding) 状态,以及如果可用,与 callerOrigin 关联的 令牌绑定 ID。
-
令 clientDataJSON 为从 collectedClientData 构建的 客户端数据的 JSON 兼容序列化。
-
令 clientDataHash 为 clientDataJSON 所代表的序列化客户端数据的哈希值。
-
如果
options.存在且其 已中止标志(aborted flag) 设置为signaltrue,则返回一个名称为 "AbortError" 的DOMException并终止此算法。 -
令 issuedRequests 为一个新的有序集合。
-
令 savedCredentialIds 为一个新的映射。
-
令 authenticators 代表一个在任何给定瞬间都是 客户端平台 特定句柄的 集合 的值,其中每个 项 标识该瞬间在此 客户端平台 上当前可用的 身份验证器。
注意: 什么条件使得 身份验证器 成为“可用”是有意未指定的;这意味着要表示 身份验证器 如何可以通过各种机制(例如通过 USB) 热插拔 到 客户端,或被其发现(例如通过 NFC 或蓝牙),或者永久内置于 客户端 中。
-
启动 lifetimeTimer。
-
当 lifetimeTimer 未过期时,根据 lifetimeTimer 的状态,以及 authenticators 中每个 authenticator 的状态和响应执行以下操作:
- 如果 lifetimeTimer 过期:
-
对于 issuedRequests 中的每个 authenticator,调用 authenticatorCancel 操作,并从 issuedRequests 中移除 authenticator。
- 如果用户通过用户代理界面选项取消了该过程:
-
对于 issuedRequests 中的每个 authenticator,在 authenticator 上调用 authenticatorCancel 操作并 从 issuedRequests 中移除 authenticator。返回一个名称为 "
NotAllowedError" 的DOMException。 - 如果
signal成员存在且 已中止标志 设置为true, -
对于 issuedRequests 中的每个 authenticator,在 authenticator 上调用 authenticatorCancel 操作并 从 issuedRequests 中移除 authenticator。然后返回一个名称为 "
AbortError" 的DOMException并终止此算法。 - 如果 issuedRequests 为空,
options.不为空,且其中没有任何 公钥凭据 所需的 authenticator 会变得可用,allowCredentials -
向用户指示找不到符合条件的凭据。当用户确认对话框时,返回一个名称为 "
NotAllowedError" 的DOMException。注意: 客户端平台 确定没有 authenticator 会变得可用的一种方法是检查
options.中存在的allowCredentials项 的PublicKeyCredentialDescriptor成员(如果有)。例如,如果所有transports项 都仅列出PublicKeyCredentialDescriptor,但已尝试了所有 平台 authenticator,则无法满足该请求。或者,所有internal项 可能列出了 客户端平台 不支持的PublicKeyCredentialDescriptor。transports - 如果 authenticator 在此 客户端设备 上变得可用,
-
注意: 这包括 authenticator 在 lifetimeTimer 初始化时已可用的情况。
-
如果
options.被设置为userVerificationrequired且 authenticator 不具备执行 用户验证 的能力,则 继续。 -
令 userVerification 为下述的断言的有效用户验证要求(一个布尔值)。如果
options.userVerification- 被设置为
required -
令 userVerification 为
true。 - 被设置为
preferred -
如果该 authenticator
- 被设置为
discouraged -
令 userVerification 为
false。
- 被设置为
-
如果
options.allowCredentials- 不为空
-
-
令 allowCredentialDescriptorList 为一个新的 列表。
-
执行一个 客户端平台 特定的程序,通过匹配 rpId、
options.和allowCredentials.idoptions.,确定allowCredentials.typeoptions.所描述的哪些 公钥凭据(如果有)绑定 到此 authenticator。将 allowCredentialDescriptorList 设置为该筛选后的列表。allowCredentials -
令 distinctTransports 为一个新的有序集合。
-
如果 allowCredentialDescriptorList 恰好有一个值,将
savedCredentialIds[authenticator]设置为allowCredentialDescriptorList[0].id的值(有关更多信息,请参阅 § 6.3.3 The authenticatorGetAssertion 操作 中的 此处)。 -
对于 allowCredentialDescriptorList 中的每个凭据描述符 C,追加
C.的每个值(如果有)到 distinctTransports。transports注意: 由于 有序集合 的属性,这只会将 distinctTransports 中该 身份验证器 的唯一
transports值聚合在一起。 -
如果 distinctTransports
- 不为空
-
客户端从 distinctTransports 中选择一个 transport 值,在进行选择时可能会结合本地关于与该 authenticator 配合使用的适当传输方式的配置知识。
然后,使用 transport,在 authenticator 上调用 authenticatorGetAssertion 操作,参数包括 rpId、clientDataHash、allowCredentialDescriptorList、userVerification 和 authenticatorExtensions。
- 为空
-
使用关于与 authenticator 一起使用的适当传输方式的本地配置知识,在 authenticator 上调用 authenticatorGetAssertion 操作,参数包括 rpId、clientDataHash、allowCredentialDescriptorList、userVerification 和 authenticatorExtensions。
-
- 为空
-
使用关于与 authenticator 一起使用的适当传输方式的本地配置知识,在 authenticator 上调用 authenticatorGetAssertion 操作,参数包括 rpId、clientDataHash、userVerification 和 authenticatorExtensions。
注意: 在这种情况下,信赖方 没有提供可接受凭据描述符的列表。因此,身份验证器被要求行使其可能拥有的且 作用域 为 rpId 所标识的 信赖方 的任何凭据。
-
将 authenticator 追加到 issuedRequests。
-
- 如果 authenticator 在此 客户端设备 上变得不可用,
-
将 authenticator 从 issuedRequests 中移除。
- 如果任何 authenticator 返回的状态表明用户取消了操作:
-
-
将 authenticator 从 issuedRequests 中移除。
-
对于 issuedRequests 中剩余的每个 authenticator,调用 authenticatorCancel 操作,并将其从 issuedRequests 中移除。
注意: 身份验证器 可能会返回“用户取消了整个操作”的指示。用户代理如何向用户展示此状态未作指定。
-
- 如果任何 authenticator 返回错误状态:
-
将 authenticator 从 issuedRequests 中移除。
- 如果任何 authenticator 表明成功:
-
-
将 authenticator 从 issuedRequests 中移除。
-
令 assertionCreationData 为一个 结构体,其 项 为
credentialIdResult-
如果
savedCredentialIds[authenticator]存在,将 credentialIdResult 的值设置为savedCredentialIds[authenticator]的字节。否则,将 credentialIdResult 的值设置为成功的 authenticatorGetAssertion 操作所返回的 凭据 ID 的字节,定义见 § 6.3.3 The authenticatorGetAssertion 操作。 clientDataJSONResult (客户端数据 JSON 结果)-
其值为 clientDataJSON 的字节。
authenticatorDataResultsignatureResult-
其值为 身份验证器 返回的签名值的字节。
userHandleResult-
如果 身份验证器 返回了一个 用户句柄,将 userHandleResult 的值设置为返回的 用户句柄 的字节。否则,将 userHandleResult 的值设置为 null。
clientExtensionResults (客户端扩展结果)-
其值为一个包含 扩展标识符 → 客户端扩展输出 条目的
AuthenticationExtensionsClientOutputs对象。这些条目是通过为options.中的每个 客户端扩展 运行其 客户端扩展处理 算法来创建的,以生成 客户端扩展输出。extensions
-
令 constructAssertionAlg 为一个接收 全局对象 global 的算法,其步骤为
-
令 pubKeyCred 为一个新的与 global 关联的
PublicKeyCredential对象,其字段为[[identifier]]-
一个新的
ArrayBuffer,使用 global 的 %ArrayBuffer% 创建,其中包含assertionCreationData.credentialIdResult的字节。 response (响应)-
一个新的与 global 关联的
AuthenticatorAssertionResponse对象,其字段如下:clientDataJSON (客户端数据 JSON)-
一个新的
ArrayBuffer,使用 global 的 %ArrayBuffer% 创建,其中包含assertionCreationData.clientDataJSONResult的字节。 authenticatorData-
一个新的
ArrayBuffer,使用 global 的 %ArrayBuffer% 创建,其中包含assertionCreationData.authenticatorDataResult的字节。 signature-
一个新的
ArrayBuffer,使用 global 的 %ArrayBuffer% 创建,其中包含assertionCreationData.signatureResult的字节。 userHandle-
如果
assertionCreationData.userHandleResult为 null,将此字段设置为 null。否则,将此字段设置为一个新的ArrayBuffer,使用 global 的 %ArrayBuffer% 创建,其中包含assertionCreationData.userHandleResult的字节。
[[clientExtensionsResults]]-
一个新的
ArrayBuffer,使用 global 的 %ArrayBuffer% 创建,其中包含assertionCreationData.clientExtensionResults的字节。
-
返回 pubKeyCred。
-
-
对于 issuedRequests 中剩余的每个 authenticator,在 authenticator 上调用 authenticatorCancel 操作,并将其从 issuedRequests 中 移除。
-
返回 constructAssertionAlg 并终止此算法。
-
-
返回一个名称为 "
NotAllowedError" 的DOMException。为了防止在没有 同意 的情况下泄露可能识别用户的信息,此步骤不得在 lifetimeTimer 到期之前执行。详情请参阅 § 14.5.2 认证仪式隐私。
在上述过程中,用户代理应当向用户显示一些 UI,以指导他们完成选择和授权身份验证器的过程,从而完成该操作。
5.1.5. 存储现有凭据 - PublicKeyCredential 的 [[Store]](credential, sameOriginWithAncestors) 方法
[[Store]](credential, sameOriginWithAncestors) 方法不支持 Web Authentication 的 PublicKeyCredential 类型,因此它总是返回一个错误。
注意: 此算法是同步的;Promise 的解析/拒绝由 navigator.credentials.store() 处理。
此 内部方法 接受两个参数
credential-
此参数是一个
PublicKeyCredential对象。 sameOriginWithAncestors
当调用此方法时,用户代理必须执行以下算法:
-
返回一个名称为 "
NotSupportedError" 的DOMException,并终止此算法
5.1.6. 防止对现有凭据的静默访问 - PublicKeyCredential 的 [[preventSilentAccess]](credential, sameOriginWithAncestors) 方法
调用 [[preventSilentAccess]](credential, sameOriginWithAncestors) 方法对于需要 授权手势 的身份验证器没有影响,但设置该标志可能会排除那些可以在无需用户干预的情况下操作的身份验证器。
此 内部方法 不接受任何参数。
5.1.7. 用户验证平台身份验证器的可用性 - PublicKeyCredential 的 isUserVerifyingPlatformAuthenticatorAvailable() 方法
WebAuthn 信赖方 使用此方法确定它们是否可以使用 用户验证平台身份验证器 创建新凭据。调用时,客户端 采用 客户端平台 特定的程序来发现可用的 用户验证平台身份验证器。如果发现任何身份验证器,promise 将以 true 值解析。否则,promise 将以 false 值解析。根据结果,信赖方 可以采取进一步行动来指导用户创建凭据。
此方法没有参数,并返回一个布尔值。
PublicKeyCredential/isUserVerifyingPlatformAuthenticatorAvailable
在所有当前引擎中。
Opera无Edge79+
Edge (旧版)18IE无
Firefox for Android60+iOS Safari13.3+Chrome for Android70+Android WebView70+Samsung Internet无Opera Mobile无
partial interface PublicKeyCredential {static Promise <boolean >(); };isUserVerifyingPlatformAuthenticatorAvailable
注意: 在根据 allowed to use 算法——即通过 权限策略——Web Authentication API 被“禁用”的 浏览上下文 中调用此方法,将导致 promise 被拒绝,返回一个名称为 "NotAllowedError" 的 DOMException。另请参阅 § 5.9 权限策略集成。
5.2. 验证器响应(接口 AuthenticatorResponse)
在所有当前引擎中。
Opera无Edge79+
Edge (旧版)18IE无
Firefox for Android60+iOS Safari13.3+Chrome for Android70+Android WebView70+Samsung Internet无Opera Mobile无
身份验证器 通过返回一个派生自 AuthenticatorResponse 接口的对象来响应 信赖方 请求
[SecureContext ,Exposed =Window ]interface AuthenticatorResponse { [SameObject ]readonly attribute ArrayBuffer clientDataJSON ; };
-
AuthenticatorResponse/clientDataJSON
在所有当前引擎中。
Firefox60+Safari13+Chrome67+
Opera无Edge79+
Edge (旧版)18IE无
Firefox for Android60+iOS Safari13.3+Chrome for Android70+Android WebView70+Samsung Internet无Opera Mobile无clientDataJSON, 类型为 ArrayBuffer,只读 -
此属性包含 客户端数据 的 JSON 兼容序列化,其 哈希值 由客户端在调用
create()或get()时传递给身份验证器(即 客户端数据 本身不会发送给身份验证器)。
5.2.1. 关于公钥凭据的信息(接口 AuthenticatorAttestationResponse)
AuthenticatorAttestationResponse
在所有当前引擎中。
Opera无Edge79+
Edge (旧版)18IE无
Firefox for Android60+iOS Safari13.3+Chrome for Android70+Android WebView70+Samsung Internet10.0+Opera MobileNone
AuthenticatorAttestationResponse 接口表示 身份验证器 对客户端创建新 公钥凭据 请求的响应。它包含关于新凭据的信息(可用于后续使用时标识它),以及 WebAuthn 信赖方 在注册期间可用来评估凭据特征的元数据。
AuthenticatorAttestationResponse/getTransports
目前没有引擎支持。
OperaNoneEdgeNone
Edge (旧版)无IE无
Firefox for AndroidNoneiOS SafariNoneChrome for AndroidNoneAndroid WebViewNoneSamsung InternetNoneOpera MobileNone
[SecureContext ,Exposed =Window ]interface AuthenticatorAttestationResponse :AuthenticatorResponse { [SameObject ]readonly attribute ArrayBuffer attestationObject ;sequence <DOMString >();getTransports ArrayBuffer ();getAuthenticatorData ArrayBuffer ?();getPublicKey COSEAlgorithmIdentifier (); };getPublicKeyAlgorithm
clientDataJSON (客户端数据 JSON)-
此属性继承自
AuthenticatorResponse,包含为生成此凭据而由客户端传递给身份验证器的 客户端数据的 JSON 兼容序列化(见 § 6.5 证明)。确切的 JSON 序列化必须保留,因为 序列化客户端数据的哈希值 是在其上计算的。 -
AuthenticatorAttestationResponse/attestationObject
在所有当前引擎中。
Firefox60+Safari13+Chrome67+
Opera无Edge79+
Edge (旧版)18IE无
Firefox for Android60+iOS Safari13.3+Chrome for Android70+Android WebView70+Samsung Internet10.0+Opera MobileNoneattestationObject, 类型为 ArrayBuffer,只读 -
此属性包含一个 证明对象,该对象对客户端而言是不透明的,并且在加密上防止篡改。证明对象 同时包含 身份验证器数据 和 证明语句。前者包含 AAGUID、唯一的 凭据 ID 和 凭据公钥。证明语句 的内容由 身份验证器 使用的 证明语句格式 确定。它还包含 信赖方 服务器验证 证明语句 以及解码和验证 身份验证器数据 与 客户端数据的 JSON 兼容序列化 所需的任何附加信息。有关详细信息,请参阅 § 6.5 证明、§ 6.5.4 生成证明对象 和 图 6。
getTransports()-
此操作返回
[[transports]]的值。 getAuthenticatorData()-
此操作返回包含在
attestationObject中的 身份验证器数据。见 § 5.2.1.1 轻松访问凭据数据。 getPublicKey()-
此操作返回新凭据的 DER SubjectPublicKeyInfo,如果不可用,则返回 null。见 § 5.2.1.1 轻松访问凭据数据。
getPublicKeyAlgorithm()-
此操作返回新凭据的
COSEAlgorithmIdentifier。见 § 5.2.1.1 轻松访问凭据数据。 [[transports]]-
此 内部槽 包含零个或多个按字典顺序排列的唯一
DOMString。这些值是据信该 身份验证器 支持的传输方式,如果信息不可用,则为空序列。这些值应当是AuthenticatorTransport的成员,但 信赖方 必须忽略未知值。
5.2.1.1. 轻松访问凭据数据
[[Create]](origin, options, sameOriginWithAncestors) 方法的每个用户都需要解析并存储返回的 凭据公钥,以便验证未来的 身份验证断言。然而,凭据公钥 采用 [RFC8152] (COSE) 格式,位于 证明对象(由 AuthenticatorAttestationResponse.attestationObject 传达)内的 身份验证器数据 内的 已认证凭据数据 的 credentialPublicKey 成员中。信赖方 希望使用 证明 时,必须履行解析 attestationObject 并获取 凭据公钥 的工作,因为该公钥副本是 身份验证器 签署 的那一项。然而,许多有效的 WebAuthn 用例不需要 证明。对于这些用途,用户代理可以完成解析工作,直接公开 身份验证器数据,并将 凭据公钥 转换为更方便的格式。
getPublicKey() 操作因此将 凭据公钥 作为 SubjectPublicKeyInfo 返回。这个 ArrayBuffer 例如可以传递给 Java 的 java.security.spec.X509EncodedKeySpec、.NET 的 System.Security.Cryptography.ECDsa.ImportSubjectPublicKeyInfo 或 Go 的 crypto/x509.ParsePKIXPublicKey。
使用 getPublicKey() 确实有一些限制:通过使用 pubKeyCredParams,信赖方 可以与 身份验证器 协商使用用户代理可能无法理解的公钥算法。然而,如果 信赖方 这样做,用户代理将无法将生成的 凭据公钥 转换为 SubjectPublicKeyInfo 格式,并且 getPublicKey() 的返回值将为 null。
当 凭据公钥 具有以下 COSEAlgorithmIdentifier 值时,用户代理必须能够为 getPublicKey() 返回非 null 值:
SubjectPublicKeyInfo 不包含 COSE 公钥中包含的签名算法信息(例如使用哪种哈希函数)。为了提供此信息,getPublicKeyAlgorithm() 返回 凭据公钥 的 COSEAlgorithmIdentifier。
为了在许多情况下完全消除解析 CBOR 的需要,getAuthenticatorData() 从 attestationObject 返回 身份验证器数据。身份验证器数据 包含其他以二进制格式编码的字段。但是,不提供用于访问它们的辅助函数,因为 信赖方 在 获取断言 时已经需要提取这些字段。与签名验证 可选 的 凭据创建 相比,信赖方 应该始终验证来自断言的签名,因此必须从已签署的 身份验证器数据 中提取字段。在那里使用的相同函数也将在凭据创建期间使用。
注意: getPublicKey() 和 getAuthenticatorData() 仅在本规范的二级中添加。信赖方 在使用这些函数之前,应通过测试 'getPublicKey' in AuthenticatorAttestationResponse.prototype 的值来使用功能检测。要求该函数必须存在的 信赖方 可能无法与旧版用户代理互操作。
5.2.2. Web 身份验证断言(接口 AuthenticatorAssertionResponse)
AuthenticatorAssertionResponse
在所有当前引擎中。
Opera无Edge79+
Edge (旧版)18IE无
Firefox for Android60+iOS Safari13.3+Chrome for Android70+Android WebView70+Samsung Internet无Opera Mobile无
AuthenticatorAssertionResponse 接口表示 身份验证器 对客户端生成新 身份验证断言 请求的响应,该请求给定 WebAuthn 信赖方 的挑战和其知晓的可选凭据列表。此响应包含一个加密签名,证明拥有 凭据私钥,以及可选的用户对特定交易 同意 的证据。
[SecureContext ,Exposed =Window ]interface AuthenticatorAssertionResponse :AuthenticatorResponse { [SameObject ]readonly attribute ArrayBuffer authenticatorData ; [SameObject ]readonly attribute ArrayBuffer signature ; [SameObject ]readonly attribute ArrayBuffer ?userHandle ; };
clientDataJSON (客户端数据 JSON)-
此属性继承自
AuthenticatorResponse,包含为生成此断言而由客户端传递给身份验证器的 客户端数据的 JSON 兼容序列化(见 § 5.8.1 WebAuthn 签名中使用的客户端数据(字典 CollectedClientData))。确切的 JSON 序列化必须保留,因为 序列化客户端数据的哈希值 是在其上计算的。 -
AuthenticatorAssertionResponse/authenticatorData
在所有当前引擎中。
Firefox60+Safari13+Chrome67+
Opera无Edge79+
Edge (旧版)18IE无
Firefox for Android60+iOS Safari13.3+Chrome for Android70+Android WebView70+Samsung Internet无Opera Mobile无authenticatorData, 类型为 ArrayBuffer,只读 -
此属性包含身份验证器返回的 身份验证器数据。见 § 6.1 身份验证器数据。
-
AuthenticatorAssertionResponse/signature
在所有当前引擎中。
Firefox60+Safari13+Chrome67+
Opera无Edge79+
Edge (旧版)18IE无
Firefox for Android60+iOS Safari13.3+Chrome for Android70+Android WebView70+Samsung Internet无Opera Mobile无signature, 类型为 ArrayBuffer,只读 -
此属性包含从身份验证器返回的原始签名。见 § 6.3.3 The authenticatorGetAssertion 操作。
-
AuthenticatorAssertionResponse/userHandle
在所有当前引擎中。
Firefox60+Safari13+Chrome67+
Opera无Edge79+
Edge (旧版)18IE无
Firefox for Android60+iOS Safari13.3+Chrome for Android70+Android WebView70+Samsung Internet无Opera Mobile无userHandle, 类型为 ArrayBuffer,只读,可为空 -
此属性包含从身份验证器返回的 用户句柄;如果身份验证器未返回 用户句柄,则为 null。见 § 6.3.3 The authenticatorGetAssertion 操作。
5.3. 凭据生成的参数(字典 PublicKeyCredentialParameters)
dictionary PublicKeyCredentialParameters {required DOMString type ;required COSEAlgorithmIdentifier alg ; };
type, 类型为 DOMString-
此成员指定要创建的凭据类型。该值应当是
PublicKeyCredentialType的成员,但客户端平台必须忽略未知值,并忽略任何具有未知type的PublicKeyCredentialParameters。 alg, 类型为 COSEAlgorithmIdentifier-
此成员指定新生成的凭据将使用的加密签名算法,从而也指定了要生成的非对称密钥对类型,例如 RSA 或椭圆曲线。
注意:我们使用 "alg" 作为后一个成员名称,而不是完整拼写 "algorithm",因为它将被序列化到发往验证器的消息中,而该消息可能会通过低带宽链路传输。
5.4. 凭据创建选项(字典 PublicKeyCredentialCreationOptions)
PublicKeyCredentialCreationOptions
在所有当前引擎中。
Opera54+Edge79+
Edge (旧版)无IE无
Firefox for Android?iOS Safari13.3+Chrome for Android67+Android WebViewNoneSamsung InternetNoneOpera Mobile48+
dictionary PublicKeyCredentialCreationOptions {required PublicKeyCredentialRpEntity rp ;required PublicKeyCredentialUserEntity user ;required BufferSource challenge ;required sequence <PublicKeyCredentialParameters >pubKeyCredParams ;unsigned long timeout ;sequence <PublicKeyCredentialDescriptor >excludeCredentials = [];AuthenticatorSelectionCriteria authenticatorSelection ;DOMString attestation = "none";AuthenticationExtensionsClientInputs extensions ; };
-
PublicKeyCredentialCreationOptions/rp
在所有当前引擎中。
Firefox60+Safari13+Chrome67+
Opera54+Edge79+
Edge (旧版)无IE无
Firefox for Android?iOS Safari13.3+Chrome for Android67+Android WebViewNoneSamsung InternetNoneOpera Mobile48+rp, 类型为 PublicKeyCredentialRpEntity -
此成员包含有关负责该请求的信赖方 (Relying Party) 的数据。
其值的
name成员是必需的。更多详情,请参阅 § 5.4.1 公钥实体描述(字典 PublicKeyCredentialEntity)。其值的
id成员指定了凭据应作用于的 RP ID。如果省略,其值将为CredentialsContainer对象关联的相关设置对象的源 (origin) 的有效域 (effective domain)。更多详情,请参阅 § 5.4.2 凭据生成的信赖方参数(字典 PublicKeyCredentialRpEntity)。 -
PublicKeyCredentialCreationOptions/user
在所有当前引擎中。
Firefox60+Safari13+Chrome67+
Opera54+Edge79+
Edge (旧版)无IE无
Firefox for Android?iOS Safari13.3+Chrome for Android67+Android WebViewNoneSamsung InternetNoneOpera Mobile48+user, 类型为 PublicKeyCredentialUserEntity -
此成员包含有关信赖方 (Relying Party) 请求认证的用户账户的数据。
其值的
name、displayName和id成员是必需的。更多详情,请参阅 § 5.4.1 公钥实体描述(字典 PublicKeyCredentialEntity) 以及 § 5.4.3 凭据生成的用户账户参数(字典 PublicKeyCredentialUserEntity)。 -
PublicKeyCredentialCreationOptions/challenge
在所有当前引擎中。
Firefox60+Safari13+Chrome67+
Opera54+Edge79+
Edge (旧版)无IE无
Firefox for Android?iOS Safari13.3+Chrome for Android67+Android WebViewNoneSamsung InternetNoneOpera Mobile48+challenge, 类型为 BufferSource -
此成员包含一个挑战 (challenge),旨在用于生成新创建凭据的认证对象 (attestation object)。请参阅 § 13.4.3 加密挑战的安全注意事项。
-
PublicKeyCredentialCreationOptions/pubKeyCredParams
在所有当前引擎中。
Firefox60+Safari13+Chrome67+
Opera54+Edge79+
Edge (旧版)无IE无
Firefox for Android?iOS Safari13.3+Chrome for Android67+Android WebViewNoneSamsung InternetNoneOpera Mobile48+pubKeyCredParams, 类型为 sequence<PublicKeyCredentialParameters> -
此成员包含有关待创建凭据预期属性的信息。该序列按首选程度从高到低排序。客户端将尽最大努力创建其所能创建的最优先凭据。
-
PublicKeyCredentialCreationOptions/timeout
在所有当前引擎中。
Firefox60+Safari13+Chrome67+
Opera54+Edge79+
Edge (旧版)无IE无
Firefox for Android?iOS Safari13.3+Chrome for Android67+Android WebViewNoneSamsung InternetNoneOpera Mobile48+timeout, 类型为 unsigned long -
此成员指定调用者愿意等待操作完成的时间(以毫秒为单位)。这仅作为提示,且可能被客户端覆盖。
-
PublicKeyCredentialCreationOptions/excludeCredentials
在所有当前引擎中。
Firefox60+Safari13+Chrome67+
Opera54+Edge79+
Edge (旧版)无IE无
Firefox for Android?iOS Safari13.3+Chrome for Android67+Android WebViewNoneSamsung InternetNoneOpera Mobile48+excludeCredentials, 类型为 sequence<PublicKeyCredentialDescriptor>,默认值为[] -
此成员供希望限制在单个验证器上为同一账户创建多个凭据的信赖方 (Relying Party) 使用。如果新凭据即将在一个已包含此参数中枚举的某个凭据的验证器上创建,则要求客户端返回错误。
-
PublicKeyCredentialCreationOptions/authenticatorSelection
在所有当前引擎中。
Firefox60+Safari13+Chrome67+
Opera54+Edge79+
Edge (旧版)无IE无
Firefox for Android?iOS Safari13.3+Chrome for Android67+Android WebViewNoneSamsung InternetNoneOpera Mobile48+authenticatorSelection, 类型为 AuthenticatorSelectionCriteria -
此成员供希望选择合适的验证器来参与
create()操作的信赖方 (Relying Party) 使用。 -
PublicKeyCredentialCreationOptions/attestation
在所有当前引擎中。
Firefox60+Safari13+Chrome67+
Opera54+Edge79+
Edge (旧版)无IE无
Firefox for Android?iOS Safari13.3+Chrome for Android67+Android WebViewNoneSamsung InternetNoneOpera Mobile48+attestation, 类型为 DOMString,默认值为"none" -
此成员供希望表达其对认证传达 (attestation conveyance) 偏好的信赖方 (Relying Party) 使用。其值应当是
AttestationConveyancePreference的成员。客户端平台必须忽略未知值,将未知值视为如同成员不存在一样。其默认值为 "none"。 extensions, 类型为 AuthenticationExtensionsClientInputs-
此成员包含请求客户端和验证器执行额外处理的附加参数。例如,调用者可以要求仅使用具有特定能力的验证器来创建凭据,或者要求在认证对象中返回特定信息。一些扩展在 § 9 WebAuthn 扩展中定义;请查阅由 [RFC8809] 建立的 IANA “WebAuthn 扩展标识符”注册表 [IANA-WebAuthn-Registries],以获取已注册 WebAuthn 扩展的最新列表。
5.4.1. 公钥实体描述(字典 PublicKeyCredentialEntity)
PublicKeyCredentialEntity 字典描述了一个用户账户,或一个WebAuthn 信赖方 (WebAuthn Relying Party),公钥凭据分别与它们相关联或被作用于其中。
dictionary PublicKeyCredentialEntity {required DOMString name ; };
name, 类型为 DOMString-
实体的 易于人类理解 的名称。其功能取决于
PublicKeyCredentialEntity代表的内容:-
当被
PublicKeyCredentialRpEntity继承时,它是信赖方 (Relying Party) 的人类可读标识符,仅供显示。例如,“ACME Corporation”、“Wonderful Widgets, Inc.” 或 “ОАО Примертех”。-
信赖方 (Relying Party) 在设置
name的值或向用户显示该值时,应当按照 [RFC8266] 第 2.3 节针对 PRECIS FreeformClass 的 Nickname Profile [RFC8264] 执行强制性规范。 -
该字符串可能包含语言和方向元数据。信赖方 (Relying Party) 应考虑提供此信息。有关该元数据编码方式的说明,请参阅 § 6.4.2 语言和方向编码。
-
客户端在向用户显示
name的值或将其包含在 authenticatorMakeCredential 操作的参数中之前,应当按照 [RFC8266] 第 2.3 节针对 PRECIS FreeformClass 的 Nickname Profile [RFC8264] 执行强制性规范。
-
-
当被
PublicKeyCredentialUserEntity继承时,它是用户账户的人类可读标识符。它仅供显示,即帮助用户区分具有相似displayName的用户账户。例如,“alexm”、“alex.mueller@example.com” 或 “+14255551234”。-
信赖方 (Relying Party) 可以让用户选择此值。信赖方 (Relying Party) 在设置
name的值或向用户显示该值时,应当按照 [RFC8265] 第 3.4.3 节针对 PRECIS IdentifierClass 的 UsernameCasePreserved Profile [RFC8264] 执行强制性规范。 -
该字符串可能包含语言和方向元数据。信赖方 (Relying Party) 应考虑提供此信息。有关该元数据编码方式的说明,请参阅 § 6.4.2 语言和方向编码。
-
客户端在向用户显示
name的值或将其包含在 authenticatorMakeCredential 操作的参数中之前,应当按照 [RFC8265] 第 3.4.3 节针对 PRECIS IdentifierClass 的 UsernameCasePreserved Profile [RFC8264] 执行强制性规范。
-
当客户端、客户端平台或验证器显示
name的值时,它们应始终使用 UI 元素为所显示的值提供明确的边界,并禁止溢出到其他元素 [css-overflow-3]。如果验证器存储该值,验证器可以将
name成员的值截断,使其适合 64 字节以内。有关截断和其他考虑因素的说明,请参阅 § 6.4.1 字符串截断。 -
5.4.2. 凭据生成的信赖方参数(字典 PublicKeyCredentialRpEntity)
PublicKeyCredentialRpEntity 字典用于在创建新凭据时提供额外的信赖方 (Relying Party) 属性。
dictionary PublicKeyCredentialRpEntity :PublicKeyCredentialEntity {DOMString id ; };
5.4.3. 凭据生成的用户账户参数(字典 PublicKeyCredentialUserEntity)
PublicKeyCredentialUserEntity 字典用于在创建新凭据时提供额外的用户账户属性。
dictionary PublicKeyCredentialUserEntity :PublicKeyCredentialEntity {required BufferSource id ;required DOMString displayName ; };
id, 类型为 BufferSource-
用户账户实体的用户句柄 (user handle)。用户句柄是一个不透明的字节序列,最大长度为 64 字节,不建议向用户显示。
为确保操作安全,认证和授权决定必须基于此
id成员,而不是displayName或name成员。请参阅 [RFC8266] 第 6.1 节。用户句柄不得包含关于用户的个人识别信息,例如用户名或电子邮件地址;有关详情,请参阅 § 14.6.1 用户句柄内容。用户句柄不能为空,但可以为 null。
注意:用户句柄不应该在不同账户间保持固定不变,即便是对于非可发现凭据而言也是如此,因为某些验证器总是创建可发现凭据。因此,固定的用户句柄会阻止用户在同一个信赖方 (Relying Party) 处将此类验证器用于多个账户。
displayName, 类型为 DOMString-
用户账户的人类可读名称,仅供显示。例如,“Alex Müller” 或 “田中倫”。信赖方 (Relying Party) 应允许用户选择此项,且不应超出必要范围地限制用户的选择。
-
信赖方 (Relying Party) 在设置
displayName的值或向用户显示该值时,应当按照 [RFC8266] 第 2.3 节针对 PRECIS FreeformClass 的 Nickname Profile [RFC8264] 执行强制性规范。 -
该字符串可能包含语言和方向元数据。信赖方 (Relying Party) 应考虑提供此信息。有关该元数据编码方式的说明,请参阅 § 6.4.2 语言和方向编码。
-
客户端在向用户显示
displayName的值或将其包含在 authenticatorMakeCredential 操作的参数中之前,应当按照 [RFC8266] 第 2.3 节针对 PRECIS FreeformClass 的 Nickname Profile [RFC8264] 执行强制性规范。
当客户端、客户端平台或验证器显示
displayName的值时,它们应始终使用 UI 元素为所显示的值提供明确的边界,并禁止溢出到其他元素 [css-overflow-3]。验证器必须接受并存储至少 64 字节长度的
displayName成员值。验证器可以将displayName成员的值截断,使其适合 64 字节以内。有关截断和其他考虑因素的说明,请参阅 § 6.4.1 字符串截断。 -
5.4.4. 验证器选择标准(字典 AuthenticatorSelectionCriteria)
WebAuthn 信赖方 (WebAuthn Relying Party) 可以使用 AuthenticatorSelectionCriteria 字典来指定其对验证器属性的要求。
dictionary AuthenticatorSelectionCriteria {DOMString authenticatorAttachment ;DOMString residentKey ;boolean requireResidentKey =false ;DOMString userVerification = "preferred"; };
authenticatorAttachment, 类型为 DOMString-
如果存在此成员,则对符合条件的验证器进行过滤,仅保留通过 § 5.4.5 验证器附件枚举 (enum AuthenticatorAttachment) 中指定的附件类型进行连接的验证器。该值应当是
AuthenticatorAttachment的成员,但客户端平台必须忽略未知值,将未知值视为如同成员不存在一样。 residentKey, 类型为 DOMString-
指定信赖方 (Relying Party) 希望创建客户端侧可发现凭据 (client-side discoverable credential) 的程度。出于历史原因,其命名保留了已弃用的“驻留 (resident)”术语。该值应当是
ResidentKeyRequirement的成员,但客户端平台必须忽略未知值,将未知值视为如同成员不存在一样。如果未提供值,则若requireResidentKey为true,其有效值为required;若为false或不存在,则其有效值为discouraged。关于
residentKey的值及语义的说明,请参阅ResidentKeyRequirement。 requireResidentKey, 类型为 boolean,默认值为false-
此成员为保持与 WebAuthn Level 1 的向后兼容性而保留,并且出于历史原因,其命名保留了已弃用的关于可发现凭据的“驻留”术语。信赖方 (Relying Party) 应仅在
residentKey设置为required时,将其设置为true。 userVerification, 类型为 DOMString,默认值为"preferred"-
此成员描述了信赖方 (Relying Party) 关于
create()操作中用户验证 (user verification) 的要求。符合条件的验证器被过滤为仅保留能够满足此要求的验证器。该值应当是UserVerificationRequirement的成员,但客户端平台必须忽略未知值,将未知值视为如同成员不存在一样。
5.4.5. 验证器附件枚举(枚举 AuthenticatorAttachment)
此枚举的值描述了验证器的连接模态 (attachment modalities)。信赖方 (Relying Party) 在调用 navigator.credentials.create() 以创建凭据时,使用此项来表达其首选的验证器连接模态。
enum AuthenticatorAttachment {"platform" ,"cross-platform" };
注意:AuthenticatorAttachment 枚举被刻意地不进行引用,请参阅 § 2.1.1 作为 DOMString 类型的枚举。
platformcross-platform
注意:验证器连接模态选择选项仅在 [[Create]](origin, options, sameOriginWithAncestors) 操作中可用。信赖方 (Relying Party) 可以利用它,例如:确保用户拥有一个用于在其他客户端设备上进行认证的漫游凭据 (roaming credential);或者专门注册一个平台凭据 (platform credential) 以便在使用特定客户端设备时更容易地进行重新认证。[[DiscoverFromExternalSource]](origin, options, sameOriginWithAncestors) 操作没有验证器连接模态选择选项,因此信赖方 (Relying Party) 应接受用户的任何已注册凭据。客户端和用户届时将使用当时可用且方便的任何凭据。
5.4.6. 驻留密钥要求枚举(枚举 ResidentKeyRequirement)
enum ResidentKeyRequirement {"discouraged" ,"preferred" ,"required" };
注意:ResidentKeyRequirement 枚举被刻意地不进行引用,请参阅 § 2.1.1 作为 DOMString 类型的枚举。
此枚举的值描述了信赖方 (Relying Party) 对客户端侧可发现凭据 (client-side discoverable credentials)(曾称为驻留凭据 (resident credentials) 或 驻留密钥 (resident keys))的要求。
discouraged(不建议)-
此值指示信赖方 (Relying Party) 更倾向于创建服务器侧凭据 (server-side credential),但也接受客户端侧可发现凭据。
注意:信赖方 (Relying Party) 无法要求创建的凭据必须是服务器侧凭据,并且凭据属性扩展 (Credential Properties Extension) 可能不会为
rk属性返回一个值。因此,可能存在无法获知凭据是否为服务器侧凭据的情况,进而不知道使用相同的用户句柄创建第二个凭据是否会移除第一个凭据。 preferred(首选)-
此值指示信赖方 (Relying Party) 强烈倾向于创建客户端侧可发现凭据,但也接受服务器侧凭据。例如,用户代理在必要时应引导用户设置用户验证以创建客户端侧可发现凭据。此设置的优先级高于
userVerification的设置。 required(必须)-
此值指示信赖方 (Relying Party) 要求使用客户端侧可发现凭据,且如果无法创建客户端侧可发现凭据,则准备好接收错误。
注意:信赖方 (Relying Party) 可以通过查看凭据属性扩展的返回值,并结合为 options. 提供的值,来获取关于验证器是否创建了客户端侧可发现凭据的信息。当 authenticatorSelection.residentKeyauthenticatorSelection.residentKey 的值为 discouraged 或 preferred 时,这非常有用,因为在这些情况下,验证器有可能创建客户端侧可发现凭据或服务器侧凭据。
5.4.7. 认证传达 (Attestation Conveyance) 偏好枚举(枚举 AttestationConveyancePreference)
WebAuthn 信赖方 (WebAuthn Relying Party) 可以使用 AttestationConveyancePreference 来指定其在凭据生成期间关于认证传达的偏好。
enum AttestationConveyancePreference {"none" ,"indirect" ,"direct" ,"enterprise" };
注意:AttestationConveyancePreference 枚举被刻意地不进行引用,请参阅 § 2.1.1 作为 DOMString 类型的枚举。
none(无)-
此值指示信赖方 (Relying Party) 对验证器认证 (attestation) 不感兴趣。例如,为了潜在地避免获取将识别信息传递给信赖方 (Relying Party) 的用户同意,或者为了节省到认证 CA 或匿名化 CA 的往返次数。
这是默认值。
indirect(间接)-
此值指示信赖方 (Relying Party) 偏好产生可验证认证声明 (attestation statements) 的认证传达,但允许客户端决定如何获取此类认证声明。客户端可以为了保护用户隐私,或为了协助信赖方 (Relying Party) 在异构生态系统中进行认证验证,而用由匿名化 CA 生成的认证声明替换由验证器生成的认证声明。
注意:在这种情况下,不能保证信赖方 (Relying Party) 一定会获得可验证的认证声明。例如,在验证器采用自认证 (self attestation) 的情况下。
direct(直接)-
此值指示信赖方 (Relying Party) 希望接收由验证器生成的认证声明。
enterprise-
此值指示信赖方 (Relying Party) 希望接收可能包含唯一识别信息的认证声明。这旨在用于企业内部的受控部署,其中组织希望将注册与特定的验证器绑定。除非用户代理或验证器配置允许请求的 RP ID 进行此类认证,否则用户代理不得提供此类认证。
如果允许,用户代理应向验证器(在调用时)发送请求企业认证的信号,并将生成的 AAGUID 和认证声明原封不动地传达给信赖方 (Relying Party)。
5.5. 断言生成的选项(字典 PublicKeyCredentialRequestOptions)
PublicKeyCredentialRequestOptions
在所有当前引擎中。
Opera54+Edge79+
Edge (旧版)无IE无
Firefox for Android?iOS Safari13.3+Chrome for Android67+Android WebView67+Samsung InternetNoneOpera Mobile48+
PublicKeyCredentialRequestOptions 字典为 get() 提供其生成断言所需的数据。其 challenge 成员必须存在,而其他成员是可选的。
dictionary PublicKeyCredentialRequestOptions {required BufferSource challenge ;unsigned long timeout ;USVString rpId ;sequence <PublicKeyCredentialDescriptor >allowCredentials = [];DOMString userVerification = "preferred";AuthenticationExtensionsClientInputs extensions ; };
-
PublicKeyCredentialRequestOptions/challenge
在所有当前引擎中。
Firefox60+Safari13+Chrome67+
Opera54+Edge79+
Edge (旧版)无IE无
Firefox for Android?iOS Safari13.3+Chrome for Android67+Android WebView67+Samsung InternetNoneOpera Mobile48+challenge, 类型为 BufferSource -
此成员表示选定的验证器在产生身份验证断言 (authentication assertion) 时,连同其他数据一起签名的挑战。请参阅 § 13.4.3 加密挑战的安全注意事项。
-
PublicKeyCredentialRequestOptions/timeout
在所有当前引擎中。
Firefox60+Safari13+Chrome67+
Opera54+Edge79+
Edge (旧版)无IE无
Firefox for Android?iOS Safari13.3+Chrome for Android67+Android WebView67+Samsung InternetNoneOpera Mobile48+timeout, 类型为 unsigned long -
此可选成员指定调用者愿意等待操作完成的时间(以毫秒为单位)。该值仅作为提示,且可能被客户端覆盖。
-
PublicKeyCredentialRequestOptions/rpId
在所有当前引擎中。
Firefox60+Safari13+Chrome67+
Opera54+Edge79+
Edge (旧版)无IE无
Firefox for Android?iOS Safari13.3+Chrome for Android67+Android WebView67+Samsung InternetNoneOpera Mobile48+rpId, 类型为 USVString -
此可选成员指定调用者声称的信赖方标识符 (relying party identifier)。如果省略,其值将为
CredentialsContainer对象关联的相关设置对象的源 (origin) 的有效域 (effective domain)。 -
PublicKeyCredentialRequestOptions/allowCredentials
在所有当前引擎中。
Firefox60+Safari13+Chrome67+
Opera54+Edge79+
Edge (旧版)无IE无
Firefox for Android?iOS Safari13.3+Chrome for Android67+Android WebView67+Samsung InternetNoneOpera Mobile48+allowCredentials, 类型为 sequence<PublicKeyCredentialDescriptor>,默认值为[] -
此可选成员包含代表调用者可接受的公钥凭据的
PublicKeyCredentialDescriptor对象列表,按调用者的偏好降序排列(列表中的第一项为首选凭据,依此类推)。 -
PublicKeyCredentialRequestOptions/userVerification
在所有当前引擎中。
Firefox60+Safari13+Chrome67+
Opera54+Edge79+
Edge (旧版)无IE无
Firefox for Android?iOS Safari13.3+Chrome for Android67+Android WebView67+Samsung InternetNoneOpera Mobile48+userVerification, 类型为 DOMString,默认值为"preferred" -
此可选成员描述了信赖方 (Relying Party) 关于
get()操作中用户验证 (user verification) 的要求。该值应当是UserVerificationRequirement的成员,但客户端平台必须忽略未知值,将未知值视为如同成员不存在一样。符合条件的验证器被过滤为仅保留能够满足此要求的验证器。 -
PublicKeyCredentialCreationOptions/extensions
在所有当前引擎中。
Firefox60+Safari13+Chrome67+
Opera54+Edge79+
Edge (旧版)无IE无
Firefox for Android?iOS Safari13.3+Chrome for Android67+Android WebViewNoneSamsung InternetNoneOpera Mobile48+PublicKeyCredentialRequestOptions/extensions
在所有当前引擎中。
Firefox60+Safari13+Chrome67+
Opera54+Edge79+
Edge (旧版)无IE无
Firefox for Android?iOS Safari13.3+Chrome for Android67+Android WebView67+Samsung InternetNoneOpera Mobile48+extensions,类型为 AuthenticationExtensionsClientInputs -
此可选成员包含请求客户端和验证器执行额外处理的附加参数。例如,如果寻求用户的交易确认,则提示字符串可能会作为扩展被包含在内。
5.6. 使用 AbortSignal 中止操作
鼓励开发人员利用 AbortController 来管理 [[Create]](origin, options, sameOriginWithAncestors) 和 [[DiscoverFromExternalSource]](origin, options, sameOriginWithAncestors) 操作。有关详细说明,请参阅 DOM §3.3 在 API 中使用 AbortController 和 AbortSignal 对象一节。
注意:DOM §3.3 在 API 中使用 AbortController 和 AbortSignal 对象一节规定,与 AbortController 集成的 Web 平台 API 必须在设置了中止标志 (aborted flag) 后立即拒绝承诺 (promise)。考虑到 [[Create]](origin, options, sameOriginWithAncestors) 和 [[DiscoverFromExternalSource]](origin, options, sameOriginWithAncestors) 方法复杂的继承和并行化结构,这两个 API 的算法通过在三处检查中止标志来履行此要求。对于 [[Create]](origin, options, sameOriginWithAncestors),首先在 Credential Management 1 §2.5.4 创建凭据中,在调用 [[Create]](origin, options, sameOriginWithAncestors) 之前立即检查中止标志;其次在 § 5.1.3 创建新凭据 - PublicKeyCredential 的 [[Create]](origin, options, sameOriginWithAncestors) 方法中,在验证器会话 (authenticator sessions) 开始之前立即检查;最后在验证器会话期间进行检查。[[DiscoverFromExternalSource]](origin, options, sameOriginWithAncestors) 的情况也是如此。
Window 对象的可见性 (visibility) 和焦点 (focus) 状态决定了 [[Create]](origin, options, sameOriginWithAncestors) 和 [[DiscoverFromExternalSource]](origin, options, sameOriginWithAncestors) 操作是否应继续。当与 Document 相关联的 Window 对象失去焦点时,应中止 [[Create]](origin, options, sameOriginWithAncestors) 和 [[DiscoverFromExternalSource]](origin, options, sameOriginWithAncestors) 操作。
WHATWG HTML 工作组正在讨论是否在浏览上下文获得或失去焦点时提供钩子 (hook)。如果提供了钩子,上述段落将被更新以包含该钩子。有关更多详细信息,请参阅 WHATWG HTML WG 问题 #2711。
5.7. WebAuthn 扩展输入和输出
下文定义了用于传达 WebAuthn 扩展输入和输出的数据类型。
注意:验证器扩展输出作为验证器数据 (Authenticator data) 的一部分进行传达(参见表 1)。
注意:下文定义的数据类型 — AuthenticationExtensionsClientInputs 和 AuthenticationExtensionsClientOutputs — 既适用于注册扩展,也适用于认证扩展。它们名称中的 “Authentication...” 部分应被理解为指代 “WebAuthentication...”
5.7.1. 身份验证扩展客户端输入(字典 AuthenticationExtensionsClientInputs)
dictionary { };AuthenticationExtensionsClientInputs
这是一个包含零个或多个 WebAuthn 扩展的客户端扩展输入值的字典。
5.7.2. 身份验证扩展客户端输出(字典 AuthenticationExtensionsClientOutputs)
dictionary { };AuthenticationExtensionsClientOutputs
这是一个包含零个或多个 WebAuthn 扩展的客户端扩展输出值的字典。
5.7.3. 身份验证扩展验证器输入(CDDL 类型 AuthenticationExtensionsAuthenticatorInputs)
AuthenticationExtensionsAuthenticatorInputs = {
* $$extensionInput .within ( tstr => any )
}
CDDL 类型 AuthenticationExtensionsAuthenticatorInputs 定义了一个 CBOR 映射,其中包含零个或多个 WebAuthn 扩展的验证器扩展输入值。扩展可以按 § 9.3 扩展请求参数中所述添加成员。
此类型不向信赖方 (Relying Party) 公开,而是由客户端和验证器使用。
5.7.4. 身份验证扩展验证器输出(CDDL 类型 AuthenticationExtensionsAuthenticatorOutputs)
AuthenticationExtensionsAuthenticatorOutputs = {
* $$extensionOutput .within ( tstr => any )
}
CDDL 类型 AuthenticationExtensionsAuthenticatorOutputs 定义了一个 CBOR 映射,其中包含零个或多个 WebAuthn 扩展的验证器扩展输出值。扩展可以按 § 9.3 扩展请求参数中所述添加成员。
5.8. 支撑数据结构
公钥凭据类型使用在支撑规范中指定的某些数据结构。具体如下。
5.8.1. WebAuthn 签名中使用的客户端数据(字典 CollectedClientData)
客户端数据 (client data) 代表了 WebAuthn 信赖方 (WebAuthn Relying Party) 和客户端的上下文绑定。它是一个键值映射,其键为字符串。值可以是任何在 JSON 中具有有效编码的类型。其结构由以下 Web IDL 定义。
注意:CollectedClientData 未来可能会被扩展。因此,在解析时,必须能够容忍未知键和键的任何重新排序。另请参阅 § 5.8.1.2 受限验证算法。
dictionary CollectedClientData {required DOMString type ;required DOMString challenge ;required DOMString origin ;boolean crossOrigin ;TokenBinding tokenBinding ; };dictionary {TokenBinding required DOMString status ;DOMString id ; };enum {TokenBindingStatus "present" ,"supported" };
type, 类型为 DOMString-
此成员在创建新凭据时包含字符串 "webauthn.create",在从现有凭据获取断言时包含 "webauthn.get"。此成员的目的是防止某些类型的签名混淆攻击(攻击者用一个合法的签名替换另一个)。
challenge, 类型为 DOMString-
此成员包含信赖方 (Relying Party) 提供的挑战的 base64url 编码。请参阅 § 13.4.3 加密挑战的安全注意事项。
origin, 类型为 DOMString-
此成员包含请求者的完全限定源 (origin),由客户端按 [RFC6454] 定义的语法提供给验证器。
crossOrigin, 类型为 boolean-
此成员包含传入内部方法的
sameOriginWithAncestors参数值的反值。 tokenBinding, 类型为 TokenBinding-
此可选成员包含有关与信赖方 (Relying Party) 通信时使用的令牌绑定 (Token Binding) 协议 [TokenBinding] 状态的信息。如果不存在,则表示客户端不支持令牌绑定。
status, 类型为 DOMString-
此成员应当是
TokenBindingStatus的成员,但客户端平台必须忽略未知值,将未知值视为如同tokenBinding成员不存在一样。当已知时,此成员为以下值之一:supported(支持)-
指示客户端支持令牌绑定,但与信赖方 (Relying Party) 通信时未协商该功能。
present(存在)-
指示与信赖方 (Relying Party) 通信时使用了令牌绑定。在这种情况下,
id成员必须存在。
注意:
TokenBindingStatus枚举被刻意地不进行引用,请参阅 § 2.1.1 作为 DOMString 类型的枚举。 id, 类型为 DOMString-
如果
status为present,则此成员必须存在,且必须是与信赖方 (Relying Party) 通信时所使用的令牌绑定 ID 的 base64url 编码。
CollectedClientData 结构由客户端用于计算以下量值:
- 客户端数据的 JSON 兼容序列化
-
这是对
CollectedClientData字典执行JSON 兼容序列化算法的结果。 - 序列化客户端数据的哈希值
-
这是由客户端构建的客户端数据 JSON 兼容序列化的哈希值(使用 SHA-256 计算)。
5.8.1.1. 序列化
CollectedClientData 的序列化是JSON 序列化为字节算法的一个子集。也就是说,它产生 CollectedClientData 的有效 JSON 编码,但也提供了验证器可能利用的附加结构,以避免集成完整的 JSON 解析器。虽然建议验证器执行标准 JSON 解析,但它们可以在完整 JSON 解析器过大的上下文中使用下方的更有限的算法。此验证算法仅需要base64url 编码、字节串拼接(可以通过写入固定模板来实现)以及三个条件检查(假设输入已知不需要转义)。
该序列化算法通过将连续的字节串追加到一个最初为空的部分结果中,直到获得完整结果为止。
-
令 result 为一个空字节串。
-
将 0x7b2274797065223a (
{"type":) 追加到 result。 -
将 CCDToString(
type) 追加到 result。 -
将 0x2c226368616c6c656e6765223a (
,"challenge":) 追加到 result。 -
将 CCDToString(
challenge) 追加到 result。 -
将 0x2c226f726967696e223a (
,"origin":) 追加到 result。 -
将 CCDToString(
origin) 追加到 result。 -
将 0x2c2263726f73734f726967696e223a (
,"crossOrigin":) 追加到 result。 -
如果
crossOrigin不存在,或者为false-
将 0x66616c7365 (
false) 追加到 result。
-
-
否则
-
否则,将 0x74727565 (
true) 追加到 result。
-
-
创建
CollectedClientData的临时副本,并移除字段type、challenge、origin和crossOrigin(如果存在)。 -
如果临时副本中没有剩余字段,则
-
将 0x7d (
}) 追加到 result。
-
-
否则
-
对临时副本调用序列化 JSON 为字节以产生字节串 remainder。
-
将 0x2c (
,) 追加到 result。 -
从 remainder 中移除前导字节。
-
将 remainder 追加到 result。
-
-
序列化的结果即为 result 的值。
上述算法中使用函数 CCDToString,定义如下:
-
令 encoded 为一个空字节串。
-
将 0x22 (
") 追加到 encoded。 -
对给定对象调用 ToString 以转换为字符串。
-
对于结果字符串中的每个码点,如果码点
- 在集合 {U+0020, U+0021, U+0023–U+005B, U+005D–U+10FFFF} 中
-
将该码点的 UTF-8 编码追加到 encoded。
- 是 U+0022
-
将 0x5c22 (
\") 追加到 encoded。 - 是 U+005C
-
将 0x5c5c (\\) 追加到 encoded。
- 否则
-
将 0x5c75 (
\u) 追加到 encoded,后跟四个小写十六进制数字,当解释为十六进制数时,代表该码点。
-
将 0x22 (
") 追加到 encoded。 -
此函数的结果即为 encoded 的值。
5.8.1.2. 受限验证算法
如果验证器无法支持完整的 JSON 解析器,则可以使用以下算法来验证编码的 CollectedClientData:
-
算法的输入为:
-
一个字节串 clientDataJSON,包含
clientDataJSON—— 即待验证的序列化CollectedClientData。 -
一个包含预期
type的字符串 type。 -
一个字节串 challenge,包含在
PublicKeyCredentialRequestOptions或PublicKeyCredentialCreationOptions中给出的挑战字节串。 -
一个包含预期
origin的字符串 origin,即向用户代理发出请求的源。 -
一个布尔值 crossOrigin,仅当请求应该在跨源
iframe内执行时为 true。
-
-
令 expected 为一个空字节串。
-
将 0x7b2274797065223a (
{"type":) 追加到 expected。 -
将 CCDToString(type) 追加到 expected。
-
将 0x2c226368616c6c656e6765223a (
,"challenge":) 追加到 expected。 -
对 challenge 执行base64url 编码以产生字符串 challengeBase64。
-
将 CCDToString(challengeBase64) 追加到 expected。
-
将 0x2c226f726967696e223a (
,"origin":) 追加到 expected。 -
将 CCDToString(origin) 追加到 expected。
-
将 0x2c2263726f73734f726967696e223a (
,"crossOrigin":) 追加到 expected。 -
如果 crossOrigin 为 true
-
将 0x74727565 (
true) 追加到 expected。
-
-
否则(即 crossOrigin 为 false)
-
将 0x66616c7365 (
false) 追加到 expected。
-
-
如果 expected 不是 clientDataJSON 的前缀,则验证失败。
-
如果 clientDataJSON 的长度不至少比 expected 长一个字节,则验证失败。
-
如果在等于 expected 长度的偏移量处 clientDataJSON 的字节
- 是 0x7d
-
验证成功。
- 是 0x2c
-
验证成功。
- 否则
-
验证失败。
5.8.1.3. 未来发展
为了保持与受限验证算法的兼容性,本规范的未来版本不得从 CollectedClientData 中移除 type、challenge、origin 或 crossOrigin 中的任何字段。它们也不得更改序列化算法以更改这些字段被序列化的顺序。
如果将附加字段添加到 CollectedClientData,那么在上述两个算法更新以包含它们之前,使用受限验证算法的验证器将无法考量这些字段。一旦发生此类更新,添加的字段将继承与上一段所述相同的限制。此类算法更新必须适应以前版本产生的序列化结果。也就是说,验证算法必须处理这样一个事实:如果由运行先前版本的用户代理生成,第五个键值对可能不会出现在第五位(或者根本不出现)。
5.8.2. 凭据类型枚举(枚举 PublicKeyCredentialType)
enum PublicKeyCredentialType {"public-key" };
注意:PublicKeyCredentialType 枚举被刻意地不进行引用,请参阅 § 2.1.1 作为 DOMString 类型的枚举。
目前定义了一种凭据类型,即 “public-key”。
5.8.3. 凭据描述符(字典 PublicKeyCredentialDescriptor)
dictionary PublicKeyCredentialDescriptor {required DOMString type ;required BufferSource id ;sequence <DOMString >transports ; };
此字典包含调用者在将公钥凭据作为 create() 或 get() 方法的输入参数进行引用时所指定的属性。它映射了由后者方法返回的 PublicKeyCredential 对象的字段。
type, 类型为 DOMString-
此成员包含调用者所引用的公钥凭据的类型。该值应当是
PublicKeyCredentialType的成员,但客户端平台必须忽略任何具有未知type的PublicKeyCredentialDescriptor。 id,类型为 BufferSourcetransports,类型为 sequence<DOMString>-
此可选成员包含关于客户端应如何与调用者所引用的公钥凭据的管理验证器通信的提示。其值应当是
AuthenticatorTransport的成员,但客户端平台必须忽略未知值。getTransports()操作可为此成员提供合适的值。在注册新凭据时,信赖方 (Relying Party) 应当存储getTransports()返回的值。在为该凭据创建PublicKeyCredentialDescriptor时,信赖方应当检索该存储的值,并将其设置为transports成员的值。
5.8.4. 验证器传输枚举 (enum AuthenticatorTransport)
enum AuthenticatorTransport {"usb" ,"nfc" ,"ble" ,"internal" };
注意:AuthenticatorTransport 枚举被特意不进行引用,参见 § 2.1.1 作为 DOMString 类型的枚举。
getTransports() 了解公钥凭据支持的传输方式。
5.8.5. 密码算法标识符 (typedef COSEAlgorithmIdentifier)
typedef long ;COSEAlgorithmIdentifier
COSEAlgorithmIdentifier 的值是一个标识密码算法的数字。算法标识符应当是在 IANA COSE 算法注册表中注册的值 [IANA-COSE-ALGS-REG],例如,“ES256”对应 -7,“RS256”对应 -257。COSE 算法注册表留下了由 COSE 密钥中的其他参数指定的自由度。为了促进互操作性,本规范对凭据公钥作出了以下额外保证:
注意:使用这些算法正确实现签名验证需要进行许多检查。其中之一是:在处理未压缩的椭圆曲线点时,实现应检查该点是否确实位于曲线上。之所以强调此检查,是因为它被认为在密码库和其他代码之间容易出现疏漏,存在特殊风险。
5.8.6. 用户验证要求枚举 (enum UserVerificationRequirement)
enum UserVerificationRequirement {"required" ,"preferred" ,"discouraged" };
WebAuthn 信赖方可能要求对某些操作进行用户验证,而对其他操作则不需要,并可使用此类型来表达其需求。
注意:UserVerificationRequirement 枚举被特意不进行引用,参见 § 2.1.1 作为 DOMString 类型的枚举。
5.9. 权限策略集成
Headers/Feature-Policy/publickey-credentials-get
仅在一种当前的引擎中可用。
Opera无Edge84+
Edge (旧版)无IE无
Firefox for Android无iOS Safari无Chrome for Android84+Android WebView84+Samsung Internet无Opera Mobile无
本规范定义了一个由策略控制的功能,其特征标识符标记为 "publickey-credentials-get"。其默认允许列表为 'self'。[Permissions-Policy]
Document 的权限策略决定了该文档中的任何内容是否被允许成功调用 Web Authentication API,即通过 navigator.credentials.get({publicKey:..., ...}) 调用。如果该策略在任何文档中被禁用,则该文档中的任何内容都将不被允许使用上述方法:尝试这样做将返回一个错误。
注意:[CREDENTIAL-MANAGEMENT-1] 中指定的算法执行实际的权限策略评估。这是因为此类策略评估需要在能够访问当前设置对象时发生。[[Create]](origin, options, sameOriginWithAncestors) 和 [[DiscoverFromExternalSource]](origin, options, sameOriginWithAncestors) 内部方法由于是在并行执行(通过 [CREDENTIAL-MANAGEMENT-1] 中指定的算法),因此无法进行此类访问。
5.10. 在 iframe 元素中使用 Web Authentication
Web Authentication API 在跨源 iframe 中默认禁用。要覆盖此默认策略并指示允许跨源 iframe 调用 Web Authentication API 的 [[DiscoverFromExternalSource]](origin, options, sameOriginWithAncestors) 方法,请在 iframe 元素上指定 allow 属性,并在 allow 属性的值中包含 publickey-credentials-get 特征标识符标记。
在嵌入式上下文中使用 WebAuthn API 的信赖方应查阅 § 13.4.2 嵌入式使用的可见性考虑因素,了解有关 UI 纠偏及其可能的缓解措施。
6. WebAuthn 验证器模型
Web Authentication API 为 WebAuthn 验证器暗示了一种特定的抽象功能模型。本节描述了该验证器模型。
客户端平台可以以任何所需的方式实现并公开此抽象模型。然而,当对该客户端平台支持的验证器进行操作时,客户端的 Web Authentication API 实现的行为必须与 § 5 Web Authentication API 中指定的行为无法区分。
注意:[FIDO-CTAP] 是此模型的一个具体实例化的例子,但其返回的数据与 WebAuthn API 算法所期望的数据存在差异。CTAP2 响应消息是使用整数键构造的 CBOR 映射,而不是本规范为相同对象定义的字符串键。预期客户端将对此类数据执行任何必要的转换。[FIDO-CTAP] 规范在 § 6.2. 响应 部分详细说明了 CTAP2 整数键与 WebAuthn 字符串键之间的映射。
对于验证器,此模型定义了它们必须支持的逻辑操作,以及它们向客户端和 WebAuthn 信赖方公开的数据格式。然而,它并未定义验证器如何与客户端设备通信的细节,除非这些细节对于与信赖方的互操作性是必要的。例如,此抽象模型没有定义通过 USB 或 NFC 等传输方式将验证器连接到客户端的协议。同样,此抽象模型也没有定义特定的错误代码或返回错误代码的方法;但它确实根据客户端的需求定义了错误行为。因此,提到特定的错误代码是为了表明哪些错误条件必须是(或不是)彼此可区分的,从而实现符合标准且安全的客户端实施。
信赖方如果认为有必要,可以通过在创建凭据和/或生成断言时通过使用凭据创建选项或断言生成选项来规定各种验证器特性,从而影响验证器选择。支持 WebAuthn API 的算法会对这些选项进行编组,并将它们传递给下面定义的适用验证器操作。
在此抽象模型中,验证器提供密钥管理和加密签名。它可以嵌入在 WebAuthn 客户端中,也可以完全放置在单独的设备中。验证器本身可以包含一个加密模块,其运行的安全级别高于验证器的其余部分。这对于嵌入在 WebAuthn 客户端中的验证器尤为重要,因为在这些情况下,此加密模块(例如,可能是 TPM)可以被认为比验证器的其余部分更值得信赖。
每个验证器存储一个 凭据映射,这是一个从 (rpId, [userHandle]) 到 公钥凭据源的映射。
此外,每个验证器都有一个 AAGUID,这是一个 128 位的标识符,表示验证器的类型(例如品牌和型号)。AAGUID 必须由制造商选择,使得该制造商生产的所有实质上相同的验证器具有相同的 AAGUID,并与其他类型的所有其他验证器的 AAGUID 不同(高概率)。给定类型的验证器的 AAGUID 应当是随机生成的,以确保这一点。信赖方可以使用 AAGUID 通过其他来源的信息来推断验证器的某些属性,例如认证级别和密钥保护强度。
验证器的主要功能是提供 WebAuthn 签名,这些签名绑定到各种上下文数据。当签名请求从服务器传递到验证器时,这些数据会在栈的不同层级被观察并添加。在验证签名时,服务器会针对期望值检查这些绑定。这些上下文绑定分为两部分:由信赖方或客户端添加的,称为客户端数据;以及由验证器添加的,称为验证器数据。验证器对客户端数据进行签名,但除此之外不关心其内容。为了节省带宽和验证器上的处理需求,客户端对客户端数据进行哈希处理,并仅将结果发送给验证器。验证器对序列化客户端数据的哈希值及其自身的验证器数据的组合进行签名。
本设计的方案可以概括如下:
-
生成签名的方案应适应客户端设备与验证器之间的链接在带宽和/或延迟方面非常有限的情况。例子包括低功耗蓝牙和近场通信。
-
由验证器处理的数据应当小且易于在低层代码中解释。特别是,验证器不应该必须解析像 JSON 这样的高层编码。
-
客户端和验证器都应具有根据需要添加上下文绑定的灵活性。
-
该设计旨在尽可能重用现有的编码格式,以利于采用和实现。
认证器出于两个不同的目的生成密码学签名
-
当通过 authenticatorMakeCredential 操作创建新的公钥凭据时,会产生认证签名。一个认证签名提供了验证器和凭据某些属性的密码学证明。例如,一个认证签名断言了验证器类型(由其 AAGUID 表示)和凭据公钥。认证签名由一个认证私钥进行签名,该私钥的选择取决于所需的认证类型。有关认证的更多详细信息,请参见 § 6.5 认证。
-
当调用 authenticatorGetAssertion 方法时,会产生断言签名。它代表验证器的一种断言,即用户已同意进行特定交易,例如登录或完成购买。因此,一个断言签名断言,拥有特定凭据私钥的验证器已尽其所能确定请求此交易的用户与当初同意创建该特定公钥凭据的用户是同一个人。它还断言了称为客户端数据的额外信息,这些信息对于调用者可能很有用,例如提供用户同意的方式,以及验证器向用户显示的提示信息。断言签名格式如下图 4 所示。
WebAuthn 签名 一词指代认证签名和断言签名。这些签名的格式以及生成它们的程序在下面指定。
6.1. 验证器数据
验证器数据 结构编码了由验证器进行的上下文绑定。这些绑定由验证器自身控制,其信任源于 WebAuthn 信赖方对验证器安全属性的评估。在一种极端情况下,验证器可能嵌入在客户端中,其绑定可能并不比客户端数据更值得信任。在另一种极端情况下,验证器可能是一个具有高安全性硬件和软件的离散实体,通过安全通道连接到客户端。在这两种情况下,信赖方以相同的格式接收验证器数据,并使用其对验证器的了解来做出信任决策。
验证器数据具有紧凑但可扩展的编码。这是所期望的,因为验证器可以是能力有限且功耗需求低的设备,其软件栈比客户端平台要简单得多。
验证器数据结构是一个 37 字节或更长的字节数组,布局如表 所示。
| 名称 | 长度(字节) | 描述 |
|---|---|---|
| rpIdHash | 32 | 凭据所作用域的 RP ID 的 SHA-256 哈希值。 |
| flags (标志) | 1 | 标志(第 0 位是最低有效位) |
| signCount | 4 | 签名计数器,32 位无符号大端整数。 |
| attestedCredentialData | 可变(如果存在) | 已认证的凭据数据(如果存在)。详见 § 6.5.1 已认证的凭据数据。其长度取决于被认证的凭据 ID 和凭据公钥的长度。 |
| extensions | 可变(如果存在) | 扩展定义的验证器数据。这是一个以扩展标识符为键,以验证器扩展输出为值的 CBOR [RFC8949] 映射。详见 § 9 WebAuthn 扩展。 |
RP ID 最初是在创建凭据时从客户端接收的,并在生成断言时再次接收。然而,它在某些重要方面与其他客户端数据不同。首先,与客户端数据不同,凭据的 RP ID 在操作之间不会更改,而是在该凭据的生命周期内保持不变。其次,它在 authenticatorGetAssertion 操作期间由验证器进行验证,通过核实请求的凭据所作用域的 RP ID 是否与客户端提供的 RP ID 完全匹配。
-
UP标志应在且仅在验证器执行了用户存在测试时设置。UV标志应在且仅在验证器执行了用户验证时设置。RFU位应设置为零。注意:如果验证器既执行了用户存在测试又执行了用户验证(可能合并在单个授权手势中),则验证器将同时设置
UP标志 和UV标志。 -
对于认证签名,验证器必须设置 AT 标志 并包含
attestedCredentialData。对于断言签名,不得设置 AT 标志,且不得包含attestedCredentialData。
确定已认证的凭据数据的长度(它是可变的)涉及确定 credentialPublicKey 的起始位置(给定前述 credentialId 的长度),然后确定 credentialPublicKey 的长度(另请参阅 [RFC8152] 的第 7 节)。
6.1.1. 签名计数器 考量因素
验证器应当实现签名计数器功能。这些计数器在概念上由验证器针对每个凭据存储,或由验证器作为一个整体进行全局存储。凭据签名计数器的初始值由 authenticatorMakeCredential 返回的验证器数据中的 signCount 值指定。签名计数器会在每次成功的 authenticatorGetAssertion 操作后增加一个正值,后续的值再次在验证器数据内返回给 WebAuthn 信赖方。签名计数器的目的是辅助信赖方检测克隆的验证器。对于保护措施有限的验证器,克隆检测更为重要。
信赖方存储最近一次 authenticatorGetAssertion 操作的签名计数器。(如果凭据从未执行过 authenticatorGetAssertion,则存储来自 authenticatorMakeCredential 操作的计数器。)在随后的 authenticatorGetAssertion 操作中,信赖方会将存储的签名计数器值与断言的验证器数据中返回的新 signCount 值进行比较。如果两者均非零,且新的 signCount 值小于或等于存储的值,则可能存在克隆的验证器,或者验证器可能出现故障。
检测到签名计数器不匹配并不表示当前操作是由克隆的验证器执行的,还是由原始验证器执行的。信赖方应根据其个人情况,即其风险承受能力,适当地处理这种情况。
认证器
-
应当实现基于每个凭据的签名计数器。这可以防止签名计数器值在信赖方之间共享,并可能被用作用户的关联句柄。验证器可以实现全局签名计数器,即基于验证器的,但这对用户而言隐私友好度较低。
-
应当确保签名计数器值不会意外减少(例如由于硬件故障)。
6.1.2. FIDO U2F 签名格式兼容性
断言签名的格式(该格式对验证器数据结构和序列化客户端数据的哈希值的串联进行签名)与 FIDO U2F 认证签名格式兼容(参见 [FIDO-U2F-Message-Formats] 的 第 5.4 节)。
这是因为 FIDO U2F 认证响应消息中签名数据的前 37 个字节构成了一个有效的验证器数据结构,其余 32 个字节是序列化客户端数据的哈希值。在此验证器数据结构中,rpIdHash 是 FIDO U2F 应用程序参数,除 UP 外的所有 标志 始终为零,且从不出现 attestedCredentialData 和 extensions。因此,FIDO U2F 认证签名可以使用与 authenticatorMakeCredential 操作生成的其他断言签名相同的过程进行验证。
6.2. 认证器分类 (Authenticator Taxonomy)
许多用例取决于所使用的验证器的能力。本节为这些能力、它们最重要的组合以及这些组合所启用的用例定义了一些术语。
例如:
-
对于在同一客户端设备上的后续重新认证,平台验证器很可能是最方便的,因为它直接内置于客户端设备中,而不是用户可能需要寻找的独立设备。
-
笔记本电脑可能支持通过 USB 和蓝牙连接到漫游验证器,而手机可能仅支持 NFC。
上述示例说明了主要的验证器类型特征
这些特征是独立的,理论上可以以任何方式组合,但表 列出并命名了一些特别重要的验证器类型。
| 认证器类型 | 认证器附加形态 | 凭据存储形态 | 身份验证因子能力 |
|---|---|---|---|
| 双因素平台验证器 | platform | 任一 | 单因素能力 |
| 用户验证型平台认证器 | platform | 任一 | 多因素能力 |
| 双因素漫游验证器 | cross-platform | 服务端侧存储 | 单因素能力 |
| 单因素漫游验证器 | cross-platform | 客户端侧存储 | 多因素能力 |
双因素平台验证器便于在同一客户端设备上进行重新认证,并可用于在启动新会话和恢复现有会话时增加额外的安全层。双因素漫游验证器更可能用于在特定客户端设备上首次认证,或在多个用户共享的客户端设备上使用。
用户验证平台验证器和单因素漫游验证器启用了无密码多因素认证。除了拥有凭据私钥的证明外,这些验证器还支持将用户验证作为第二个认证因子,通常是 PIN 或生物识别。验证器因此可以充当两种认证因子,从而实现多因素认证,同时消除了与信赖方共享密码的需要。
未在表 中命名的四种组合具有较不突出的用例
-
凭据存储形态对于平台验证器的相关性低于漫游验证器,因为使用平台验证器的用户通常可以通过会话 cookie 或类似方式(即环境凭据)进行识别。
-
一个具有可发现凭据能力但没有多因素能力的漫游验证器可用于不带用户名的单因素认证,其中用户通过用户句柄自动识别,而拥有凭据私钥则被用作唯一的认证因子。这在某些情况下很有用,但使用户特别容易受到验证器丢失的影响。
-
一个具有多因素能力但没有可发现凭据能力的漫游验证器可用于多因素认证,但要求先识别用户,这冒着泄露个人身份信息的风险;参见 § 14.6.3 通过凭据 ID 进行隐私泄露。
以下小节更深入地定义了验证器连接形态、凭据存储形态和认证因子能力这三个方面。
6.2.1. 认证器附加形态 (Authenticator Attachment Modality)
客户端可以使用多种机制与验证器通信。例如,客户端可能使用特定于客户端设备的 API 与物理绑定到客户端设备的验证器通信。另一方面,客户端可以使用多种标准化的跨平台传输协议(例如蓝牙,参见 § 5.8.4 验证器传输枚举)来发现并与跨平台连接的验证器通信。我们将作为客户端设备一部分的验证器称为平台验证器,而那些可通过跨平台传输协议访问的验证器称为漫游验证器。
-
平台验证器使用特定于客户端设备的传输方式(称为平台连接)进行连接,通常不可从客户端设备上移除。绑定到平台验证器的公钥凭据称为平台凭据。
-
漫游验证器使用跨平台传输方式(称为跨平台连接)进行连接。此类验证器可从客户端设备上移除,并可在客户端设备之间“漫游”。绑定到漫游验证器的公钥凭据称为漫游凭据。
某些平台验证器也可能根据上下文充当漫游验证器。例如,集成在移动设备中的平台验证器可以通过蓝牙将自身作为漫游验证器提供。在这种情况下,运行在移动设备上的客户端会将验证器识别为平台验证器,而运行在不同客户端设备上并通过蓝牙与同一验证器通信的客户端会将其实别为漫游验证器。
平台验证器的主要用例是将特定客户端设备注册为“受信任设备”,从而使客户端设备本身充当未来认证的持有物 (something you have) 认证因子。这为用户提供了无需在未来的认证仪式中使用漫游验证器的便利,例如用户无需在口袋里寻找密钥卡或手机。
漫游验证器的用例包括:在新的客户端设备上首次认证、在很少使用的客户端设备上、在多个用户共享的客户端设备上、或不包含平台验证器的客户端设备上;以及当策略或偏好规定必须将验证器与其使用的客户端设备分开时。漫游验证器还可用于保存备份凭据,以防另一个验证器丢失。
6.2.2. 凭据存储形态 (Credential Storage Modality)
-
嵌入在验证器、客户端或客户端设备的持久存储中,例如安全单元中。这是客户端侧可发现公钥凭据源的技术要求。
-
通过加密(即包装)凭据私钥,使得只有此验证器可以解密(即解包)它,并让生成的密文成为公钥凭据源的凭据 ID。凭据 ID 由信赖方存储,并通过
get()的allowCredentials选项返回给验证器,这使得验证器可以解密并使用凭据私钥。这使得验证器能够拥有无限的凭据私钥存储容量,因为加密的凭据私钥由信赖方而不是验证器存储——但这意味着以这种方式存储的凭据必须在验证器可以使用它之前从信赖方处检索。
验证器支持其中的哪种存储策略定义了该验证器的 凭据存储形态,具体如下
-
如果验证器支持客户端侧可发现公钥凭据源,则它具有客户端侧凭据存储形态。具有客户端侧凭据存储形态的验证器也称为具有可发现凭据能力。
-
如果验证器不具备客户端侧凭据存储形态,则它具有服务器侧凭据存储形态,即它仅支持将凭据私钥作为凭据 ID 中的密文进行存储。
请注意,具有可发现凭据能力的验证器可以支持两种存储策略。在这种情况下,验证器可以自行决定对不同的凭据使用不同的存储策略,尽管这受 residentKey 或 requireResidentKey create() 选项的制约。
6.2.3. 身份验证因子能力 (Authentication Factor Capability)
有三大类认证因子可用于在认证仪式中证明身份:持有物 (something you have)、知识 (something you know) 和生物特征 (something you are)。例子分别为物理密钥、密码和指纹。
所有 WebAuthn 验证器都属于持有物类,但支持用户验证的验证器还可以充当一到两种额外的认证因子。例如,如果验证器可以验证 PIN,则 PIN 是知识因子,而生物识别验证器可以验证生物特征因子。因此,支持用户验证的验证器是多因素能力的。反之,不具备多因素能力的验证器是单因素能力的。请注意,单个多因素能力的验证器可以支持多种用户验证模式,这意味着它可以充当所有三种认证因子。
尽管用户验证是在验证器本地执行,而非由依赖方执行,但验证器会通过在返回给依赖方的已签名响应中设置UV标志来指示是否执行了用户验证。因此,依赖方可以使用UV标志来验证在注册或认证仪式中是否使用了额外的认证因素。UV标志的真实性又可以通过检查验证器的证明声明来评估。
6.3. 验证器操作
WebAuthn客户端必须连接到验证器,以便调用该验证器的任何操作。此连接定义了一个验证器会话。验证器必须在会话之间保持隔离。它可以通过在任何特定时间仅允许一个会话存在,或通过提供更复杂的会话管理来实现这一点。
客户端可以在认证器会话中调用以下操作。
6.3.1. 通过凭据ID查找凭据源算法
在验证器 authenticator 中查找 凭据ID credentialId 的结果是以下算法的结果:
-
如果 authenticator 可以将 credentialId 解密为公钥凭据源 credSource
-
将 credSource.id 设置为 credentialId。
-
返回 credSource。
-
-
对于 authenticator 的凭据映射中的每个公钥凭据源 credSource
-
如果 credSource.id 为 credentialId,则返回 credSource。
-
-
返回
null。
6.3.2. authenticatorMakeCredential 操作
它接受以下输入参数
- hash (哈希)
-
由客户端提供的序列化客户端数据的哈希值。
- rpEntity
- userEntity
-
用户账户的
PublicKeyCredentialUserEntity,包含由依赖方提供的用户句柄。 - requireResidentKey
-
凭据创建的有效驻留密钥要求,由客户端确定的布尔值。
- requireUserPresence
-
常量布尔值
true。此处将其包含为伪参数,旨在简化将此抽象验证器模型应用于可能希望使用户存在性测试可选(尽管WebAuthn并非如此)的实现。 - requireUserVerification
-
凭据创建的有效用户验证要求,由客户端确定的布尔值。
- credTypesAndPubKeyAlgs
-
依赖方请求的
PublicKeyCredentialType和公钥算法(COSEAlgorithmIdentifier)对的序列。此序列按从最优先到最不优先的顺序排列。验证器会尽最大努力创建其能支持的最优先凭据。 - excludeCredentialDescriptorList
-
依赖方提供的可选
PublicKeyCredentialDescriptor对象列表,目的是如果验证器已知其中任何一个,则它不应创建新凭据。excludeCredentialDescriptorList 包含已知凭据的列表。 - enterpriseAttestationPossible
-
一个布尔值,指示验证器可能返回可唯一标识的证明。
- extensions
注意: 在执行此操作之前,必须通过运行 authenticatorCancel 操作来中止验证器会话中所有正在进行的其他操作。
当调用此操作时,验证器必须执行以下过程
-
检查所有提供的参数是否在语法上格式正确且长度正确。如果不是,返回等同于“
UnknownError”的错误代码并终止操作。 -
检查是否至少支持 credTypesAndPubKeyAlgs 中指定的
PublicKeyCredentialType和加密参数的组合之一。如果不是,返回等同于“NotSupportedError”的错误代码并终止操作。 -
对于 excludeCredentialDescriptorList 中的每个 descriptor
-
如果在此验证器中查找
descriptor.返回非空值,且返回项目的RP ID和类型分别与idrpEntity.和idexcludeCredentialDescriptorList.匹配,则收集确认创建新凭据的用户同意的授权手势。该授权手势必须包括用户存在性测试。如果用户type- 确认同意创建新凭据
-
返回等同于“
InvalidStateError”的错误代码并终止操作。 - 不同意创建新凭据
-
返回等同于“
NotAllowedError”的错误代码并终止操作。
注意: 此授权手势的目的不是继续创建凭据,而是出于隐私原因授权披露
descriptor.绑定到此验证器这一事实。如果用户同意,客户端和依赖方可以检测到这一点并引导用户使用不同的验证器。如果用户不同意,验证器不会透露iddescriptor.已绑定到它,并以用户只是拒绝创建凭据的同意的方式进行响应。id
-
-
如果 requireResidentKey 为
true且验证器无法存储客户端可发现的公钥凭据源,则返回等同于“ConstraintError”的错误代码并终止操作。 -
如果 requireUserVerification 为
true且验证器无法执行用户验证,则返回等同于“ConstraintError”的错误代码并终止操作。 -
收集确认创建新凭据的用户同意的授权手势。该授权手势的提示由验证器(如果其具有自己的输出能力)或用户代理显示。如果可能,提示应显示
rpEntity.、idrpEntity.、nameuserEntity.和nameuserEntity.。displayName如果 requireUserVerification 为
true,则授权手势必须包括用户验证。如果 requireUserPresence 为
true,则授权手势必须包括用户存在性测试。如果用户未同意或用户验证失败,则返回等同于“
NotAllowedError”的错误代码并终止操作。 -
-
令 (publicKey, privateKey) 为使用此验证器支持的 credTypesAndPubKeyAlgs 中的第一个项目所表示的
PublicKeyCredentialType和加密参数组合的新加密密钥对。 -
令 userHandle 为
userEntity.。id -
令 credentialSource 为具有以下字段的新公钥凭据源
- type
- privateKey
-
privateKey
- rpId
-
rpEntity.id - userHandle
-
userHandle
- otherUI
-
认证器选择包含的任何其他信息。
-
如果 requireResidentKey 为
true或验证器选择创建客户端可发现的公钥凭据源 -
否则
-
令 credentialId 为序列化并加密 credentialSource 的结果,使得只有此认证器可以解密它。
-
-
-
如果在创建新凭据对象时发生任何错误,返回等同于“
UnknownError”的错误代码并终止操作。 -
令 processedExtensions 为 验证器扩展处理 的结果,该处理针对 extensions 中的每个受支持的扩展标识符 → 验证器扩展输入进行迭代。
-
如果验证器
-
令 attestedCredentialData 为包含 credentialId 和 publicKey 的已验证凭据数据字节数组。
-
令 authenticatorData 为 § 6.1 验证器数据 中指定的字节数组,包含 attestedCredentialData 作为
attestedCredentialData,以及 processedExtensions(如果有)作为extensions。 -
使用 § 6.5.4 生成证明对象 中指定的过程,为新凭据创建一个证明对象,使用验证器选择的证明声明格式、authenticatorData 和 hash,并
考虑enterpriseAttestationPossible 的值。有关证明的更多详情,请参见 § 6.5 证明。
成功完成此操作后,验证器将证明对象返回给客户端。
6.3.3. authenticatorGetAssertion 操作
它接受以下输入参数
- rpId
- hash (哈希)
-
由客户端提供的序列化客户端数据的哈希值。
- allowCredentialDescriptorList
-
描述依赖方可接受的凭据(可能由客户端过滤,如果有)的可选
PublicKeyCredentialDescriptor列表。 - requireUserPresence
-
常量布尔值
true。此处将其包含为伪参数,旨在简化将此抽象验证器模型应用于可能希望使用户存在性测试可选(尽管WebAuthn并非如此)的实现。 - requireUserVerification
-
由客户端提供的 断言的有效用户验证要求,一个布尔值。
- extensions
注意: 在执行此操作之前,必须通过运行 authenticatorCancel 操作来中止验证器会话中所有正在进行的其他操作。
当调用此方法时,验证器必须执行以下过程
-
检查所有提供的参数是否在语法上格式正确且长度正确。如果不是,返回等同于“
UnknownError”的错误代码并终止操作。 -
如果提供了 allowCredentialDescriptorList,则对于 allowCredentialDescriptorList 中的每个 descriptor
-
否则(未提供 allowCredentialDescriptorList),对于此验证器的凭据映射中的每个 key → credSource,将 credSource附加到 credentialOptions。
-
如果 credentialOptions 现在为空,返回等同于“
NotAllowedError”的错误代码并终止操作。 -
提示用户从 credentialOptions 中选择一个公钥凭据源 selectedCredential。收集确认使用 selectedCredential 的用户同意的授权手势。该授权手势的提示可由验证器(如果其具有自己的输出能力)或用户代理显示。
如果 requireUserVerification 为
true,则授权手势必须包括用户验证。如果 requireUserPresence 为
true,则授权手势必须包括用户存在性测试。如果用户未同意,则返回等同于“
NotAllowedError”的错误代码并终止操作。 -
令 processedExtensions 为 验证器扩展处理 的结果,该处理针对 extensions 中的每个受支持的扩展标识符 → 验证器扩展输入进行迭代。
-
将与凭据相关的签名计数器或全局签名计数器值增加某个正值,具体取决于验证器实现的方法。如果验证器不实现签名计数器,则令签名计数器值保持为零的常数。
-
令 authenticatorData 为 § 6.1 验证器数据 中指定的字节数组,包含 processedExtensions(如果有)作为
extensions,并排除attestedCredentialData。 -
令 signature 为 下方图 所示的串联
authenticatorData || hash的断言签名,使用 selectedCredential 的私钥。此处使用简单的无定界符串联是安全的,因为验证器数据描述了其自身的长度。序列化客户端数据的哈希值(其长度可能可变)始终是最后一个元素。生成一个断言签名。 -
如果在生成断言签名时发生任何错误,返回等同于“
UnknownError”的错误代码并终止操作。 -
返回给用户代理
-
selectedCredential.id(如果客户端提供了长度为 2 或以上的凭据列表,即 allowCredentialDescriptorList,或者未提供此类列表)。
注意: 如果客户端在 allowCredentialDescriptorList 中仅提供了一个凭据并且它已被成功采用,则不会返回其凭据ID,因为客户端已经知道了。这在可能是受限连接的情况下节省了传输这些字节的开销,而这很可能是常见情况。
-
authenticatorData
-
signature
-
selectedCredential.userHandle
注意: 返回的 userHandle 值可能为
null,请参见:userHandleResult。
-
如果验证器无法找到对应于指定依赖方且符合指定条件的任何凭据,它将终止操作并返回错误。
6.3.4. authenticatorCancel 操作
此操作不接受输入参数,也不返回任何结果。
当此操作由客户端在验证器会话中调用时,它会终止该验证器会话中当前正在进行的任何 authenticatorMakeCredential 或 authenticatorGetAssertion 操作。验证器停止提示或接受与授权已取消操作相关的任何用户输入。客户端忽略验证器针对已取消操作的任何进一步响应。
如果此操作是在没有当前正在进行的 authenticatorMakeCredential 或 authenticatorGetAssertion 操作的验证器会话中调用的,它将被忽略。
6.4. 字符串处理
验证器可能需要存储由依赖方选择的任意字符串,例如 PublicKeyCredentialUserEntity 中的 name 和 displayName。本节讨论处理可能呈现给人类的任意字符串的一些实际后果。
6.4.1. 字符串截断
API 中的每个任意字符串都将对验证器可能有限的可用资源进行一些调整。如果选择了字符串值截断作为调整方式,则验证器为了使字符串符合等于或大于指定支持的最小长度,可能进行截断。此类截断还应尊重 UTF-8 序列边界或字素簇边界 [UTR29]。这定义了允许的最大截断量,验证器不得进一步截断。
例如,在 图 中,字符串长度为 65 字节。如果截断为 64 字节,则必须纯粹因为空间原因移除最后一个 0x88 字节。由于这留下了一个部分的 UTF-8 序列,该序列的其余部分也可能被移除。由于这留下了一个部分的字素簇,验证器可能会移除该簇的其余部分。
符合标准的用户代理负责确保依赖方观察到的验证器行为在字符串处理方面符合本规范。例如,如果已知验证器在被要求存储长字符串时表现不正确,则用户代理应为它执行截断,以从依赖方的角度保持模型。执行此操作的用户代理应在字素簇边界处进行截断。
仅基于 UTF-8 序列的截断可能会导致字素簇被截断。这可能会使字素簇渲染为不同的字形,从而潜在地改变字符串的含义,而不是完全移除字形。
除此之外,仅在字节边界上进行截断会引发用户代理应意识到的已知问题:如果验证器正在使用 [FIDO-CTAP],则来自验证器的未来消息可能包含无效的 CBOR,因为该值被键入为 CBOR 字符串,因此必须是有效的 UTF-8。用户代理的任务是处理此问题,以避免在理解字符编码和 Unicode 字符属性方面给验证器增加负担。因此,在处理验证器时,用户代理应
-
确保发送到验证器的任何字符串都是有效编码的。
-
处理字符串已被截断导致无效编码的情况。例如,末尾的任何部分代码点都可能被丢弃或替换为 U+FFFD。
6.4.2. 语言和方向编码
为了在上下文中正确显示,字符串的语言和基本方向可能需要。此 API 中的字符串可能必须被写入到固定功能的验证器中,然后稍后读回并在不同的平台上显示。因此,语言和方向元数据被编码在字符串本身中,以确保其被原子传输。
要在文档规定允许的字符串中对语言和方向元数据进行编码,请在其代码点后附加两个代码点序列
第一个使用代码点 U+E0001 对语言标签进行编码,后跟每个向上移动 U+E0000 的语言标签的 ASCII 值。例如,语言标签“en-US”变为代码点 U+E0001、U+E0065、U+E006E、U+E002D、U+E0055、U+E0053。
第二个由单个代码点组成,该代码点是 U+200E(“左到右标记”)、U+200F(“右到左标记”)或 U+E007F(“取消标签”)。前两个可用于指示方向性,但应仅在产生正确结果所必需时使用。(例如,以 LTR 强字符开头的 RTL 字符串。)值 U+E007F 是对语言标签结尾的与方向无关的指示。
因此,根据语言是否被编码,字符串“حبیب الرحمان”可以具有两个不同的 DOMString 值。(由于方向明确,在这个例子中不需要方向性标记。)
-
未装饰的字符串:U+FEA2、U+FE92、U+FBFF、U+FE91、U+20、U+FE8E、U+FEDF、U+FEAE、U+FEA4、U+FEE3、U+FE8E、U+FEE7
-
编码了语言“ar-SA”:U+FEA2、U+FE92、U+FBFF、U+FE91、U+20、U+FE8E、U+FEDF、U+FEAE、U+FEA4、U+FEE3、U+FE8E、U+FEE7、U+E0001、U+E0061、U+E0072、U+E002D、U+E0053、U+E0041、U+E007F
可能已编码语言和方向的字符串的消费者应意识到,截断可能会将语言标签截断为另一种虽然不同但仍然有效的语言。最终的方向性标记或取消标签代码点提供了对截断的明确指示。
6.5. 证明
验证器如果可能,也应提供某种形式的证明。如果验证器提供了证明,基本要求是验证器能够为每个凭据公钥产生一个可由WebAuthn依赖方验证的证明声明。通常,此证明声明包含由证明私钥对已验证的凭据公钥和质询进行的签名,以及提供证明公钥来源信息的证书或类似数据,从而使依赖方能够做出信任决策。但是,如果证明密钥对不可用,则验证器可以使用相应的凭据私钥对凭据公钥执行自证明,或者执行无证明。所有这些信息均由验证器在每次生成新的公钥凭据时以证明对象的整体形式返回。证明对象与(包含已验证凭据数据的)验证器数据和证明声明的关系如下面的 图 所示。
如果验证器采用自证明或无证明,则不会为依赖方提供基于其进行信任决策的来源信息。在这种情况下,验证器不对依赖方提供关于其操作的任何保证。
证明对象的一个重要组成部分是证明声明。这是一种特定类型的已签名数据对象,包含关于公钥凭据本身以及创建它的验证器的声明。它包含使用证明机构的密钥创建的证明签名(自证明除外,此时它使用凭据私钥创建)。为了正确解释证明声明,依赖方需要了解证明的这两个方面
-
证明声明格式是验证器表示签名并将各种上下文绑定合并到证明声明中的方式。换句话说,这定义了声明的语法。各种现有组件和操作系统平台(如 TPM 和 Android OS)之前已经定义了证明声明格式。本规范以可扩展的方式支持多种此类格式,如 § 6.5.2 证明声明格式 中定义的那样。格式本身由字符串标识,如 § 8.1 证明声明格式标识符 中所述。
-
证明类型定义了证明声明及其底层信任模型的语义。具体而言,它定义了依赖方在验证特定证明声明在密码学上有效后,如何对其建立信任。本规范支持多种证明类型,如 § 6.5.3 证明类型 中所述。
通常,证明声明格式和证明类型之间没有简单的映射关系。例如,在 § 8.2 打包证明声明格式 中定义的“packed”证明声明格式可以与所有证明类型结合使用,而其他格式和类型则适用范围有限。
证明的隐私、安全和操作特性取决于
预期大多数验证器将支持少量的证明类型和证明声明格式,而依赖方将通过策略决定哪些证明类型对其可接受。依赖方还需要根据其拥有的关于这些验证器的信息,了解其信任的验证器的特性。例如,FIDO 元数据服务 [FIDOMetadataService] 提供了一种访问此类信息的方法。
6.5.1. 已验证凭据数据
已验证凭据数据 是一个变长字节数组,在为给定凭据生成证明对象时添加到验证器数据中。其格式显示在 表 中。
| 名称 | 长度(字节) | 描述 |
|---|---|---|
| aaguid | 16 | 验证器的 AAGUID。 |
| credentialIdLength | 2 | 凭据 ID 的字节长度 L,16 位无符号大端整数。 |
| credentialId | L | 凭据 ID |
| credentialPublicKey | 变量 | 以 COSE_Key 格式编码的凭据公钥,如 [RFC8152] 的 第 7 节 中所定义,使用 CTAP2 规范 CBOR 编码形式。COSE_Key 编码的凭据公钥必须包含“alg”参数,并且不得包含任何其他可选参数。“alg”参数必须包含 COSEAlgorithmIdentifier 值。编码的凭据公钥还必须包含相关密钥类型规范规定的任何其他必需参数,即对于密钥类型“kty”和算法“alg”为必需(参见 [RFC8152] 的第 8 节)。 |
6.5.1.1. COSE_Key 格式编码的 credentialPublicKey 值示例
本节提供了用于 ES256、PS256 和 RS256 签名算法的 COSE_Key 编码椭圆曲线和 RSA 公钥示例。这些示例遵循上述关于 credentialPublicKey 值的规则,并以 CDDL [RFC8610] 呈现以供清晰查阅。
[RFC8152] 第 7 节 定义了所有 COSE_Key 编码密钥的通用框架。特定算法的特定密钥类型在 [RFC8152] 的其他章节以及其他规范中定义,如下所述。
下面是用于 ES256 签名算法(ECDSA w/ SHA-256,参见 [RFC8152] 第 8.1 节)的 P-256 曲线上,以 EC2 格式(参见 [RFC8152] 第 13.1 节)的 COSE_Key 编码椭圆曲线公钥示例。
{ 1 : 2 , ; kt y: EC2 keyt ype3 : -7 , ; alg: ES256 signature algorit hm-1 : 1 , ; crv: P-256 curve-2 : x, ; x- coordinate as byte str in g32 bytes in len gt h ; e.g., in hex: 65e da5 a12577 c2 bae829437 fe 338701 a10 aaa375e1 bb5 b5 de108 de439 c08551 d-3 : y ; y- coordinate as byte str in g32 bytes in len gt h ; e.g., in hex: 1e52e d75701163 f 7 f 9e40 ddf 9 f 341 b3 dc9 ba860 af 7e0 ca7 ca7e9ee cd0084 d19 c}
下面是上述以 CTAP2 规范 CBOR 编码形式编码的椭圆曲线公钥,此处包含空格和换行符是为了清晰起见,并符合上述 CDDL [RFC8610] 的演示。
A5 01 02 03 26 20 01 21 58 20 65e da5 a12577 c2 bae829437 fe 338701 a10 aaa375e1 bb5 b5 de108 de439 c08551 d22 58 20 1e52e d75701163 f 7 f 9e40 ddf 9 f 341 b3 dc9 ba860 af 7e0 ca7 ca7e9ee cd0084 d19 c
下面是一个用于 PS256 签名算法(RSASSA-PSS with SHA-256,参见 [RFC8230] 第 2 节)的 COSE_Key 编码 2048 位 RSA 公钥(参见 [RFC8230] 第 4 节)的示例。
{ 1 : 3 , ; kt y: RSA keyt ype3 : -37 , ; alg: PS256 -1 : n , ;n : RSA modulusn byte str in g256 bytes in len gt h ; e.g., in hex (middle bytes elidedf or brevit y): DB5 F651550...6 DC6548 ACC3 -2 : e ; e: RSA public exponent e byte str in g3 bytes in len gt h ; e.g., in hex: 010001 }
下面是与上述相同且用于 RS256 签名算法(RSASSA-PKCS1-v1_5 with SHA-256)的 COSE_Key 编码 RSA 公钥的示例。
{ 1 : 3 , ; kt y: RSA keyt ype3 : -257 , ; alg: RS256 -1 : n , ;n : RSA modulusn byte str in g256 bytes in len gt h ; e.g., in hex (middle bytes elidedf or brevit y): DB5 F651550...6 DC6548 ACC3 -2 : e ; e: RSA public exponent e byte str in g3 bytes in len gt h ; e.g., in hex: 010001 }
6.5.2. 证明声明格式
如上所述,证明声明格式是一种数据格式,它表示验证器对一组上下文绑定的加密签名。每个证明声明格式必须使用以下模板定义
-
支持的证明类型
-
语法: 以此格式生成的证明声明的语法,使用 CDDL [RFC8610] 为 § 6.5.4 生成证明对象 中定义的扩展点
$attStmtFormat定义。 -
签名过程:给定要证明的公钥凭据、包含用于证明的验证器数据的验证器数据结构以及序列化客户端数据的哈希值,用于计算此格式中的证明声明的签名过程。
-
验证过程:验证证明声明的过程,该过程接受以下验证过程输入
-
attStmt:证明声明结构
-
authenticatorData:声称已用于证明的验证器数据
-
clientDataHash:序列化客户端数据的哈希值
该过程返回
-
指定证明声明格式的初始列表位于 § 8 已定义的证明声明格式 中。
6.5.3. 证明类型
WebAuthn 支持多种证明类型,定义证明声明及其底层信任模型的语义
Note: 本规范没有定义明确表达验证器所采用的证明类型的任何数据结构。依赖方参与证明声明验证 — 即在调用 navigator.credentials.create() 时选择除 none 之外的证明传达并验证收到的证明声明 — 将作为验证的一部分确定所采用的证明类型。参见 § 8 已定义的证明声明格式 的“验证过程”小节。另请参见 § 14.4.1 证明隐私。对于本节中除 Self 和 None 之外定义的所有证明类型,依赖方验证之后,按照 § 7.1 注册新凭据 的步骤 21,将信任路径与可接受的根证书进行匹配。区分这些证明类型主要作为确定证明在依赖方策略下是否可接受的一种手段。
- 基本证明 (Basic)
-
在基本证明 [UAFProtocol] 的情况下,验证器的证明密钥对特定于验证器“型号”,即一批验证器。因此,相同或相似型号的验证器通常共享同一个证明密钥对。有关更多信息,请参见 § 14.4.1 证明隐私。
基本证明也称为批量证明。
- 自证明 (Self)
-
在自证明(也称为代理基本证明 [UAFProtocol])的情况下,验证器没有任何特定的证明密钥对。相反,它使用凭据私钥创建证明签名。对于证明私钥没有有效保护措施的验证器通常使用此证明类型。
- 证明 CA (AttCA)
-
在这种情况下,验证器基于可信平台模块 (TPM),并拥有验证器特定的“背书密钥”(EK)。此密钥用于与可信第三方(证明 CA [TCG-CMCProfile-AIKCertEnroll],以前称为“隐私 CA”)进行安全通信。验证器可以生成多个证明身份密钥对 (AIK),并请求证明 CA 为每个密钥对颁发 AIK 证书。使用这种方法,此类验证器可以将 EK(全局关联句柄)的暴露限制在证明 CA 中。可以为每个验证器生成的公钥凭据单独请求 AIK,并将其作为证明证书传达给依赖方。
Note: 此概念通常会导致多个证明证书。请求最频繁的证明证书称为“激活”。
- 匿名化 CA (AnonCA)
-
在这种情况下,验证器使用动态生成每个凭据 证明证书的匿名化 CA,使得呈现给依赖方的证明声明不提供可唯一标识的信息,例如可能用于跟踪目的的信息。
Note: 传达类型为 AttCA 或 AnonCA 的证明的证明声明与类型为 Basic 的数据结构相同,因此这三种证明类型通常只有在关于证明声明中传达的证明证书的内容有外部提供知识的情况下才能区分。
- 无证明声明 (None)
-
在这种情况下,没有可用的证明信息。另请参阅 § 8.7 None 证明语句格式。
6.5.4. 生成证明对象 (Attestation Object)
认证器必须
-
令 attStmt 为运行 attestationFormat 的签名过程(给定 authData 和 hash)的结果。
-
令 fmt 为 attestationFormat 的证明语句格式标识符
-
返回证明对象,作为具有以下语法的 CBOR 映射,并使用此算法初始化的变量进行填充
attObj = { authData: bytes, $$attStmtType } attStmtTemplate = ( fmt: text, attStmt: { * tstr => any } ; Map is filled in by each concrete attStmtType ) ; Every attestation statement format must have the above fields attStmtTemplate .within $$attStmtType
6.5.5. 打包证明、FIDO U2F 证明和断言签名的签名格式
-
对于 COSEAlgorithmIdentifier -7 (ES256) 以及其他基于 ECDSA 的算法,
sig值必须按照 [RFC3279] 第 2.2.3 节的定义,编码为 ASN.1 DER Ecdsa-Sig-Value。Example: 30 44 ; SEQUENCE (68 Bytes) 02 20 ; INTEGER (32 Bytes) | 3d 46 28 7b 8c 6e 8c 8c 26 1c 1b 88 f2 73 b0 9a | 32 a6 cf 28 09 fd 6e 30 d5 a7 9f 26 37 00 8f 54 02 20 ; INTEGER (32 Bytes) | 4e 72 23 6e a3 90 a9 a1 7b cf 5f 7a 09 d6 3a b2 | 17 6c 92 bb 8e 36 c0 41 98 a2 7b 90 9b 6e 8f 13注:由于 CTAP1/U2F 认证器已经以这种格式生成签名值,出于一致性考虑,CTAP2 认证器也将以相同的格式生成签名值。
建议任何新定义的证明格式不要使用 ASN.1 编码,而是将签名表示为没有内部结构的等效固定长度字节数组,并使用 [RFC8152] 和 [RFC8230] 中定义的与 COSE 签名相同的表示形式。
以下签名格式定义满足此要求,并作为为此处未明确提及的其他签名算法推导相同格式的示例
-
对于 COSEAlgorithmIdentifier -257 (RS256),
sig必须包含使用 [RFC8017] 第 8.2.1 节中定义的 RSASSA-PKCS1-v1_5 签名方案生成的签名(以 SHA-256 作为哈希函数)。该签名不进行 ASN.1 封装。 -
对于 COSEAlgorithmIdentifier -37 (PS256),
sig必须包含使用 [RFC8017] 第 8.1.1 节中定义的 RSASSA-PSS 签名方案生成的签名(以 SHA-256 作为哈希函数)。该签名不进行 ASN.1 封装。
7. WebAuthn 依赖方 (Relying Party) 操作
注册或认证仪式始于 WebAuthn 依赖方创建 PublicKeyCredentialCreationOptions 或 PublicKeyCredentialRequestOptions 对象,该对象编码了仪式的参数。依赖方应注意在此阶段不要泄露敏感信息;详情请参阅 § 14.6.2 用户名枚举。
在成功执行 create() 或 get() 后,依赖方的脚本会从客户端接收到一个包含 AuthenticatorAttestationResponse 或 AuthenticatorAssertionResponse 结构的 PublicKeyCredential。然后必须使用本规范范围之外的方法将该结构的内容发送给依赖方服务器。本节描述了依赖方在收到这些结构时必须执行的操作。
7.1. 注册新凭据
-
令 options 为一个新的
PublicKeyCredentialCreationOptions结构,该结构配置为依赖方仪式所需的内容。 -
调用
navigator.credentials.create()并将 options 作为选项传入。令 credential 为成功解析的 Promise 的结果。如果 Promise 被拒绝,则中止仪式并提示用户可见的错误,或根据被拒绝的 Promise 中可用的上下文引导用户体验。例如,如果 Promise 被拒绝并带有等同于 "publicKeyInvalidStateError" 的错误代码,可能会指示用户使用不同的认证器。有关不同错误上下文及其产生原因的信息,请参阅 § 6.3.2 The authenticatorMakeCredential Operation。 -
令 response 为
credential.。如果 response 不是responseAuthenticatorAttestationResponse的实例,则中止仪式并提示用户可见的错误。 -
令 clientExtensionResults 为调用
credential.的结果。getClientExtensionResults() -
令 JSONtext 为对
response.的值运行 UTF-8 解码的结果。clientDataJSON注:只要其产生的结果与 UTF-8 解码算法所产生的结果相同,使用任何 UTF-8 解码实现都是可接受的。特别是,必须去除任何前导的字节顺序标记 (BOM)。
-
令 C 为在凭据创建期间声明收集到的客户端数据,它是对 JSONtext 运行特定于实现的 JSON 解析器的结果。
注:C 可以是任何特定于实现的数据结构表示,只要 C 的组件如本算法所要求的那样是可引用的即可。
-
验证
C.的值是否为typewebauthn.create。 -
验证
C.的值是否与依赖方的来源 (origin) 匹配。origin -
验证
C.的值是否与获得断言所使用的 TLS 连接的令牌绑定 (Token Binding) 状态匹配。如果该 TLS 连接使用了令牌绑定,还需验证tokenBinding.statusC.是否与该连接的令牌绑定 ID 的 base64url 编码匹配。tokenBinding.id -
令 hash 为使用 SHA-256 对
response.进行哈希计算的结果。clientDataJSON -
对
AuthenticatorAttestationResponse结构的attestationObject字段执行 CBOR 解码,以获得证明语句格式 fmt、认证器数据 authData 和证明语句 attStmt。 -
验证 authData 中
flags的用户在场 (User Present) 位是否已设置。 -
如果此注册需要用户验证,请验证 authData 中
flags的用户已验证 (User Verified) 位是否已设置。 -
验证 authData 中凭据公钥中的 "alg" 参数是否与
options.中条目之一的pubKeyCredParamsalg属性匹配。 -
考虑在
options.中给出的客户端扩展输入值,以及依赖方关于未经请求的扩展(即未指定为extensionsoptions.一部分的扩展)的任何特定策略,验证 clientExtensionResults 中的客户端扩展输出和 authData 中extensionsextensions的认证器扩展输出的值是否符合预期。通常情况下,“符合预期”的含义特定于依赖方以及正在使用的扩展。注:客户端平台可能会制定本地策略,设置额外的认证器扩展或客户端扩展,从而导致认证器扩展输出或客户端扩展输出中出现最初未指定为
options.一部分的值。依赖方必须准备好处理此类情况,无论是忽略这些未经请求的扩展还是拒绝证明。依赖方可以根据本地策略和正在使用的扩展做出此决定。extensions -
通过对 fmt 与受支持的 WebAuthn 证明语句格式标识符集进行 USASCII 大小写敏感匹配来确定证明语句格式。注册的 WebAuthn 证明语句格式标识符值的最新列表维护在由 [RFC8809] 建立的 IANA “WebAuthn 证明语句格式标识符”注册表 [IANA-WebAuthn-Registries] 中。
-
使用证明语句格式 fmt 的验证过程(给定 attStmt、authData 和 hash),验证 attStmt 是否为正确的证明语句,并传达有效的证明签名。
注:每种证明语句格式都指定了自己的验证过程。有关最初定义的格式,请参阅 § 8 已定义的证明语句格式;有关最新列表,请参阅 [IANA-WebAuthn-Registries]。
-
如果验证成功,请从受信任的来源或策略中获取该证明类型和证明语句格式 fmt 的可接受信任锚点(即证明根证书)列表。例如,FIDO 元数据服务 [FIDOMetadataService] 提供了一种获取此类信息的方法,它使用 authData 中
attestedCredentialData里的aaguid。 -
使用第 19 步中验证过程的输出,按如下方式评估证明的可信度
-
检查
credentialId是否尚未注册给任何其他用户。如果请求注册的凭据已经注册给不同的用户,依赖方应使此注册仪式失败,或者可以选择接受该注册,例如在删除旧注册的同时。 -
如果证明语句 attStmt 验证成功且被发现是可信的,则将新凭据注册到
options.中指定的账户。user-
将用户账户与
authData.attestedCredentialData中的credentialId和credentialPublicKey相关联,以适合依赖方系统的方式。 -
将
credentialId与初始化为authData.signCount值的新存储签名计数器相关联。
建议同时也
-
将
credentialId与通过调用credential.返回的传输提示相关联。该值在存储前后都不应被修改。建议在未来的response.getTransports()get()调用中使用此值来填充allowCredentials选项的transports,以帮助客户端了解如何找到合适的认证器。
-
-
如果证明语句 attStmt 验证成功,但根据上述第 21 步判定为不可信,则依赖方应使注册仪式失败。
注意:但是,如果策略允许,依赖方可以注册凭据 ID 和凭据公钥,但将该凭据视为自证明凭据(请参阅 § 6.5.3 证明类型)。如果这样做,依赖方声明没有加密证据证明该公钥凭据是由特定的认证器模型生成的。有关更详细的讨论,请参阅 [FIDOSecRef] 和 [UAFProtocol]。
验证证明对象要求依赖方在上述第 20 步中拥有确定可接受信任锚点的受信任方法。此外,如果正在使用证书,依赖方必须能够访问中间 CA 证书的证书状态信息。如果客户端未在证明信息中提供证书链,依赖方还必须能够构建证明证书链。
7.2. 验证认证断言
-
令 options 为一个新的
PublicKeyCredentialRequestOptions结构,该结构配置为依赖方仪式所需的内容。如果
options.存在,则每个条目的allowCredentialstransports成员应设置为注册相应凭据时credential.返回的值。response.getTransports() -
调用
navigator.credentials.get()并将 options 作为选项传入。令 credential 为成功解析的 Promise 的结果。如果 Promise 被拒绝,则中止仪式并提示用户可见的错误,或根据被拒绝的 Promise 中可用的上下文引导用户体验。有关不同错误上下文及其产生原因的信息,请参阅 § 6.3.3 The authenticatorGetAssertion Operation。publicKey -
令 response 为
credential.。如果 response 不是responseAuthenticatorAssertionResponse的实例,则中止仪式并提示用户可见的错误。 -
令 clientExtensionResults 为调用
credential.的结果。getClientExtensionResults() -
如果
options.不为空,请验证allowCredentialscredential.是否标识了idoptions.中列出的公钥凭据之一。allowCredentials -
确定正在进行认证的用户,并验证该用户是
credential.所标识的公钥凭据源 credentialSource 的所有者。id- 如果用户在认证仪式启动前已被识别(例如,通过用户名或 Cookie),
-
验证被识别的用户是否为 credentialSource 的所有者。如果
response.存在,令 userHandle 为其值。验证 userHandle 是否也映射到同一个用户。userHandle - 如果用户在认证仪式启动前未被识别,
-
验证
response.是否存在,且该值识别的用户是否为 credentialSource 的所有者。userHandle
-
使用
credential.(或者idcredential.,如果 base64url 编码不适合您的用例),查找对应的凭据公钥,并令 credentialPublicKey 为该凭据公钥。rawId -
令 cData、authData 和 sig 分别表示 response 的
clientDataJSON、authenticatorData和signature的值。 -
令 JSONtext 为对 cData 的值运行 UTF-8 解码的结果。
注:只要其产生的结果与 UTF-8 解码算法所产生的结果相同,使用任何 UTF-8 解码实现都是可接受的。特别是,必须去除任何前导的字节顺序标记 (BOM)。
-
令 C 为声明用于签名的客户端数据,它是对 JSONtext 运行特定于实现的 JSON 解析器的结果。
注:C 可以是任何特定于实现的数据结构表示,只要 C 的组件如本算法所要求的那样是可引用的即可。
-
验证
C.的值是否为字符串typewebauthn.get。 -
验证
C.的值是否与获得证明所使用的 TLS 连接的令牌绑定状态匹配。如果该 TLS 连接使用了令牌绑定,还需验证tokenBinding.statusC.是否与该连接的令牌绑定 ID 的 base64url 编码匹配。tokenBinding.id -
验证 authData 中的
rpIdHash是否为依赖方预期的 RP ID 的 SHA-256 哈希值。注:如果使用 appid 扩展,此步骤需要一些特殊的逻辑。有关详细信息,请参阅 § 10.1 FIDO AppID 扩展 (appid)。
-
考虑在
options.中给出的客户端扩展输入值,以及依赖方关于未经请求的扩展(即未指定为extensionsoptions.一部分的扩展)的任何特定策略,验证 clientExtensionResults 中的客户端扩展输出和 authData 中extensionsextensions的认证器扩展输出的值是否符合预期。通常情况下,“符合预期”的含义特定于依赖方以及正在使用的扩展。注:客户端平台可能会制定本地策略,设置额外的认证器扩展或客户端扩展,从而导致认证器扩展输出或客户端扩展输出中出现最初未指定为
options.一部分的值。依赖方必须准备好处理此类情况,无论是忽略这些未经请求的扩展还是拒绝断言。依赖方可以根据本地策略和正在使用的扩展做出此决定。extensions -
令 hash 为使用 SHA-256 对 cData 进行哈希计算的结果。
-
使用 credentialPublicKey,验证 sig 是否为 authData 和 hash 的二进制连接上的有效签名。
注:此验证步骤与 FIDO U2F 认证器生成的签名兼容。请参阅 § 6.1.2 FIDO U2F 签名格式兼容性。
-
令 storedSignCount 为与
credential.相关联的已存储签名计数器值。如果 authData.idsignCount不为零或 storedSignCount 不为零,则运行以下子步骤
8. 已定义的证明语句格式
WebAuthn 支持可插拔的证明语句格式。本节定义了一组初始格式。
8.1. 证明语句格式标识符
证明语句格式由字符串标识,称为证明语句格式标识符,由证明语句格式的作者选择。
证明语句格式标识符应在由 [RFC8809] 建立的 IANA “WebAuthn 证明语句格式标识符”注册表 [IANA-WebAuthn-Registries] 中注册。所有已注册的证明语句格式标识符在惯例上彼此唯一。
未注册的证明语句格式标识符应使用小写反向域名命名,并使用开发者注册的域名,以确保标识符的唯一性。所有证明语句格式标识符的最大长度必须为 32 个八位字节,且必须仅包含可打印的 USASCII 字符,不包括反斜杠和双引号,即 [RFC5234] 中定义的 VCHAR,但不包含 %x22 和 %x5c。
注:这意味着基于域名的证明语句格式标识符必须仅包含 LDH 标签 [RFC5890]。
实现必须以大小写敏感的方式匹配 WebAuthn 证明语句格式标识符。
可能存在多个版本的证明语句格式应在标识符中包含版本信息。实际上,不同的版本被视为不同的格式,例如,packed2 作为 § 8.2 打包证明语句格式的新版本。
以下各节介绍了一组当前定义和注册的证明语句格式及其标识符。已注册 WebAuthn 扩展的最新列表维护在由 [RFC8809] 建立的 IANA “WebAuthn 证明语句格式标识符”注册表 [IANA-WebAuthn-Registries] 中。
8.2. 打包证明语句格式
这是一种 WebAuthn 优化证明语句格式。它使用一种非常紧凑但仍可扩展的编码方法。它可由资源受限的认证器(例如安全元件)实现。
- 证明声明格式标识符
-
packed
- 支持的证明类型
- 语法
-
打包证明语句的语法由以下 CDDL 定义
$$attStmtType //= ( fmt: "packed", attStmt: packedStmtFormat ) packedStmtFormat = { alg: COSEAlgorithmIdentifier, sig: bytes, x5c: [ attestnCert: bytes, * (caCert: bytes) ] } // { alg: COSEAlgorithmIdentifier sig: bytes, }各字段的语义如下
- alg
-
包含用于生成证明签名的算法标识符的
COSEAlgorithmIdentifier。 - sig
-
包含证明签名的字节字符串。
- x5c
-
此数组的元素包含 attestnCert 及其证书链(如有),均以 X.509 格式编码。证明证书 attestnCert 必须是数组中的第一个元素。
- attestnCert
-
以 X.509 格式编码的证明证书。
- 签名过程
-
此证明语句格式的签名过程类似于生成断言签名的过程。
-
令 authenticatorData 表示用于证明的认证器数据,令 clientDataHash 表示序列化客户端数据的哈希值。
-
如果正在使用 Basic 或 AttCA 证明,认证器通过连接 authenticatorData 和 clientDataHash 并使用通过特定于认证器的机制选择的证明私钥对结果进行签名来产生 sig。它将 x5c 设置为 attestnCert 后跟相关证书链(如有)。它将 alg 设置为证明私钥的算法。
-
如果正在使用 自证明,认证器通过连接 authenticatorData 和 clientDataHash 并使用凭据私钥对结果进行签名来产生 sig。它将 alg 设置为凭据私钥的算法,并省略其他字段。
-
- 验证过程
-
给定验证过程输入 attStmt、authenticatorData 和 clientDataHash,验证过程如下:
-
验证 attStmt 是否为符合上述语法的有效 CBOR,并对其执行 CBOR 解码以提取包含的字段。
-
如果存在 x5c
-
验证 sig 是否是使用 attestnCert 中的证明公钥和 alg 中指定的算法对 authenticatorData 和 clientDataHash 的连接进行的有效签名。
-
验证 attestnCert 是否满足 § 8.2.1 打包证明语句证书要求中的要求。
-
如果 attestnCert 包含 OID 为
1.3.6.1.4.1.45724.1.1.4(id-fido-gen-ce-aaguid) 的扩展,验证该扩展的值是否与 authenticatorData 中的aaguid匹配。该扩展不得标记为关键。
-
-
如果不存在 x5c,则正在使用自证明。
-
验证 alg 是否与 authenticatorData 中
credentialPublicKey的算法相匹配。 -
验证 sig 是否是使用凭据公钥和 alg 对 authenticatorData 和 clientDataHash 的连接进行的有效签名。
-
-
8.2.1. 打包证明语句证书要求
证明证书必须具有以下字段/扩展:
-
版本必须设置为 3(由值为 2 的 ASN.1 INTEGER 表示)。
-
主体字段必须设置为
- Subject-C
-
指定认证器供应商注册所在国家的 ISO 3166 代码 (PrintableString)
- Subject-O
-
认证器供应商的法定名称 (UTF8String)
- Subject-OU
-
文字字符串 “Authenticator Attestation” (UTF8String)
- Subject-CN
-
供应商选择的 UTF8String
-
如果相关证明根证书用于多个认证器型号,则必须存在扩展 OID
1.3.6.1.4.1.45724.1.1.4(id-fido-gen-ce-aaguid),其中包含作为 16 字节 OCTET STRING 的 AAGUID。该扩展不得标记为关键。请注意,X.509 扩展将值的 DER 编码编码在 OCTET STRING 中。因此,AAGUID 必须包装在两个 OCTET STRINGS 中才能有效。这是一个示例,已编码的扩展结构
30 21 -- SEQUENCE 06 0b 2b 06 01 04 01 82 e5 1c 01 01 04 -- 1.3.6.1.4.1.45724.1.1.4 04 12 -- OCTET STRING 04 10 -- OCTET STRING cd 8c 39 5c 26 ed ee de -- AAGUID 65 3b 00 79 7d 03 ca 3c -
基本约束扩展的 CA 组件必须设置为
false。 -
带有
id-ad-ocsp条目的颁发机构信息访问 (AIA) 扩展和 CRL 分发点扩展 [RFC5280] 均为可选,因为许多证明证书的状态可通过认证器元数据服务获得。例如,请参阅 FIDO 元数据服务 [FIDOMetadataService]。
8.3. TPM 证明语句格式
此证明语句格式通常由使用可信平台模块 (TPM) 作为其加密引擎的认证器使用。
- 证明声明格式标识符
-
tpm
- 支持的证明类型
- 语法
-
TPM 证明语句的语法如下
$$attStmtType // = ( fmt: "tpm", attStmt: tpmStmtFormat ) tpmStmtFormat = { ver: "2.0", ( alg: COSEAlgorithmIdentifier, x5c: [ aikCert: bytes, * (caCert: bytes) ] ) sig: bytes, certInfo: bytes, pubArea: bytes }以上各字段的语义如下
- ver
-
签名所符合的 TPM 规范版本。
- alg
-
包含用于生成证明签名的算法标识符的
COSEAlgorithmIdentifier。 - x5c
-
X.509 编码的 aikCert 及其证书链。
- aikCert
-
用于证明的 AIK 证书(以 X.509 编码)。
- sig
-
证明签名,采用 [TPMv2-Part2] 第 11.3.4 节中指定的 TPMT_SIGNATURE 结构形式。
- certInfo
-
计算上述签名的 TPMS_ATTEST 结构,如 [TPMv2-Part2] 第 10.12.8 节所指定。
- pubArea
-
TPM 用来表示凭据公钥的 TPMT_PUBLIC 结构(请参阅 [TPMv2-Part2] 第 12.2.4 节)。
- 签名过程
-
令 authenticatorData 表示用于证明的认证器数据,令 clientDataHash 表示序列化客户端数据的哈希值。
连接 authenticatorData 和 clientDataHash 以形成 attToBeSigned。
使用 [TPMv2-Part3] 第 18.2 节中指定的程序生成签名,使用证明私钥并将
extraData参数设置为 attToBeSigned 的摘要(使用对应于“alg”签名算法的哈希算法)。(对于“RS256”算法,这将是 SHA-256 摘要。)将 pubArea 字段设置为凭据公钥的公共区域,将 certInfo 字段设置为同名输出参数,并将 sig 字段设置为从上述程序获得的签名。
- 验证过程
-
给定验证过程输入 attStmt、authenticatorData 和 clientDataHash,验证过程如下:
验证 attStmt 是否为符合上述语法的有效 CBOR,并对其执行 CBOR 解码以提取包含的字段。
验证由 pubArea 的
parameters和unique字段指定的公钥是否与 authenticatorData 中attestedCredentialData里的credentialPublicKey完全相同。连接 authenticatorData 和 clientDataHash 以形成 attToBeSigned。
验证 certInfo 是否有效
-
验证
magic是否设置为TPM_GENERATED_VALUE。 -
验证
type是否设置为TPM_ST_ATTEST_CERTIFY。 -
验证
extraData是否设置为使用“alg”中采用的哈希算法对 attToBeSigned 进行哈希计算的结果。 -
验证
attested是否包含 [TPMv2-Part2] 第 10.12.3 节中指定的 TPMS_CERTIFY_INFO 结构,该结构的name字段包含 pubArea 的有效名称(通过使用 pubArea 的nameAlg字段中的算法,按照 [TPMv2-Part1] 第 16 节中指定的程序计算)。 -
验证是否存在 x5c。
-
请注意,“标准证明结构”[TPMv2-Part1] 第 31.2 节中的其余字段,即
qualifiedSigner、clockInfo和firmwareVersion将被忽略。这些字段可用作风险引擎的输入。 -
验证 sig 是否是使用 aikCert 中的证明公钥和 alg 中指定的算法对 certInfo 进行的有效签名。
-
验证 aikCert 是否满足 § 8.3.1 TPM 证明语句证书要求中的要求。
-
如果 aikCert 包含 OID 为
1.3.6.1.4.1.45724.1.1.4(id-fido-gen-ce-aaguid) 的扩展,验证该扩展的值是否与 authenticatorData 中的aaguid匹配。
-
8.3.1. TPM 证明语句证书要求
TPM 证明证书必须具有以下字段/扩展:
-
版本必须设置为 3。
-
主体字段必须设置为空。
-
主体备用名称扩展必须按照 [TPMv2-EK-Profile] 第 3.2.9 节的定义进行设置。
-
扩展密钥用法扩展必须包含 OID
2.23.133.8.3("joint-iso-itu-t(2) internationalorganizations(23) 133 tcg-kp(8) tcg-kp-AIKCertificate(3)")。 -
基本约束扩展的 CA 组件必须设置为
false。 -
带有
id-ad-ocsp条目的颁发机构信息访问 (AIA) 扩展和 CRL 分发点扩展 [RFC5280] 均为可选,因为许多证明证书的状态可通过元数据服务获得。例如,请参阅 FIDO 元数据服务 [FIDOMetadataService]。
8.4. Android 密钥证明语句格式
当所讨论的认证器是 Android "N" 或更高版本平台上的平台认证器时,证明语句基于 Android 密钥证明。在这种情况下,证明语句由在安全操作环境中运行的组件产生,但用于证明的认证器数据在此环境之外产生。WebAuthn 依赖方应检查声称用于证明的认证器数据是否与证明证书扩展数据中的字段一致。
- 证明声明格式标识符
-
android-key
- 支持的证明类型
- 语法
-
Android 密钥证明语句仅由 Android 证明语句组成,该语句是一系列 DER 编码的 X.509 证书。请参阅 Android 开发者文档。其语法定义如下
$$attStmtType //= ( fmt: "android-key", attStmt: androidStmtFormat ) androidStmtFormat = { alg: COSEAlgorithmIdentifier, sig: bytes, x5c: [ credCert: bytes, * (caCert: bytes) ] } - 签名过程
-
令 authenticatorData 表示用于证明的认证器数据,令 clientDataHash 表示序列化客户端数据的哈希值。
通过调用
keyStore.getCertificateChain(myKeyUUID)并将 clientDataHash 作为挑战值(例如,通过使用 setAttestationChallenge)来请求 Android 密钥证明。将 x5c 设置为返回值。认证器通过连接 authenticatorData 和 clientDataHash 并使用凭据私钥对结果进行签名来产生 sig。它将 alg 设置为签名格式的算法。
- 验证过程
-
给定验证过程输入 attStmt、authenticatorData 和 clientDataHash,验证过程如下:
-
验证 attStmt 是否为符合上述语法的有效 CBOR,并对其执行 CBOR 解码以提取包含的字段。
-
验证 sig 是否是使用 x5c 中第一个证书的公钥和 alg 中指定的算法对 authenticatorData 和 clientDataHash 的连接进行的有效签名。
-
验证 x5c 中第一个证书的公钥是否与 authenticatorData 中
attestedCredentialData里的credentialPublicKey匹配。 -
使用来自扩展数据证明证书的相应授权列表验证以下内容:
-
AuthorizationList.allApplications字段不存在于任何一个授权列表(softwareEnforced或teeEnforced)中,因为 PublicKeyCredential 必须限定 (scoped) 到 RP ID。 -
对于以下内容,如果 RP 希望仅接受来自受信任执行环境的密钥,则仅使用
teeEnforced授权列表,否则使用teeEnforced和softwareEnforced的并集。-
AuthorizationList.origin字段中的值等于KM_ORIGIN_GENERATED。 -
AuthorizationList.purpose字段中的值等于KM_PURPOSE_SIGN。
-
-
-
8.4.1. Android 密钥证明语句证书要求
Android 密钥证明证明证书的 Android 密钥证明证书扩展数据由 OID 1.3.6.1.4.1.11129.2.1.17 标识,其模式定义在 Android 开发者文档中。
8.5. Android SafetyNet 证明语句格式
当认证器是某些 Android 平台上的平台认证器时,证明语句可以基于 SafetyNet API。在这种情况下,认证器数据完全由 SafetyNet API 的调用者(通常是在 Android 平台上运行的应用程序)控制,证明语句提供了一些关于平台健康状况和调用应用程序身份的声明(有关详细信息,请参阅 SafetyNet 文档)。
- 证明声明格式标识符
-
android-safetynet
- 支持的证明类型
- 语法
-
Android 证明语句的语法定义如下
$$attStmtType //= ( fmt: "android-safetynet", attStmt: safetynetStmtFormat ) safetynetStmtFormat = { ver: text, response: bytes }以上各字段的语义如下
- ver
-
负责提供 SafetyNet API 的 Google Play 服务版本号。
- response (响应)
-
SafetyNet API 的 getJwsResult() 调用的 UTF-8 编码结果。此值是一个采用紧凑序列化形式的 JWS [RFC7515] 对象(请参阅 SafetyNet 在线文档)。
- 签名过程
-
令 authenticatorData 表示用于证明的认证器数据,令 clientDataHash 表示序列化客户端数据的哈希值。
连接 authenticatorData 和 clientDataHash,对连接后的字符串执行 SHA-256 哈希计算,并令该哈希结果构成 attToBeSigned。
请求 SafetyNet 证明,将 attToBeSigned 作为 nonce 值提供。将 response 设置为结果,并将 ver 设置为认证器中运行的 Google Play 服务版本。
- 验证过程
-
给定验证过程输入 attStmt、authenticatorData 和 clientDataHash,验证过程如下:
-
验证 attStmt 是否为符合上述语法的有效 CBOR,并对其执行 CBOR 解码以提取包含的字段。
-
通过遵循 SafetyNet 在线文档指示的步骤,验证 response 是否为 ver 版本的有效 SafetyNet 响应。截至撰写本文时,SafetyNet 响应只有一种格式,且 ver 保留供将来使用。
-
验证 response 有效负载中的
nonce属性是否与 authenticatorData 和 clientDataHash 连接的 SHA-256 哈希值的 Base64 编码相同。 -
通过遵循 SafetyNet 在线文档中的步骤,验证 SafetyNet 响应确实来自 SafetyNet 服务。
-
8.6. FIDO U2F 证明语句格式
此证明语句格式与使用 [FIDO-U2F-Message-Formats] 中定义的格式的 FIDO U2F 认证器配合使用。
- 证明声明格式标识符
-
fido-u2f
- 支持的证明类型
- 语法
-
FIDO U2F 证明语句的语法定义如下
$$attStmtType //= ( fmt: "fido-u2f", attStmt: u2fStmtFormat ) u2fStmtFormat = { x5c: [ attestnCert: bytes ], sig: bytes }以上各字段的语义如下
- x5c
-
一个包含 X.509 格式证明证书的单元素数组。
- sig
-
证明签名。该签名是对客户端从认证器接收到的(原始)U2F 注册响应消息 [FIDO-U2F-Message-Formats] 进行计算的。
- 签名过程
-
如果被证明凭据的凭据公钥不是 -7 ("ES256") 算法,请停止并返回错误。否则,令 authenticatorData 表示用于证明的认证器数据,令 clientDataHash 表示序列化客户端数据的哈希值。(由于使用 SHA-256 对序列化的客户端数据进行哈希处理,clientDataHash 将为 32 字节长。)
按照 [FIDO-U2F-Message-Formats] 第 4.3 节中的规定生成注册响应消息,应用程序参数设置为给定凭据所限定到的 RP ID 的 SHA-256 哈希值,挑战参数设置为 clientDataHash,密钥句柄参数设置为给定凭据的凭据 ID。将此注册响应消息的原始签名部分(即没有用户公钥、密钥句柄和证明证书的部分)设置为 sig,并将证明公钥的证明证书设置为 x5c。
- 验证过程
-
给定验证过程输入 attStmt、authenticatorData 和 clientDataHash,验证过程如下:
-
验证 attStmt 是否为符合上述语法的有效 CBOR,并对其执行 CBOR 解码以提取包含的字段。
-
检查 x5c 是否恰好有一个元素,并令 attCert 为该元素。令 certificate public key 为 attCert 传达的公钥。如果 certificate public key 不是 P-256 曲线上的椭圆曲线 (EC) 公钥,请终止此算法并返回适当的错误。
-
从 authenticatorData 中提取声称的 rpIdHash,并从 authenticatorData
attestedCredentialData中提取声称的 credentialId 和 credentialPublicKey。 -
将 COSE_KEY 格式的 credentialPublicKey(请参阅 [RFC8152] 的 第 7 节)转换为原始 ANSI X9.62 公钥格式(请参阅 [FIDO-Registry] 中 第 3.6.2 节“公钥表示格式”的 ALG_KEY_ECC_X962_RAW)。
-
令 x 为 credentialPublicKey 中对应于 "-2" 键(表示 x 坐标)的值,并确认其大小为 32 字节。如果大小不同或未找到 "-2" 键,请终止此算法并返回适当的错误。
-
令 y 为 credentialPublicKey 中对应于 "-3" 键(表示 y 坐标)的值,并确认其大小为 32 字节。如果大小不同或未找到 "-3" 键,请终止此算法并返回适当的错误。
-
令 publicKeyU2F 为连接
0x04 || x || y的结果。注意: 这表示未压缩的 ECC 密钥格式。
-
-
令 verificationData 为 (0x00 || rpIdHash || clientDataHash || credentialId || publicKeyU2F) 的拼接(参见 第 4.3 节 [FIDO-U2F-Message-Formats])。
-
使用 verificationData 和 证书公钥 (certificate public key),按照 [SEC1] 第 4.1.4 节验证 sig,并在第二步中使用 SHA-256 作为哈希函数。
-
8.7. None 认证声明格式
当 WebAuthn 依赖方 (Relying Party) 表示其不希望接收认证信息时,None 认证声明格式用于替换任何由 认证器 (authenticator) 提供的 认证声明,参见 § 5.4.7 认证传输偏好枚举 (enum AttestationConveyancePreference)。
如果 认证器 不支持 认证,该 认证器 也可以直接生成此格式的认证声明。
- 证明声明格式标识符
-
none(无)
- 支持的证明类型
- 语法
-
None 认证声明的语法定义如下
$$attStmtType //= ( fmt: "none", attStmt: emptyMap ) emptyMap = {} - 签名过程
-
返回上述定义的固定认证声明。
- 验证过程
8.8. Apple 匿名认证声明格式
此认证声明格式专供支持 WebAuthn 的特定类型的 Apple 设备使用。
- 证明声明格式标识符
-
apple
- 支持的证明类型
- 语法
-
Apple 认证声明的语法定义如下
$$attStmtType //= ( fmt: "apple", attStmt: appleStmtFormat ) appleStmtFormat = { x5c: [ credCert: bytes, * (caCert: bytes) ] }以上各字段的语义如下
- x5c
-
credCert 及其证书链,每个均以 X.509 格式编码。
- credCert
-
用于认证的凭据公钥证书,以 X.509 格式编码。
- 签名过程
-
-
令 authenticatorData 表示认证的认证器数据,令 clientDataHash 表示 序列化客户端数据的哈希。
-
拼接 authenticatorData 和 clientDataHash 以形成 nonceToHash。
-
对 nonceToHash 执行 SHA-256 哈希运算以生成 nonce。
-
让 Apple 匿名认证 CA 为 凭据公钥 生成一个 X.509 证书,并将 nonce 作为 OID 为
1.2.840.113635.100.8.2的证书扩展包含在内。credCert 表示此证书。credCert 因此作为认证的证明,而包含的 nonce 则证明认证是实时的。此外,nonce 还保护了 authenticatorData 和 客户端数据 的完整性。 -
将 x5c 设置为 credCert 及其证书链。
-
- 验证过程
-
给定验证过程输入 attStmt、authenticatorData 和 clientDataHash,验证过程如下
-
验证 attStmt 是否为符合上述语法的有效 CBOR,并对其执行 CBOR 解码以提取包含的字段。
-
拼接 authenticatorData 和 clientDataHash 以形成 nonceToHash。
-
对 nonceToHash 执行 SHA-256 哈希运算以生成 nonce。
-
验证 nonce 是否等于 credCert 中 OID 为
1.2.840.113635.100.8.2的扩展的值。 -
验证 凭据公钥 是否等于 credCert 的主体公钥 (Subject Public Key)。
-
如果成功,返回特定于实现的表示认证类型 匿名化 CA 和认证信任路径 x5c 的值。
-
9. WebAuthn 扩展
生成 公钥凭据 以及请求和生成身份验证断言(如 § 5 Web 身份验证 API 中所定义)的机制,可以进行扩展以适应特定的用例。每种情况都通过定义 注册扩展 和/或 身份验证扩展 来解决。
每个扩展都是一个 客户端扩展,意味着该扩展涉及与客户端的通信及由客户端进行处理。客户端扩展定义了以下步骤和数据
-
navigator.credentials.create()的 注册扩展请求参数和响应值。 -
navigator.credentials.get()的 身份验证扩展请求参数和响应值。
当创建 公钥凭据 或请求 身份验证断言 时,WebAuthn 依赖方 可以请求使用一组扩展。如果客户端和/或 WebAuthn 认证器 支持这些扩展,它们将在所请求的操作期间被调用。依赖方 在 get() 调用(针对 身份验证扩展)或 create() 调用(针对 注册扩展)中将每个扩展的 客户端扩展输入 发送给 客户端。客户端 对 客户端平台 支持的每个扩展执行 客户端扩展处理,并通过包含 扩展标识符 和 客户端扩展输出 值,按照每个扩展的规定增加 客户端数据。
一个扩展也可以是一个 认证器扩展,意味着该扩展涉及与认证器的通信及由认证器进行处理。认证器扩展定义了以下步骤和数据
-
authenticatorMakeCredential 的 注册扩展请求参数和响应值。
-
authenticatorGetAssertion 的 身份验证扩展请求参数和响应值。
对于 认证器扩展,作为 客户端扩展处理 的一部分,客户端还会为每个扩展创建 CBOR 认证器扩展输入 值(通常基于相应的 客户端扩展输入 值),并在 create() 调用(针对 注册扩展)或 get() 调用(针对 身份验证扩展)中将它们传递给认证器。这些 认证器扩展输入 值以 CBOR 表示并作为名称-值对传递,其中 扩展标识符 作为名称,相应的 认证器扩展输入 作为值。认证器反过来对其支持的扩展执行额外的处理,并按照扩展的规定返回每个扩展的 CBOR 认证器扩展输出。认证器扩展 的 客户端扩展处理 的一部分是使用 认证器扩展输出 作为创建 客户端扩展输出 的输入。
所有 WebAuthn 扩展 对于客户端和认证器都是可选的。因此,依赖方 请求的任何扩展都可能被客户端浏览器或操作系统忽略而完全不传递给认证器,或者也可能被认证器忽略。在 WebAuthn API 处理中,忽略扩展绝不被视为失败,因此当 依赖方 在任何 API 调用中包含扩展时,它们必须准备好处理部分或全部这些扩展被忽略的情况。
希望支持尽可能广泛的扩展的客户端,可以选择将它们无法识别的任何扩展传递给认证器,只需将 客户端扩展输入 以 CBOR 编码即可生成 认证器扩展输入。所有 WebAuthn 扩展 的定义必须确保这种实现选择不会危及用户的安全或隐私。例如,如果一个扩展需要客户端处理,它可以定义为确保这种简单的透传将产生一个语义上无效的 认证器扩展输入 值,从而导致该扩展被认证器忽略。由于所有扩展都是可选的,这不会导致 API 操作的功能性失败。同样,客户端可以选择通过将 认证器扩展输出 值编码为 JSON,来为其无法理解的扩展生成 客户端扩展输出 值,前提是 CBOR 输出仅使用 JSON 中存在的类型。
当 客户端 选择透传其无法识别的扩展时,客户端扩展输入 中的 JavaScript 值被转换为 认证器扩展输入 中的 CBOR 值。当 JavaScript 值为 %ArrayBuffer% 时,它被转换为 CBOR 字节数组。当 JavaScript 值为非整数数字时,它被转换为 64 位 CBOR 浮点数。否则,当 JavaScript 类型对应于 JSON 类型时,转换使用 [RFC8949] 第 6.2 节(从 JSON 转换为 CBOR)中定义的规则完成,但对 JavaScript 类型值的输入进行操作,而不是对 JSON 类型值的输入。一旦完成这些转换,必须使用 CTAP2 规范化 CBOR 编码形式 对生成的 CBOR 进行规范化。
注意,JavaScript 数值转换规则导致当客户端透传其无法识别的扩展时,如果扩展使用浮点值,则 认证器 需要准备好以 CBOR 整数的形式接收这些值,以防 认证器 希望该扩展在没有实际 客户端 支持的情况下始终工作。当使用的浮点值恰好是整数时,就会发生这种情况。
同样,当客户端从其透传的无法识别的扩展接收输出时,认证器扩展输出 中的 CBOR 值被转换为 客户端扩展输出 中的 JavaScript 值。当 CBOR 值为字节字符串时,它被转换为 JavaScript %ArrayBuffer%(而不是 base64url 编码的字符串)。否则,当 CBOR 类型对应于 JSON 类型时,转换使用 [RFC8949] 第 6.1 节(从 CBOR 转换为 JSON)中定义的规则完成,但产生 JavaScript 类型值的输出,而不是 JSON 类型值的输出。
注意,一些客户端可能选择在功能标志下实现此透传功能。支持此功能可以促进创新,允许认证器试验新扩展,并允许 依赖方 在客户端中显式支持它们之前使用它们。
可以查阅由 [RFC8809] 建立的 IANA “WebAuthn 扩展标识符”注册表 [IANA-WebAuthn-Registries],以获取已注册的 WebAuthn 扩展 的最新列表。
9.1. 扩展标识符
扩展由一个字符串标识,称为 扩展标识符,由扩展作者选择。
扩展标识符应当在由 [RFC8809] 建立的 IANA “WebAuthn 扩展标识符”注册表 [IANA-WebAuthn-Registries] 中注册。所有已注册的扩展标识符本身都是唯一的。
未注册的扩展标识符应力求全局唯一,例如通过包含定义实体,如 myCompany_extension。
所有扩展标识符的长度最大必须为 32 个八位字节,且必须仅包含可打印的 USASCII 字符,不包括反斜杠和双引号,即 [RFC8809] 中定义的 VCHAR,但没有 %x22 和 %x5c。实现必须以区分大小写的方式匹配 WebAuthn 扩展标识符。
可能存在多个版本的扩展应注意在标识符中包含版本。实际上,不同版本因此被视为不同的扩展,例如 myCompany_extension_01
§ 10 定义的扩展 定义了额外的一组扩展及其标识符。有关已注册 WebAuthn 扩展标识符的最新列表,请参阅由 [RFC8809] 建立的 IANA “WebAuthn 扩展标识符”注册表 [IANA-WebAuthn-Registries]。
9.2. 定义扩展
扩展的定义必须指定一个 扩展标识符、一个通过 get() 或 create() 调用发送的 客户端扩展输入 参数、客户端扩展处理 规则以及一个 客户端扩展输出 值。如果扩展与认证器通信(意味着它是一个 认证器扩展),它还必须指定通过 authenticatorGetAssertion 或 authenticatorMakeCredential 调用发送的 CBOR 认证器扩展输入 参数、认证器扩展处理 规则以及 CBOR 认证器扩展输出 值。
任何由客户端处理的 客户端扩展 必须返回一个 客户端扩展输出 值,以便 WebAuthn 依赖方 知道该扩展已被客户端认可。同样,任何需要认证器处理的扩展必须返回一个 认证器扩展输出,以让 依赖方 知道该扩展已被认证器认可。如果扩展在其他方面不需要任何结果值,它应定义为返回一个 JSON 布尔值 客户端扩展输出 结果,设置为 true 以表示该扩展已被理解和处理。同样,任何不需要其他结果值的 认证器扩展 必须返回一个值,并应返回一个 CBOR 布尔值 认证器扩展输出 结果,设置为 true 以表示该扩展已被理解和处理。
9.3. 扩展请求参数
扩展定义了一个或两个请求参数。客户端扩展输入 是一个可以编码为 JSON 的值,由 WebAuthn 依赖方 在 get() 或 create() 调用中传递给客户端,而 CBOR 认证器扩展输入 则在这些调用的处理过程中由客户端针对 认证器扩展 传递给认证器。
依赖方 通过在 extensions 选项中包含一个条目到 create() 或 get() 调用中,同时请求使用一个扩展并设置其 客户端扩展输入。条目键是 扩展标识符,值是 客户端扩展输入。
注意: 其他文档已经指定了扩展输入不总是使用 扩展标识符 作为条目键的扩展。新扩展应遵循上述约定。
var assertionPromise= navigator. credentials. get({ publicKey: { // Other members omitted for brevity extensions: { // An "entry key" identifying the "webauthnExample_foobar" extension, // whose value is a map with two input parameters: "webauthnExample_foobar" : { foo: 42 , bar: "barfoo" } } } });
扩展定义必须指定其 客户端扩展输入 的有效值。客户端应忽略具有无效 客户端扩展输入 的扩展。如果一个扩展不需要来自 依赖方 的任何参数,它应定义为采用一个布尔客户端参数,设置为 true 以表示该扩展是由 依赖方 请求的。
仅影响客户端处理的扩展不需要指定 认证器扩展输入。具有认证器处理的扩展必须指定从 客户端扩展输入 计算 认证器扩展输入 的方法,并且必须通过定义 组套接字 (group sockets) $$extensionInput 和 $$extensionOutput 的额外选择(使用 扩展标识符 作为条目键),为 CDDL 类型 AuthenticationExtensionsAuthenticatorInputs 和 AuthenticationExtensionsAuthenticatorOutputs 定义扩展。不需要输入参数、因此被定义为采用设置为 true 的布尔 客户端扩展输入 值的扩展,应将 认证器扩展输入 也定义为常量布尔值 true(CBOR 主类型 7,值 21)。
以下示例定义了一个 标识符 为 webauthnExample_foobar 的扩展,它采用无符号整数作为 认证器扩展输入,并返回一个包含至少一个字节字符串的数组作为 认证器扩展输出
$$extensionInput //= ( webauthnExample_foobar: uint ) $$extensionOutput //= ( webauthnExample_foobar: [+ bytes] )
注意: 扩展应力求定义尽可能小的认证器参数。一些认证器通过低带宽链路(如低功耗蓝牙或 NFC)进行通信。
9.4. 客户端扩展处理
扩展可能在凭据创建或断言生成期间对 客户端 定义额外的处理要求。该扩展的 客户端扩展输入 被用作此客户端处理的输入。对于每个受支持的 客户端扩展,客户端会将一个条目添加到 clientExtensions 映射 (map) 中,以 扩展标识符 作为键,以扩展的 客户端扩展输入 作为值。
同样,客户端扩展输出 在 getClientExtensionResults() 的结果中表示为一个字典,以 扩展标识符 作为键,以每个扩展的 客户端扩展输出 值作为值。像 客户端扩展输入 一样,客户端扩展输出 是一个可以编码为 JSON 的值。严禁为被忽略的扩展返回任何值。
需要认证器处理的扩展必须定义确定 CBOR 认证器扩展输入 的过程,以及确定 CBOR 认证器扩展输出 的过程,从而由此确定 客户端扩展输出。
9.5. 认证器扩展处理
每个已处理的 认证器扩展 的 CBOR 认证器扩展输入 值都被包含在 authenticatorMakeCredential 和 authenticatorGetAssertion 操作的 extensions 参数中。extensions 参数是一个 CBOR 映射,其中每个键是一个 扩展标识符,对应的值是该扩展的 认证器扩展输入。
同样,扩展输出表示在 认证器数据 的 extensions 部分。认证器数据 的 extensions 部分是一个 CBOR 映射,其中每个键是一个 扩展标识符,对应的值是该扩展的 认证器扩展输出。
对于每个受支持的扩展,该扩展的 认证器扩展处理 规则被用于从 认证器扩展输入 以及可能的其他输入中创建 认证器扩展输出。严禁为被忽略的扩展返回任何值。
10. 定义的扩展
本节定义了额外的一组扩展,将在由 [RFC8809] 建立的 IANA “WebAuthn 扩展标识符”注册表 [IANA-WebAuthn-Registries] 中注册。这些扩展可由以广泛互操作性为目标的代理实现。
10.1. FIDO AppID 扩展 (appid)
此扩展允许那些先前使用旧版 FIDO U2F JavaScript API [FIDOU2FJavaScriptAPI] 注册了凭据的 WebAuthn 依赖方 请求 断言。FIDO API 对 依赖方 使用另一种称为 AppID [FIDO-APPID] 的标识符,并且使用这些 API 创建的任何凭据都将 限定范围 (scoped) 在该标识符下。如果没有此扩展,它们将需要被重新注册,以便将其 限定范围 在一个 RP ID 下。
除了设置 appid 扩展输入之外,使用此扩展还需要 依赖方 进行一些额外的处理,以允许用户使用其注册的 U2F 凭据进行 身份验证
-
在
get()方法的allowCredentials选项中列出所需的 U2F 凭据-
将
type成员设置为public-key。 -
将
id成员设置为所需凭据各自的 U2F 密钥句柄。注意,U2F 密钥句柄通常使用 base64url 编码,但在用于id时必须解码为其二进制形式。
allowCredentials可能包含 WebAuthn 凭据 ID 和 U2F 密钥句柄的混合体;通过此扩展声明appid并不阻止用户使用在rpId中声明的 RP ID 下限定范围的 WebAuthn 注册凭据。 -
此扩展不允许创建 FIDO 兼容的凭据。因此,使用 WebAuthn 创建的凭据与 FIDO JavaScript API 不向后兼容。
注意: appid 应设置为 依赖方 先前 在旧版 FIDO API 中使用的 AppID。这可能与将 依赖方 的 WebAuthn RP ID 转换为 AppID 格式的结果不同,例如,先前使用的 AppID 可能是 "https://accounts.example.com",但当前使用的 RP ID 可能是 "example.com"。
- 扩展标识符
-
appid - 操作适用性
- 客户端扩展输入
-
指定 FIDO AppID 的单个 USVString。
partial dictionary AuthenticationExtensionsClientInputs {USVString ; };appid - 客户端扩展处理
-
-
令 facetId 为将调用者的 源 (origin) 传递给 FIDO 算法以 确定调用应用程序的 FacetID 的结果。
-
令 appId 为扩展输入。
-
将 facetId 和 appId 传递给 FIDO 算法以 确定调用者的 FacetID 是否被授权用于 AppID。如果该算法拒绝 appId,则返回 "
SecurityError"DOMException。 -
当 构建 allowCredentialDescriptorList 时,如果 U2F 认证器指示凭据不适用(例如通过返回
SW_WRONG_DATA),则客户端必须重试,并将 U2F 应用程序参数设置为 appId 的 SHA-256 哈希。如果这导致了适用的凭据,客户端必须将该凭据包含在 allowCredentialDescriptorList 中。appId 的值随后替换 authenticatorGetAssertion 的rpId参数。 -
令 output 为布尔值
false。 -
当 创建 assertionCreationData 时,如果 断言 是由 U2F 认证器创建的,且 U2F 应用程序参数设置为 appId 的 SHA-256 哈希而不是 RP ID 的 SHA-256 哈希,则将 output 设置为
true。
-
注意: 在实践中,一些实现并没有实现算法的第四步及后续步骤以 确定调用者的 FacetID 是否被授权用于 AppID。相反,在第三步中,主机上的比较被放宽以接受 相同站点 上的主机。
- 客户端扩展输出
-
返回 output 的值。如果为真,则使用了 AppID,因此当 验证断言 时,依赖方 必须预期
rpIdHash为 AppID 的哈希,而不是 RP ID 的哈希。partial dictionary AuthenticationExtensionsClientOutputs {boolean ; };appid - 认证器扩展输入
-
无。
- 认证器扩展处理
-
无。
- 认证器扩展输出
-
无。
10.2. FIDO AppID 排除扩展 (appidExclude)
此注册扩展允许 WebAuthn 依赖方 排除包含指定凭据的认证器,这些凭据是使用旧版 FIDO U2F JavaScript API [FIDOU2FJavaScriptAPI] 创建的。
在从 FIDO U2F JavaScript API 过渡期间,依赖方 可能拥有一群已经注册了旧版凭据的用户。appid 扩展允许登录流程平稳过渡,但在过渡注册流程时,excludeCredentials 字段在排除带有旧版凭据的认证器时将无效,因为其内容被视为 WebAuthn 凭据。此扩展指示 客户端平台 将 excludeCredentials 的内容同时视为 WebAuthn 和旧版 FIDO 凭据。注意,U2F 密钥句柄通常使用 base64url 编码,但在用于 excludeCredentials 时必须解码为其二进制形式。
- 扩展标识符
-
appidExclude - 操作适用性
- 客户端扩展输入
-
指定 FIDO AppID 的单个 USVString。
partial dictionary AuthenticationExtensionsClientInputs {USVString ; };appidExclude - 客户端扩展处理
-
当 创建新凭据 时
-
在 确定 RP ID 后立即执行这些步骤
-
令 facetId 为将调用者的 源 (origin) 传递给 FIDO 算法以 确定调用应用程序的 FacetID 的结果。
-
令 appId 为扩展输入
appidExclude的值。 -
将 facetId 和 appId 传递给 FIDO 算法以 确定调用者的 FacetID 是否被授权用于 AppID。如果后者算法拒绝 appId,则返回 "
SecurityError"DOMException并终止 创建新凭据 算法以及这些步骤。注意: 在实践中,一些实现并没有实现算法的第四步及后续步骤以 确定调用者的 FacetID 是否被授权用于 AppID。相反,在第三步中,主机上的比较被放宽以接受 相同站点 上的主机。
-
否则,继续进行正常处理。
-
-
在 调用 authenticatorMakeCredential 之前立即执行这些步骤
-
如果 authenticator 支持 U2F 协议 [FIDO-U2F-Message-Formats],则 对于每一个 凭据描述符 C 在 excludeCredentialDescriptorList 中
-
通过向 authenticator 发送
U2F_AUTHENTICATE消息来检查 C 是否是使用 authenticator 上的 U2F 创建的,该消息的“五个部分”设置为以下值 -
如果 authenticator 响应
message:error:test-of-user-presence-required(即成功):停止对该 authenticator 的正常处理,并以特定于平台的方式指示该认证器不适用。例如,这可以是 UI 的形式,或者可能涉及从 authenticator 请求 用户同意,并在收到同意后,将其视为认证器已返回InvalidStateError。可以通过向 authenticator 发送上述的另一个U2F_AUTHENTICATE消息(除了将 控制字节 设置为0x03("enforce-user-presence-and-sign") 并忽略响应之外)来请求 用户同意。
-
-
继续进行正常处理。
-
-
- 客户端扩展输出
-
返回值
true以向 依赖方 指示该扩展已被执行。partial dictionary AuthenticationExtensionsClientOutputs {boolean ; };appidExclude - 认证器扩展输入
-
无。
- 认证器扩展处理
-
无。
- 认证器扩展输出
-
无。
10.3. 用户验证方法 扩展 (uvm)
此扩展启用用户验证方法的使用。
- 扩展标识符
-
uvm - 操作适用性
- 客户端扩展输入
-
布尔值
true,指示此扩展由 依赖方 请求。partial dictionary AuthenticationExtensionsClientInputs {boolean ; };uvm - 客户端扩展处理
-
无,除了从客户端扩展输入创建认证器扩展输入外。
- 客户端扩展输出
-
返回一个由 3 个数字组成的数组的 JSON 数组,该数组对认证器扩展输出中的因子进行编码。
typedef sequence <unsigned long >;UvmEntry typedef sequence <UvmEntry >;UvmEntries partial dictionary AuthenticationExtensionsClientOutputs {UvmEntries ; };uvm - 认证器扩展输入
-
布尔值
true,以 CBOR 编码(主类型 7,值 21)。$$extensionInput //= ( uvm: true, ) - 认证器扩展处理
-
认证器 将 认证器扩展输出 设置为一个或多个用户验证方法,指示用户用于授权操作的方法,定义如下。此扩展可以添加到认证对象和断言中。
- 认证器扩展输出
-
认证器可以使用以下定义的 CBOR 语法,报告在单个身份验证实例中使用的多达 3 种不同的用户验证方法(因子)
$$extensionOutput //= ( uvm: [ 1*3 uvmEntry ], ) uvmEntry = [ userVerificationMethod: uint .size 4, keyProtectionType: uint .size 2, matcherProtectionType: uint .size 2 ]每个
uvmEntry中字段的语义如下- userVerificationMethod
-
认证器用于验证用户的身份验证方法/因子。可用值在 [FIDO-Registry] 的 第 3.1 节 用户验证方法 中定义。
- keyProtectionType
-
认证器用于保护 FIDO 注册私钥材料的方法。可用值在 [FIDO-Registry] 的 第 3.2 节 密钥保护类型 中定义。
- matcherProtectionType
-
认证器用于保护执行用户验证的匹配器的方法。可用值在 [FIDO-Registry] 的 第 3.3 节 匹配器保护类型 中定义。
如果身份验证实例中可以使用 >3 个因子,认证器供应商必须选择其认为与服务器最相关的 3 个因子包含在 UVM 中。
包含一个 UVM 扩展的 认证器数据 示例,用于使用了 2 个因子的多因子身份验证实例
... -- RP ID hash (32 bytes) 81 -- UP and ED set 00 00 00 01 -- (initial) signature counter ... -- all public key alg etc. A1 -- extension: CBOR map of one element 63 -- Key 1: CBOR text string of 3 bytes 75 76 6d -- "uvm" [=UTF-8 encoded=] string 82 -- Value 1: CBOR array of length 2 indicating two factor usage 83 -- Item 1: CBOR array of length 3 02 -- Subitem 1: CBOR integer for User Verification Method Fingerprint 04 -- Subitem 2: CBOR short for Key Protection Type TEE 02 -- Subitem 3: CBOR short for Matcher Protection Type TEE 83 -- Item 2: CBOR array of length 3 04 -- Subitem 1: CBOR integer for User Verification Method Passcode 01 -- Subitem 2: CBOR short for Key Protection Type Software 01 -- Subitem 3: CBOR short for Matcher Protection Type Software
10.4. 凭据属性扩展 (credProps)
此 客户端 注册扩展 促进在 注册仪式 的结果中创建 公钥凭据源 时,向请求的 WebAuthn 依赖方 报告由 客户端 已知的特定 凭据属性。
目前,定义了一个 凭据属性:驻留密钥凭据属性(即 客户端侧可发现凭据属性)。
- 扩展标识符
-
credProps - 操作适用性
- 客户端扩展输入
-
布尔值
true,指示此扩展由 依赖方 请求。partial dictionary AuthenticationExtensionsClientInputs {boolean ; };credProps - 客户端扩展处理
-
无,除了在输出中报告凭据属性外。
- 客户端扩展输出
-
设置
clientExtensionResults["为在 调用 authenticatorMakeCredential 操作时使用的 requireResidentKey 参数的值。credProps"]["rk"]dictionary {CredentialPropertiesOutput boolean rk ; };partial dictionary AuthenticationExtensionsClientOutputs {CredentialPropertiesOutput ; };credProps rk, 类型为 boolean-
此可选属性,在抽象上称为 驻留密钥凭据属性(即 客户端侧可发现凭据属性),是一个布尔值,指示作为 注册仪式 的结果返回的
PublicKeyCredential是否为 客户端侧可发现凭据。如果rk为true,则该凭据为 可发现凭据。如果rk为false,则该凭据为 服务端凭据。如果rk不存在,则未知该凭据是 可发现凭据 还是 服务端凭据。注意: 一些 认证器 即使在 客户端平台 未请求时也会创建 可发现凭据。因此,客户端平台 可能被迫省略
rk属性,因为它们缺乏将其设置为false的把握。依赖方 应假设,如果支持credProps扩展,则 客户端平台 将努力填充rk属性。因此,缺失rk表示所创建的凭据很可能是 非可发现凭据。
- 认证器扩展输入
-
无。
- 认证器扩展处理
-
无。
- 认证器扩展输出
-
无。
10.5. 大 blob 存储扩展 (largeBlob)
此 客户端 注册扩展 和 身份验证扩展 允许 依赖方 存储与凭据关联的不透明数据。由于 认证器 只能存储少量数据,且大多数 依赖方 是可以为用户存储任意数量状态的在线服务,因此这仅在特定情况下有用。例如,依赖方 可能希望颁发证书,而不是运行集中的身份验证服务。
注意: 依赖方 可以假设不透明数据在写入空间有限的设备时会被压缩,因此不需要自行压缩。
由于证书系统需要对凭据的公钥进行签名,而该公钥仅在创建后才可用,因此此扩展没有增加在 注册 上下文中写入 blob 的能力。然而,如果 依赖方 希望稍后使用 身份验证扩展,则应在创建凭据时使用 注册扩展。
由于证书相对于典型认证器的存储能力而言较大,代理应考虑哪些指示和确认适合最好地指导用户分配此有限资源并防止滥用。
注意: 为了进行互操作,使用 [FIDO-CTAP] 在认证器上存储大 blob 的代理应使用该规范中详述的用于存储 大、每个凭据 blob 的规定。
- 扩展标识符
-
largeBlob - 操作适用性
- 客户端扩展输入
-
partial dictionary AuthenticationExtensionsClientInputs {AuthenticationExtensionsLargeBlobInputs ; };largeBlob enum {LargeBlobSupport ,"required" , };"preferred" dictionary {AuthenticationExtensionsLargeBlobInputs DOMString support ;boolean read ;BufferSource write ; };support, 类型为 DOMString-
一个采用
LargeBlobSupport值之一的 DOMString。(参见 § 2.1.1 枚举作为 DOMString 类型。)仅在 注册 期间有效。 read, 类型为 booleanwrite, 类型为 BufferSource
- 客户端扩展处理(注册)
-
-
-
返回一个名为 “
NotSupportedError” 的DOMException。
-
-
-
将
supported设置为true。注意: 这是为了预见即将可用的能够存储大 blob 的认证器。它发生在
[[Create]]()的第 11 步的扩展处理期间。如果没有可用的满意认证器,AuthenticationExtensionsLargeBlobOutputs将被放弃。 -
如果 候选认证器 变为可用(
[[Create]]()的第 19 步),则在评估任何options之前,如果 候选认证器 无法存储大 blob,则 继续(即忽略 候选认证器)。
-
-
- 客户端扩展处理(身份验证)
-
-
如果
support存在-
返回一个名为 “
NotSupportedError” 的DOMException。
-
-
-
返回一个名为 “
NotSupportedError” 的DOMException。
-
-
如果
read存在且值为true-
如果任何验证器表示成功(在
[[DiscoverFromExternalSource]]()中),尝试读取与所声明凭据关联的任何 largeBlob 数据。 -
如果成功,将
blob设置为该结果。注意:如果读取不成功,
largeBlob将存在于AuthenticationExtensionsClientOutputs中,但blob成员将不存在。
-
如果
write存在-
如果
allowCredentials不包含且仅包含一个元素-
返回一个名称为 “
NotSupportedError” 的DOMException。
-
-
如果成功,将
written设置为true,否则设置为false。
-
-
- 客户端扩展输出
-
partial dictionary AuthenticationExtensionsClientOutputs {AuthenticationExtensionsLargeBlobOutputs ; };largeBlob dictionary {AuthenticationExtensionsLargeBlobOutputs boolean supported ;ArrayBuffer blob ;boolean written ; }; - 认证器扩展处理
-
此扩展 指导用户代理将 large blob 存储在验证器上,或从验证器中检索它。因此,它没有为 依赖方 指定任何直接的验证器交互。
11. 用户代理自动化
为了用户代理自动化和 Web 应用程序 测试,本文档定义了多个 [WebDriver] 扩展命令。
11.1. WebAuthn WebDriver 扩展能力
为了通告下述 扩展命令 的可用性,定义了一种新的 扩展能力。
在 验证能力 时,验证带有 value 的 "webauthn:virtualAuthenticators" 的扩展特定子步骤如下:
-
如果
value不是 布尔值,则返回一个带有 WebDriver 错误代码 invalid argument 的 WebDriver 错误。 -
否则,令
deserialized设置为value。
在 匹配能力 时,匹配带有 value 的 "webauthn:virtualAuthenticators" 的扩展特定步骤如下:
11.1.1. 验证器扩展能力
此外,针对本规范中定义的每个 验证器扩展(即那些定义了 验证器扩展处理 的扩展)定义了 扩展能力。
| 能力 | 键 | 值类型 | 描述 |
|---|---|---|---|
| 用户验证方法扩展支持 | "webauthn:extension:uvm"
| boolean | 指示 端点节点 WebAuthn WebDriver 实现是否支持 用户验证方法 扩展。 |
| Large Blob 存储扩展支持 | "webauthn:extension:largeBlob"
| boolean | 指示 端点节点 WebAuthn WebDriver 实现是否支持 largeBlob 扩展。 |
在 验证能力 时,验证带有 value 的 验证器扩展能力 key 的扩展特定子步骤如下:
-
如果
value不是 布尔值,则返回一个带有 WebDriver 错误代码 invalid argument 的 WebDriver 错误。 -
否则,令
deserialized设置为value。
在 匹配能力 时,匹配带有 value 的 验证器扩展能力 key 的扩展特定步骤如下:
实现已定义的 验证器扩展 的用户代理应当实现相应的 验证器扩展能力。
11.2. 虚拟验证器
这些 WebDriver 扩展命令 创建并与 虚拟验证器 进行交互:验证器模型 的软件实现。虚拟验证器 存储在 虚拟验证器数据库 中。每个存储的 虚拟验证器 具有以下属性
- authenticatorId
-
一个非空字符串,由 [RFC3986] 附录 A 定义的
unreserved生成规则中最多 48 个字符组成,用于唯一标识 虚拟验证器。 - protocol
-
虚拟验证器 所使用的协议:
"ctap1/u2f"、"ctap2"或"ctap2_1"[FIDO-CTAP] 之一。 - transport
-
模拟的
AuthenticatorTransport。如果 transport 设置为internal,则验证器模拟 平台附着。否则,模拟 跨平台附着。 - hasResidentKey
-
如果设置为
true,验证器将支持 客户端可发现凭据。 - hasUserVerification
-
如果设置为
true,验证器支持 用户验证。 - isUserConsenting
-
确定所有 用户同意 授权手势 的结果,进而确定在 虚拟验证器 上执行的任何 用户存在性测试 的结果。如果设置为
true,则始终授予 用户同意。如果设置为false,则不会授予。 - isUserVerified
-
确定在 虚拟验证器 上执行的 用户验证 的结果。如果设置为
true,则 用户验证 将始终成功。如果设置为false,则会失败。注意:如果 hasUserVerification 设置为
false,此属性无效。 - extensions
-
虚拟验证器 必须支持其 extensions 数组中存在的所有 验证器扩展。它不得支持其 extensions 数组中不存在的任何 验证器扩展。
- uvm
-
在处理 用户验证方法 扩展时,设置为 验证器扩展输出 的
UvmEntries数组。
11.3. 添加虚拟验证器
添加虚拟验证器 WebDriver 扩展命令 创建一个软件 虚拟验证器。其定义如下:
| HTTP 方法 | URI 模板 |
|---|---|
| POST | /session/{session id}/webauthn/authenticator
|
验证器配置 是作为 parameters 传递给 远端步骤 的 JSON 对象。它包含以下 键 和 值 对
| 键 | 值类型 | 有效值 | 默认值 |
|---|---|---|---|
| protocol | string | "ctap1/u2f"、"ctap2"、"ctap2_1" | 无 |
| transport | string | AuthenticatorTransport 值 | 无 |
| hasResidentKey | boolean | true, false | false
|
| hasUserVerification | boolean | true, false | false
|
| isUserConsenting | boolean | true, false | true
|
| isUserVerified | boolean | true, false | false
|
| extensions | 字符串数组 | 包含 扩展标识符 的数组 | 空数组 |
| uvm | UvmEntries
| 最多 3 个 用户验证方法 条目 | 空数组 |
远端步骤 为:
-
如果 parameters 不是 JSON 对象,则返回一个带有 WebDriver 错误代码 invalid argument 的 WebDriver 错误。
注意:parameters 是一个 验证器配置 对象。
-
令 authenticator 为一个新的 虚拟验证器。
-
对于 parameters 中的每个可枚举 自有属性
-
令 key 为属性名。
-
令 value 为 获取属性 的结果,该属性名为 key,从 parameters 中获取。
-
如果 parameters 中没有与 key 匹配的
key,则返回一个带有 WebDriver 错误代码 invalid argument 的 WebDriver 错误。 -
如果 value 不是该 key 的
有效值之一,则返回一个带有 WebDriver 错误代码 invalid argument 的 WebDriver 错误。 -
设置属性 key 为 value 在 authenticator 上。
-
-
对于 验证器配置 中定义了默认值的每个属性
-
如果
key不是 authenticator 的已定义属性,则 设置属性key为default在 authenticator 上。
-
-
对于 验证器配置 中的每个属性
-
如果
key不是 authenticator 的已定义属性,则返回一个带有 WebDriver 错误代码 invalid argument 的 WebDriver 错误。
-
-
对于 authenticator.extensions 中的每个 extension
-
如果 extension 不是 端点节点 WebAuthn WebDriver 实现支持的 扩展标识符,则返回一个带有 WebDriver 错误代码 unsupported operation 的 WebDriver 错误。
-
-
生成一个有效的唯一 authenticatorId。
-
设置属性
authenticatorId为 authenticatorId 在 authenticator 上。 -
将 authenticator 存储在 虚拟验证器数据库 中。
-
返回带有数据 authenticatorId 的 success。
11.4. 移除虚拟验证器
移除虚拟验证器 WebDriver 扩展命令 移除先前创建的 虚拟验证器。其定义如下:
| HTTP 方法 | URI 模板 |
|---|---|
| DELETE | /session/{session id}/webauthn/authenticator/{authenticatorId}
|
远端步骤 为:
-
如果 authenticatorId 与存储在 虚拟验证器数据库 中的任何 虚拟验证器 不匹配,则返回一个带有 WebDriver 错误代码 invalid argument 的 WebDriver 错误。
-
返回 success。
11.5. 添加凭据
添加凭据 WebDriver 扩展命令 将 公钥凭据源 注入到现有的 虚拟验证器 中。其定义如下:
| HTTP 方法 | URI 模板 |
|---|---|
| POST | /session/{session id}/webauthn/authenticator/{authenticatorId}/credential
|
凭据参数 是作为 parameters 传递给 远端步骤 的 JSON 对象。它包含以下 键 和 值 对
| 键 | 描述 | 值类型 |
|---|---|---|
| credentialId | 使用 Base64url 编码 编码的 凭据 ID。 | string |
| isResidentCredential | 如果设置为 true,则创建 客户端可发现凭据。如果设置为 false,则改为创建 服务端凭据。 | boolean |
| rpId | 凭据所属的 依赖方 ID。 | string |
| privateKey | 根据 [RFC5958] 包含单个 私钥 的非对称密钥包,使用 Base64url 编码 编码。 | string |
| userHandle | 与凭据关联的 userHandle,使用 Base64url 编码 编码。此属性可能未定义。 | string |
| signCount | 与 公钥凭据源 关联的 签名计数器 的初始值。 | number |
| largeBlob | 与 公钥凭据源 关联的 大型、每个凭据 blob,使用 Base64url 编码 编码。此属性可能未定义。 | string |
远端步骤 为:
-
如果 parameters 不是 JSON 对象,则返回一个带有 WebDriver 错误代码 invalid argument 的 WebDriver 错误。
注意:parameters 是一个 凭据参数 对象。
-
令 credentialId 为对 parameters 的 credentialId 属性进行 Base64url 编码 解码的结果。
-
如果 credentialId 解码失败,则返回一个带有 WebDriver 错误代码 invalid argument 的 WebDriver 错误。
-
令 isResidentCredential 为 parameters 的 isResidentCredential 属性。
-
如果 isResidentCredential 未定义,则返回一个带有 WebDriver 错误代码 invalid argument 的 WebDriver 错误。
-
令 rpId 为 parameters 的 rpId 属性。
-
如果 rpId 不是有效的 RP ID,则返回一个带有 WebDriver 错误代码 invalid argument 的 WebDriver 错误。
-
令 privateKey 为对 parameters 的 privateKey 属性进行 Base64url 编码 解码的结果。
-
如果 privateKey 解码失败,则返回一个带有 WebDriver 错误代码 invalid argument 的 WebDriver 错误。
-
如果 privateKey 不是根据 [RFC5958] 合法编码的、包含单个 P-256 曲线上 ECDSA 私钥的非对称密钥包,则返回一个带有 WebDriver 错误代码 invalid argument 的 WebDriver 错误。
-
如果定义了 parameters 的 userHandle 属性
-
令 userHandle 为对 parameters 的 userHandle 属性进行 Base64url 编码 解码的结果。
-
如果 userHandle 解码失败,则返回一个带有 WebDriver 错误代码 invalid argument 的 WebDriver 错误。
-
-
否则
-
如果 isResidentCredential 为
true,则返回一个带有 WebDriver 错误代码 invalid argument 的 WebDriver 错误。 -
令 userHandle 为
null。
-
-
如果 authenticatorId 与存储在 虚拟验证器数据库 中的任何 虚拟验证器 不匹配,则返回一个带有 WebDriver 错误代码 invalid argument 的 WebDriver 错误。
-
令 authenticator 为由 authenticatorId 匹配的 虚拟验证器。
-
如果 isResidentCredential 为
true且 authenticator 的 hasResidentKey 属性为false,则返回一个带有 WebDriver 错误代码 invalid argument 的 WebDriver 错误。 -
如果 authenticator 支持 largeBlob 扩展且定义了 parameters 的 largeBlob 特性
-
令 largeBlob 为对 parameters 的 largeBlob 属性进行 Base64url 编码 解码的结果。
-
如果 largeBlob 解码失败,则返回一个带有 WebDriver 错误代码 invalid argument 的 WebDriver 错误。
-
-
否则
-
令 largeBlob 为
null。
-
-
如果 isResidentCredential 为
true,则令 credential 为一个新的 客户端可发现公钥凭据源,否则令其为 服务端公钥凭据源,其项包括:- type
- id
-
credentialId
- privateKey
-
privateKey
- rpId
-
rpId
- userHandle
-
userHandle
-
将 签名计数器 counter 与 credential 关联,起始值等于 parameters 的 signCount,如果 signCount 为
null,则为0。 -
如果 largeBlob 不为
null,则将与 credential 关联的 大型、每个凭据 blob 设置为 largeBlob。 -
将 credential 和 counter 存储在 authenticator 的数据库中。
-
返回 success。
11.6. 获取凭据
获取凭据 WebDriver 扩展命令 返回存储在 虚拟验证器 中的每个 公钥凭据源 的一个 凭据参数 对象,无论它们是使用 添加凭据 还是 navigator.credentials.create() 存储的。其定义如下:
| HTTP 方法 | URI 模板 |
|---|---|
| GET | /session/{session id}/webauthn/authenticator/{authenticatorId}/credentials
|
远端步骤 为:
-
如果 authenticatorId 与存储在 虚拟验证器数据库 中的任何 虚拟验证器 不匹配,则返回一个带有 WebDriver 错误代码 invalid argument 的 WebDriver 错误。
-
令 credentialsArray 为一个空数组。
-
对于由 authenticatorId 标识的验证器管理的每个 公钥凭据源 credential,构建一个对应的 凭据参数 对象 并将其添加到 credentialsArray。
-
返回包含 credentialsArray 的 success。
11.7. 移除凭据
移除凭据 WebDriver 扩展命令 移除存储在 虚拟验证器 上的 公钥凭据源。其定义如下:
| HTTP 方法 | URI 模板 |
|---|---|
| DELETE | /session/{session id}/webauthn/authenticator/{authenticatorId}/credentials/{credentialId}
|
远端步骤 为:
-
如果 authenticatorId 与存储在 虚拟验证器数据库 中的任何 虚拟验证器 不匹配,则返回一个带有 WebDriver 错误代码 invalid argument 的 WebDriver 错误。
-
令 authenticator 为由 authenticatorId 标识的 虚拟验证器。
-
如果 credentialId 与 authenticator 管理的任何 公钥凭据源 不匹配,则返回一个带有 WebDriver 错误代码 invalid argument 的 WebDriver 错误。
-
移除由 credentialId 标识并由 authenticator 管理的 公钥凭据源。
-
返回 success。
11.8. 移除所有凭据
移除所有凭据 WebDriver 扩展命令 移除存储在 虚拟验证器 上的所有 公钥凭据源。其定义如下:
| HTTP 方法 | URI 模板 |
|---|---|
| DELETE | /session/{session id}/webauthn/authenticator/{authenticatorId}/credentials
|
远端步骤 为:
-
如果 authenticatorId 与存储在 虚拟验证器数据库 中的任何 虚拟验证器 不匹配,则返回一个带有 WebDriver 错误代码 invalid argument 的 WebDriver 错误。
-
返回 success。
11.9. 设置用户已验证
设置用户已验证 扩展命令 设置 虚拟验证器 上的 isUserVerified 属性。其定义如下:
| HTTP 方法 | URI 模板 |
|---|---|
| POST | /session/{session id}/webauthn/authenticator/{authenticatorId}/uv
|
远端步骤 为:
-
如果 parameters 不是 JSON 对象,则返回一个带有 WebDriver 错误代码 invalid argument 的 WebDriver 错误。
-
如果 authenticatorId 与存储在 虚拟验证器数据库 中的任何 虚拟验证器 不匹配,则返回一个带有 WebDriver 错误代码 invalid argument 的 WebDriver 错误。
-
如果 isUserVerified 不是 parameters 的已定义属性,则返回一个带有 WebDriver 错误代码 invalid argument 的 WebDriver 错误。
-
令 authenticator 为由 authenticatorId 标识的 虚拟验证器。
-
将 authenticator 的 isUserVerified 属性设置为 parameters 的 isUserVerified 属性。
-
返回 success。
12. IANA 考虑事项
12.1. WebAuthn 认证语句格式标识符注册更新
本节更新了下述在 IANA "WebAuthn 认证语句格式标识符" 注册表 [IANA-WebAuthn-Registries] 中定义的认证语句格式,该注册表由 [RFC8809] 建立,最初在 [WebAuthn-1] 中注册,现指向本规范。
-
WebAuthn 认证语句格式标识符:packed
-
描述:“packed”认证语句格式是一种针对 认证 进行了 WebAuthn 优化的格式。它使用一种非常紧凑但仍可扩展的编码方法。这种格式可由资源有限的验证器(例如安全元件)实现。
-
规范文档:本规范的 § 8.2 Packed 认证语句格式
-
WebAuthn 认证语句格式标识符:tpm
-
描述:TPM 认证语句格式返回与 packed 认证语句格式格式相同的认证语句,尽管 rawData 和 signature 字段的计算方式不同。
-
规范文档:本规范的 § 8.3 TPM 认证语句格式
-
WebAuthn 认证语句格式标识符:android-key
-
描述:“N”及更高版本的 平台验证器 可以提供此专有的“硬件认证”语句。
-
规范文档:本规范的 § 8.4 Android 密钥认证语句格式
-
WebAuthn 认证语句格式标识符:android-safetynet
-
描述:基于 Android 的 平台验证器 可能生成基于 Android SafetyNet API 的认证语句。
-
规范文档:本规范的 § 8.5 Android SafetyNet 认证语句格式
-
WebAuthn 认证语句格式标识符:fido-u2f
-
描述:与 FIDO U2F 验证器一起使用
-
规范文档:本规范的 § 8.6 FIDO U2F 认证语句格式
12.2. WebAuthn 认证语句格式标识符注册
本节在 IANA "WebAuthn 认证语句格式标识符" 注册表 [IANA-WebAuthn-Registries] 中注册了下述在 § 8 定义的认证语句格式 中新定义的认证语句格式,该注册表由 [RFC8809] 建立。
-
WebAuthn 认证语句格式标识符:apple
-
描述:与 Apple 设备的 平台验证器 一起使用
-
规范文档:本规范的 § 8.8 Apple 匿名认证语句格式
-
WebAuthn 认证语句格式标识符:none
-
描述:当 WebAuthn 依赖方表示不希望接收认证信息时,用于替换任何验证器提供的认证语句。
-
规范文档:本规范的 § 8.7 None 认证语句格式
12.3. WebAuthn 扩展标识符注册更新
本节更新了下述在 IANA "WebAuthn 扩展标识符" 注册表 [IANA-WebAuthn-Registries] 中定义的 扩展标识符 值,该注册表由 [RFC8809] 建立,最初在 [WebAuthn-1] 中注册,现指向本规范。
-
WebAuthn 扩展标识符:appid
-
描述:此 认证扩展 允许先前使用传统 FIDO JavaScript API 注册凭据的 WebAuthn 依赖方 请求断言。
-
规范文档:本规范的 § 10.1 FIDO AppID 扩展 (appid)
-
WebAuthn 扩展标识符:uvm
-
描述:此 注册扩展 和 认证扩展 启用了用户验证方法的使用。用户验证方法扩展会向 WebAuthn 依赖方 返回 WebAuthn 操作所使用的用户验证方法(因子)。
-
规范文档:本规范的 § 10.3 用户验证方法扩展 (uvm)
12.4. WebAuthn 扩展标识符注册
本节在 IANA "WebAuthn 扩展标识符" 注册表 [IANA-WebAuthn-Registries] 中注册了下述在 § 10 定义的扩展 中新定义的 扩展标识符 值,该注册表由 [RFC8809] 建立。
-
WebAuthn 扩展标识符:appidExclude
-
描述:此注册扩展允许 WebAuthn 依赖方 排除包含使用传统 FIDO U2F JavaScript API [FIDOU2FJavaScriptAPI] 创建的指定凭据的验证器。
-
规范文档:本规范的 § 10.2 FIDO AppID 排除扩展 (appidExclude)
-
WebAuthn 扩展标识符:credProps
-
描述:此 客户端 注册扩展 启用了将由 客户端 确定的、新创建的 凭据 属性上报给调用方的 WebAuthn 依赖方 的 Web 应用程序 的功能。
-
规范文档:本规范的 § 10.4 凭据属性扩展 (credProps)
-
WebAuthn 扩展标识符:largeBlob
-
规范文档:本规范的 § 10.5 大型 blob 存储扩展 (largeBlob)
13. 安全考虑事项
本规范定义了一种 Web API 和一种加密的对等实体认证协议。Web 认证 API 允许 Web 开发人员(即“作者”)在他们的 注册 和 认证 仪式 中利用 Web 认证协议。构成 Web 认证协议端点的实体是用户控制的 WebAuthn 验证器 和托管 依赖方 的 Web 应用程序 的 WebAuthn 依赖方 的计算环境。在此模型中,用户代理与 WebAuthn 客户端 一起,充当 验证器 和 依赖方 之间的中介。此外,验证器 可以向 依赖方 证明 其来源。
目前,本规范未提供详细的安全考虑事项。但是,[FIDOSecRef] 文档提供了整体适用于本规范的安全分析。此外,[FIDOAuthnrSecReqs] 文档集提供了有关 验证器 安全特性的有用信息。
以下小节包含当前的 Web 认证特定安全考虑事项。它们按受众划分;常规安全考虑事项是本节的直接小节,而专门针对 验证器、客户端 和 依赖方 实现者的安全考虑事项被归入各自的小节中。
13.1. 未签名的凭据 ID
凭据 ID 未经签名。这不是问题,因为如果 验证器 返回错误的 凭据 ID,或者攻击者拦截并篡改了 凭据 ID,唯一会发生的事情是 WebAuthn 依赖方 将无法查找用于验证返回的签名 验证器数据(即 断言)的正确 凭据公钥,因此交互将以错误结束。
13.2. 客户端与验证器之间的物理邻近性
在 WebAuthn 验证器模型 中,通常假设 漫游验证器 与 客户端 物理靠近并直接通信。这种安排有一些重要的优势。
客户端 和 验证器 之间物理邻近的承诺是 你所拥有的 认证因子 的关键优势。例如,如果 漫游验证器 只能通过 USB 或蓝牙通信,这些传输方式的有限范围确保了任何恶意攻击者必须物理存在于该范围内才能与 验证器 交互。对于可以远程调用的 验证器 而言,情况并非必然如此——即使 验证器 验证了 用户存在性,用户也可能被诱骗去授权远程发起的恶意请求。
客户端 和 验证器 之间的直接通信意味着 客户端 可以强制执行 凭据 的 作用域 限制。相比之下,如果 客户端 和 验证器 之间的通信由第三方介导,则 客户端 必须信任第三方来强制执行 作用域 限制并控制对 验证器 的访问。未能做到这两者中的任何一个都可能导致恶意 依赖方 收到对其他 依赖方 有效的 认证断言,或恶意用户获得其他用户的 认证断言。
如果设计一个 验证器 不需要与 客户端 物理靠近的解决方案,或者 客户端 和 验证器 不直接通信的解决方案,设计者应该考虑这如何影响 作用域 限制的执行,以及 验证器 作为 你所拥有的 认证因子的强度。
13.3. 针对 验证器 的安全考虑事项
13.3.1. 认证证书层次结构
推荐采用 3 层认证证书层次结构(即认证根、认证颁发 CA、认证证书)。还推荐对每个 WebAuthn 验证器 产品线(即型号)使用单独的颁发 CA,以帮助促进隔离特定版本验证器型号的问题。
如果认证根证书并非专用于单个 WebAuthn 验证器 产品线(即 AAGUID),则 AAGUID 应当在认证证书本身中指定,以便可以根据 验证器数据 对其进行验证。
13.3.2. 认证证书和认证证书 CA 泄露
当用于颁发认证证书的中间 CA 或根 CA 泄露时,WebAuthn 验证器 认证密钥对 仍然是安全的,尽管它们的证书已不可信任。记录了其 验证器 型号 认证公钥 的 WebAuthn 验证器 制造商可以从新的中间 CA 或新的根 CA 为这些密钥颁发新的 认证证书。如果根 CA 发生更改,WebAuthn 依赖方 必须相应地更新其受信任的根证书。
如果 WebAuthn 验证器 认证证书 的 私钥 已泄露,则颁发 CA 必须撤销该证书。如果泄露是由于固件缺陷引起的,WebAuthn 验证器制造商可能需要发布固件更新,并向已制造的 WebAuthn 验证器 中注入新的 认证私钥 和 证书。(此过程的发生方式超出本规范的范围。)如果 WebAuthn 验证器 制造商不具备此能力,则 依赖方 可能无法再信任来自受影响 WebAuthn 验证器 的任何 认证语句。
另请参阅 § 13.4.5 已撤销的认证证书 中关于 依赖方 的相关安全考虑事项。
13.4. 针对 依赖方 的安全考虑事项
13.4.1. WebAuthn 依赖方的安全益处
本规范为 WebAuthn 依赖方 提供的主要益处包括:
-
用户和账户可以使用广泛兼容、易于使用的多因素认证来保护。
-
依赖方 不需要向用户提供 验证器 硬件。相反,每个用户可以独立获得任何符合标准的 验证器,并将同一个 验证器 与任意数量的 依赖方 一起使用。依赖方 可以选择通过检查从 验证器 返回的 认证语句 来对 验证器 的安全属性强制执行要求。
-
认证仪式 能够抵御 中间人攻击。关于 注册仪式,请参阅下方的 § 13.4.4 认证限制。
-
依赖方 可以自动支持多种类型的 用户验证(例如 PIN、生物识别和/或未来的方法),几乎无需更改代码,并可以让每个用户通过他们对 验证器 的选择来决定他们更喜欢使用哪种。
-
依赖方 不需要存储额外的密钥即可获得上述益处。
如 一致性 部分所述,依赖方 必须按照 § 7 WebAuthn 依赖方操作 中的描述行事,以获得所有上述安全益处。然而,下方 § 13.4.4 认证限制 中描述了一个略有偏差的显著用例。
13.4.2. 嵌入式使用的可见性考虑事项
在嵌入式环境中(例如 § 5.10 在 iframe 元素中使用 Web 认证 中描述的 iframe 内)单纯地使用 WebAuthn,可能会使用户容易受到 UI 覆盖 攻击,也称为 “点击劫持”。在这种情况下,攻击者将其自己的 UI 覆盖在 依赖方 的预期 UI 之上,并试图诱骗用户对 依赖方 执行非预期的操作。例如,使用这些技术,攻击者可能能够诱骗用户购买商品、转账等。
即使 WebAuthn 特定的 UI 通常由 客户端平台 处理,因此不易受到 UI 覆盖 的攻击,但对于拥有嵌入式 WebAuthn 内容的 依赖方 而言,确保其内容的 UI 对用户可见可能很重要。实现此目标的一种新兴方法是观察实验性的 Intersection Observer v2 的 isVisible 属性的状态。例如,运行在嵌入式环境中的 依赖方 脚本如果检测到 isVisble 被设置为 false,则可以抢先在弹出窗口中加载自身,从而规避对其内容的任何遮挡。
13.4.3. 加密挑战
作为一种加密协议,Web Authentication(Web身份验证)依赖于随机挑战值来避免重放攻击。因此,PublicKeyCredentialCreationOptions.challenge 和 PublicKeyCredentialRequestOptions.challenge 的值必须由依赖方 (Relying Parties) 在其信任的环境(例如服务器端)中随机生成,并且客户端响应中返回的 challenge 值必须与生成的值相匹配。这应当以不依赖客户端行为的方式完成,例如,依赖方应暂时存储该挑战值,直到操作完成。容忍不匹配将损害协议的安全性。
为了防止重放攻击,挑战值必须包含足够的熵,以使得猜测它们变得不可行。因此,挑战值长度应至少为 16 字节。
13.4.4. 证明限制
本节不具有规范性。
在注册新凭据时,如果存在证明语句 (attestation statement),则它可能允许 WebAuthn 依赖方获得关于各种验证器 (authenticator) 质量的保证。例如,验证器型号,或它是如何存储和保护凭据私钥的。然而,必须注意,证明语句本身不能使依赖方验证证明对象 (attestation object) 是否由用户预期的验证器生成,而不是由中间人攻击者生成。例如,此类攻击者可以使用注入到依赖方脚本中的恶意代码。因此,依赖方必须依赖其他手段(例如 TLS 及相关技术)来保护证明对象免受中间人攻击。
假设注册仪式安全完成,且验证器保持了凭据私钥的机密性,那么使用该公钥凭据的后续身份验证仪式将能够抵御中间人攻击。
上述讨论适用于所有证明类型。在所有情况下,中间人攻击者都有可能替换 PublicKeyCredential 对象(包括证明语句和待注册的凭据公钥),并随后篡改针对同一依赖方且通过该攻击者的未来身份验证断言(作用域内)。
这种攻击潜在是可以检测到的;由于依赖方注册的是攻击者的凭据公钥而非用户的,攻击者必须篡改该依赖方的所有后续身份验证仪式:未被篡改的仪式将会失败,从而可能暴露攻击。
除自证明和无证明之外的证明类型可以增加此类攻击的难度,因为依赖方可能向用户显示验证器信息,例如型号名称。因此,攻击者可能需要使用与用户验证器同型号的真品验证器,否则用户可能会注意到依赖方报告的验证器型号与其预期不符。
注意:对于攻击者而言,上述所有中间人攻击变体比针对传统密码验证的中间人攻击更难实施。
13.4.5. 撤销的证明证书
如果由于中间证明 CA 证书被撤销导致证明证书验证失败,且依赖方的策略要求在这种情况下拒绝注册/身份验证请求,则建议依赖方同时也取消注册(或标记为等同于“自证明”的信任级别)那些在 CA 泄露日期之后,使用链接到相同中间 CA 的证明证书所注册的公钥凭据。因此,建议依赖方在注册期间记录中间证明 CA 证书,以便在这些证书撤销后,能够取消注册相关的公钥凭据。
另请参阅 § 13.3.2 证明证书和证明证书 CA 泄露中关于验证器的相关安全考量。
13.4.6. 凭据丢失与密钥可移植性
本规范未定义任何备份凭据私钥,或在不同验证器之间共享它们的协议。通常,预期凭据私钥永远不会离开创建它的验证器。因此,丢失一个验证器通常意味着丢失所有绑定到该遗失验证器的凭据,如果用户在依赖方处仅注册了一个凭据,这可能会导致用户无法访问账户。Web Authentication API 允许为同一用户注册多个凭据,而不是备份或共享私钥。例如,用户可以在常用的客户端设备上注册平台凭据,并注册一个或多个漫游凭据,以备备份使用,或用于新的、少用的客户端设备。
依赖方应允许并鼓励用户向同一账户注册多个凭据。依赖方应利用 和 excludeCredentials 选项,以确保这些不同的凭据绑定到不同的验证器。user.id
13.4.7. 未受保护的账户检测
本节不具有规范性。
此安全考量适用于支持在身份验证第一步中使用非空 allowCredentials 参数进行身份验证仪式的依赖方。例如,在第一步身份验证中使用了服务器端凭据的情况。
在这种情况下,allowCredentials 参数存在泄露哪些用户账户注册了 WebAuthn 凭据、哪些没有注册的信息的风险,这可能是账户保护强度的一个信号。例如,假设攻击者可以通过仅提供用户名来发起身份验证仪式,而依赖方对某些用户返回非空的 allowCredentials,对其他用户则返回失败或密码挑战。那么攻击者可以推断出后者账户可能不需要 WebAuthn 断言即可成功认证,从而将攻击重点放在这些可能较弱的账户上。
此问题类似于 § 14.6.2 用户名枚举 和 § 14.6.3 通过凭据 ID 的隐私泄露 中描述的问题,可以通过类似方式进行缓解。
14. 隐私考量
[FIDO-Privacy-Principles] 中的隐私原则也适用于本规范。
本节按受众划分;一般性隐私考量是本节的直接子节,而专门针对验证器、客户端和依赖方实施者的隐私考量被归类到各自的子节中。
14.1. 去匿名化预防措施
本节不具有规范性。
Web Authentication API 设计的许多方面都出于隐私考虑。本规范主要考量的是保护用户的个人身份,即一个人的人身识别或将不同身份关联为同一人的关联。尽管 Web Authentication API 不使用也不提供任何形式的全球标识,但使用了以下几种潜在的可关联标识符:
-
这些由 WebAuthn 依赖方注册,随后被用户用于证明其拥有相应的凭据私钥。它们在与验证器的通信中对客户端也是可见的。
-
用户的生物识别特征,例如指纹或面部识别数据 [ISOBiometricVocabulary]。
-
用户验证器的型号,例如产品名称。
-
用户验证器的身份,例如序列号。
上述某些信息必然与依赖方共享。以下章节描述了为防止恶意依赖方利用这些信息发现用户个人身份所采取的措施。
14.2. 匿名、作用域化、不可关联的公钥凭据
本节不具有规范性。
尽管凭据 ID 和凭据公钥必然与 WebAuthn 依赖方共享以实现强身份验证,但它们的设计旨在尽可能减少身份识别,且不在依赖方之间共享。
-
每个公钥凭据严格作用域化到特定的依赖方,且客户端确保其存在性不会向其他依赖方透露。因此,恶意依赖方无法要求客户端泄露用户的其他身份。
-
客户端还确保在未经用户同意的情况下,公钥凭据的存在性不会向依赖方透露。这在 § 14.5.1 注册仪式隐私 和 § 14.5.2 身份验证仪式隐私 中有更详细的说明。因此,即使在用户拥有已注册且可用的公钥凭据的情况下,恶意依赖方也无法静默识别用户。
-
验证器确保不同公钥凭据的凭据 ID 和凭据公钥不可关联为属于同一用户。因此,一对恶意依赖方无法在没有额外信息(例如故意重复使用的用户名或电子邮件地址)的情况下关联其系统间的用户。
-
验证器确保其证明证书的唯一性不足以识别单个验证器或一小群验证器。这在 § 14.4.1 证明隐私 中有更详细的说明。因此,一对恶意依赖方无法通过追踪单个验证器来关联其系统间的用户。
此外,客户端侧可发现的公钥凭据源可以选择包含由依赖方指定的用户句柄。该凭据随后可同时用于识别和验证用户。这意味着注重隐私的依赖方可以允许用户在没有传统用户名的情况下创建账户,进一步改善了依赖方之间的不可关联性。
14.3. 验证器本地生物识别
生物识别验证器在验证器内部执行生物识别——尽管对于平台验证器,根据具体实现,生物识别数据也可能对客户端可见。生物识别数据不会透露给 WebAuthn 依赖方;它仅在本地用于执行用户验证,从而授权创建、注册或使用公钥凭据进行身份验证。因此,恶意依赖方无法通过生物识别数据发现用户的个人身份,且依赖方的安全泄露也不会暴露生物识别数据供攻击者用于伪造在其他依赖方处的登录。
在依赖方需要生物识别的情况下,这是由生物识别验证器在本地执行用户验证,然后通过在签名断言响应中设置 UV 标志来发出结果信号,而不是向依赖方透露生物识别数据本身。
14.4. 针对验证器的隐私考量
14.4.1. 证明隐私
证明证书和证明密钥对可用于追踪用户或关联同一用户的各种在线身份。这可以通过多种方式缓解,包括:
-
WebAuthn 验证器制造商可以选择分批出货验证器,同一批次中的验证器共享相同的证明证书(称为基本证明或批次证明)。这将匿名化用户,但代价是若其私钥泄露,无法撤销特定的证明证书。验证器制造商应确保此类批次足够大以提供有意义的匿名化,同时尽量减小批次大小,以便在证明私钥泄露时限制受影响用户的数量。
[UAFProtocol] 要求至少 100,000 个验证器设备共享同一个证明证书,以产生足够大的群体。这可以作为关于合适批次大小的指导。
-
WebAuthn 验证器可能具备动态生成不同证明密钥对(并请求相关证书)的能力,每个凭据对应一对,如 Anonymization CA 方法所述。例如,验证器可以出厂时携带一个主证明私钥(和证书),并结合云端运行的 Anonymization CA,动态生成每个凭据专属的证明密钥对和证明证书。
注意:在本规范之外的许多地方,术语“Privacy CA”用于指代此处所称的 Anonymization CA。由于可信计算组织 (TCG) 也曾使用术语“Privacy CA”来指代其现在称为证明 CA (ACA) 的内容 [TCG-CMCProfile-AIKCertEnroll],我们在此使用术语 Anonymization CA 以试图缓解在本规范特定上下文中的混淆。
14.4.2. 存储在验证器中的个人身份信息隐私
验证器可能在定义的本规范之外向客户端提供额外信息,例如使客户端能够提供丰富的用户界面,以便用户选择用于身份验证仪式的凭据。如果验证器选择这样做,除非已成功执行用户验证,否则不应暴露个人身份信息。如果验证器支持同时注册多个用户的用户验证,则验证器不应暴露除当前已验证用户之外的其他用户的个人身份信息。因此,不具备用户验证能力的验证器不应存储个人身份信息。
出于此讨论的目的,作为 PublicKeyCredentialUserEntity 的 id 成员传递的用户句柄不被视为个人身份信息;请参阅 § 14.6.1 用户句柄内容。
这些建议旨在防止拥有验证器物理访问权的对手提取有关验证器已注册用户的个人身份信息。
14.5. 针对客户端的隐私考量
14.5.1. 注册仪式隐私
为了保护用户在未经同意的情况下被识别,[[Create]](origin, options, sameOriginWithAncestors) 方法的实现需要注意不要泄露可能使恶意 WebAuthn 依赖方能够区分以下情况的信息,其中“排除 (excluded)”意味着 依赖方 在 excludeCredentials 中列出的至少一个凭据被绑定到了该验证器:
如果上述情况是可以区分的,那么就会泄露信息,恶意依赖方可以通过探测哪些凭据可用而识别用户。例如,一种这样的信息泄露是客户端在排除的验证器可用时立即返回失败响应。在这种情况下——特别是如果该被排除的验证器是平台验证器——依赖方可能会检测到仪式在超时前被取消,且用户不可能手动取消它,从而推断出用户拥有 excludeCredentials 参数中列出的至少一个凭据。
然而,如果用户在返回可区分的错误之前已经同意创建新凭据,则上述情况并非担忧,因为在这种情况下,用户已确认有意共享可能被泄露的信息。
14.5.2. 身份验证仪式隐私
为了保护用户在未经同意的情况下被识别,[[DiscoverFromExternalSource]](origin, options, sameOriginWithAncestors) 方法的实现需要注意不要泄露可能使恶意 WebAuthn 依赖方能够区分以下情况的信息,其中“命名 (named)”意味着凭据被 依赖方 列在 allowCredentials 中:
如果上述情况是可以区分的,那么就会泄露信息,恶意依赖方可以通过探测哪些凭据可用而识别用户。例如,一种这样的信息泄露是客户端在用户拒绝同意继续进行身份验证仪式时立即返回失败响应。在这种情况下,依赖方可能会检测到仪式是被用户取消而非超时取消,从而推断出用户拥有 allowCredentials 参数中列出的至少一个凭据。
14.5.3. 操作系统账户之间的隐私
如果一个平台验证器包含在具有多用户操作系统的客户端设备中,平台验证器和客户端设备应协同工作,以确保任何平台凭据的存在性仅向创建该平台凭据的操作系统用户揭示。
14.6. 针对依赖方的隐私考量
14.6.1. 用户句柄内容
由于用户句柄在 § 14.4.2 存储在验证器中的个人身份信息隐私 中不被视为个人身份信息,因此依赖方不得在用户句柄中包含个人身份信息,例如电子邮件地址或用户名。这包括个人身份信息的哈希值,除非哈希函数使用对依赖方私有的加盐 (salted) 值进行了加盐处理,因为哈希不能防止对可猜测输入值的探测。建议让用户句柄为 64 字节的随机值,并将此值存储在用户的账户中。
14.6.2. 用户名枚举
在发起注册或身份验证仪式时,存在 WebAuthn 依赖方可能泄露其注册用户敏感信息的风险。例如,如果依赖方使用电子邮件地址作为用户名,且攻击者尝试为 "alex.mueller@example.com" 发起身份验证仪式,而依赖方响应失败,但随后成功为 "j.doe@example.com" 发起了身份验证仪式,那么攻击者可以推断出 "j.doe@example.com" 已注册,而 "alex.mueller@example.com" 未注册。依赖方因此泄露了 "j.doe@example.com" 在此依赖方拥有账户这一可能敏感的信息。
以下是一份非规范性、非详尽的列表,列出了依赖方可能实施以减轻或防止由于此类攻击导致的信息泄露的措施:
-
对于注册仪式:
-
对于身份验证仪式:
-
如果在发起身份验证仪式时没有与提供的用户名匹配的账户,通过使用填充了合理的虚构值的语法有效的
PublicKeyCredentialRequestOptions对象调用navigator.credentials.get()来继续仪式。这种方法也可以用于减轻通过
allowCredentials的信息泄露;请参阅 § 13.4.7 未受保护的账户检测 和 § 14.6.3 通过凭据 ID 的隐私泄露。注意:用户名可以通过各种依赖方特定的方式“提供”:登录表单、会话 Cookie 等。
注意:如果返回的虚构值与实际值有显著差异,聪明的攻击者可能能够分辨出它们,从而能够测试实际账户的存在。显著不同值的示例包括:所有用户名输入的值总是相同的,或者在用同一个用户名输入进行的重复尝试中是不同的。因此,
allowCredentials成员可以用从用户名确定性导出的伪随机值来填充,例如。 -
在验证来自验证器的
AuthenticatorAssertionResponse响应时,使验证失败的原因(是因为签名无效,还是因为未注册此类用户或凭据)无法区分。 -
执行多步身份验证仪式,例如在作为后续步骤启动 WebAuthn 仪式之前,先从提供用户名和密码或会话 Cookie 开始。这会将用户名枚举问题从 WebAuthn 步骤转移到前面的身份验证步骤,在那里可能更容易解决。
-
14.6.3. 通过凭据 ID 的隐私泄露
本节不具有规范性。
此隐私考量适用于支持在身份验证第一步中使用非空 allowCredentials 参数进行身份验证仪式的依赖方。例如,在第一步身份验证中使用了服务器端凭据的情况。
在这种情况下,allowCredentials 参数存在泄露个人身份信息的风险,因为它向未认证的调用者暴露了用户的凭据 ID。凭据 ID 的设计宗旨是不在依赖方之间关联,但凭据 ID 的长度可能是其创建者验证器类型的线索。用户很可能会对多个依赖方使用相同的用户名和一组验证器,因此 allowCredentials 中凭据 ID 的数量及其长度可能作为全局关联句柄来对用户进行去匿名化。了解用户的凭据 ID 也使得在仅有瞬时物理访问权限获取用户其中一个验证器的情况下,确认关于用户身份的猜测成为可能。
为了防止此类信息泄露,依赖方可以例如:
-
在发起 WebAuthn 身份验证仪式并暴露用户的凭据 ID 之前,执行单独的身份验证步骤,例如用户名和密码身份验证或会话 Cookie 身份验证。
-
使用客户端侧可发现凭据,这样就不需要
allowCredentials参数。
如果上述预防措施不可用,即如果仅给定用户名就需要暴露 allowCredentials,依赖方可以使用与 § 14.6.2 用户名枚举 中讨论的返回虚构凭据 ID 相同的方法来减轻隐私泄露。
15. 可访问性考量
具备用户验证能力的验证器,无论是漫游验证器还是平台验证器,都应为用户提供一种以上的用户验证方法。例如,指纹感应和 PIN 输入。这允许在所选方法由于某种原因无法工作时,回退到其他用户验证手段。请注意,在漫游验证器的情况下,验证器和平台可能协同工作以提供诸如 PIN 输入的用户验证方法 [FIDO-CTAP]。
依赖方应在注册时提供便利,让用户能够正确完成未来的授权手势。这可能包括命名验证器、选择一张图片与设备关联,或输入自由文本说明(例如作为自我提醒)。
依赖于时间的仪式,例如注册仪式(请参阅 timeout)或身份验证仪式(请参阅 timeout),应当遵循 [WCAG21] 的 指南 2.2 足够时间。如果客户端平台确定依赖方提供的超时时间未能适当遵循后者的 [WCAG21] 指南,则客户端平台可以相应地调整超时时间。
16. 致谢
我们感谢以下人员对本规范的评审和贡献:Yuriy Ackermann, James Barclay, Richard Barnes, Dominic Battré, Julien Cayzac, Domenic Denicola, Rahul Ghosh, Brad Hill, Jing Jin, Wally Jones, Ian Kilpatrick, Axel Nennker, Yoshikazu Nojima, Kimberly Paulhamus, Adam Powers, Yaron Sheffer, Ki-Eun Shin, Anne van Kesteren, Johan Verrept, 和 Boris Zbarsky。感谢 Adam Powers 创建了整体的注册和身份验证流程图(图 1 和 图 2)。
我们感谢 Anthony Nadalin, John Fontana, 和 Richard Barnes 作为 Web Authentication 工作组联合主席所做的贡献。
我们还要感谢 Wendy Seltzer, Samuel Weiler, 和 Harry Halpin 作为我们的 W3C 团队联系人所做的贡献。