1. 介绍
本节内容不具有规范性。
本规范定义了一个 API,允许通过范围限定的、基于公钥的强认证凭据的创建和使用,供Web 应用用于强用户身份验证。公钥凭据由WebAuthn 认证器在WebAuthn 依赖方的要求下创建和存储,并需要用户同意。此后,公钥凭据只能由属于该依赖方的来源访问。此范围由符合规范的用户代理和认证器共同执行。此外,还会保持跨依赖方的隐私;依赖方无法检测到其他依赖方的凭据属性,甚至无法检测到凭据的存在。
依赖方在涉及用户的两个独立但相关的过程中使用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框架开发者
-
上述两个受众特别应参考§ 7 WebAuthn依赖方操作。§ 5 Web身份验证API的介绍可能会有所帮助,但读者应认识到§ 5 Web身份验证API部分专门针对用户代理开发者,而非Web应用程序开发者。此外,如果他们打算验证认证器的证明,那么§ 6.5 证明和§ 8 已定义的证明声明格式也将相关。§ 9 WebAuthn扩展和§ 10 已定义的扩展将引起他们的兴趣,如果他们希望使用扩展功能。最后,他们应阅读§ 13.4 针对依赖方的安全注意事项和§ 14.6 针对依赖方的隐私注意事项,并考虑哪些挑战适用于他们的应用程序和用户。
-
-
用户代理开发者
-
操作系统平台开发者,负责操作系统平台API设计和实现,涉及平台特定的认证器API、平台WebAuthn客户端实例化等。
-
上述两个受众应非常仔细地阅读§ 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,加载脚本。此时,用户可能已经使用传统的用户名和密码、其他认证器或其他依赖方接受的方法登录,或者用户可能正在创建新帐户。
-
依赖方脚本运行下面的代码片段。
-
客户端平台搜索并定位认证器。
-
客户端连接到认证器,必要时执行任何配对操作。
-
认证器显示适当的用户界面,用户提供生物识别或其他授权手势。
-
如果创建了新凭证,
生成并注册新密钥的示例代码如下:
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 -- 用户从认证器中删除凭证。
1.4. 平台特定的实现指南
本规范定义了如何在一般情况下使用Web Authentication。 在与特定平台支持(例如应用程序)相关使用Web Authentication时,建议参阅平台特定的文档和指南,以获得更多指导和限制。
2. 一致性
本规范定义了三个一致性类。每个类的规范都是为了确保该类的符合成员能够安全抵御其他类的非符合或敌对成员。
2.1. 用户代理
用户代理必须按§ 5 Web Authentication 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编码指的是第5节中定义的使用URL和文件名安全字符集的base64编码[RFC4648],省略了所有尾随的'='字符(如第3.2节允许)且不包含任何换行符、空白或其他附加字符。
- CBOR
-
本规范中的许多结构,包括证明声明和扩展,都是使用CTAP2规范的CBOR编码形式的紧凑二进制对象表示(CBOR)[RFC8949]编码的,如[FIDO-CTAP]中定义。
- CDDL
- COSE
-
CBOR对象签名和加密(COSE)[RFC8152]。此规范建立的IANA COSE算法注册表[IANA-COSE-ALGS-REG]也被使用。
- 凭据管理
-
本文档描述的API是[CREDENTIAL-MANAGEMENT-1]中定义的
Credential
概念的扩展。 - DOM
-
DOMException
及本规范中使用的DOMException值定义在[DOM4]中。 - ECMAScript
- HTML
- URL
- Web IDL
-
本规范中的许多接口定义及所有IDL依赖于[WebIDL]。此Web IDL标准的更新版本增加了对
Promise
的支持,这些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. 术语
- 证明
-
通常情况下,证明是一种用于见证、确认或认证的声明。在WebAuthn的上下文中,证明用于证明认证器及其发出的数据的来源;包括例如:凭证ID、凭证密钥对、签名计数器等。在注册期间,证明声明通过证明对象传达。另见§ 6.5 证明和图6。客户端是否以及如何传达证明声明和AAGUID部分到依赖方由证明传递决定。
- 证明证书
-
A X.509 证书用于 证明密钥对,由认证器用于证明其制造和能力。在注册时,认证器使用证明私钥签署特定于依赖方的凭证公钥(和其他数据),并通过authenticatorMakeCredential操作生成并返回这些数据。依赖方使用在证明证书中传达的证明公钥来验证证明签名。请注意,在自我证明的情况下,认证器没有独立的证明密钥对或证明证书,请参阅自我证明了解详情。
- 身份验证
- 身份验证仪式
-
在此仪式中,用户及其包含至少一个认证器的客户端协同工作,以加密方式向依赖方证明用户控制了先前注册的公钥凭证的凭证私钥(参见注册)。请注意,这包括用户存在性测试或用户验证。
WebAuthn身份验证仪式定义在§ 7.2 验证身份验证断言中,由依赖方调用
navigator.credentials.get()
并传入publicKey
参数来启动。参见§ 5 Web身份验证API了解介绍性概述,以及§ 1.3.3 身份验证的实现示例。 - 身份验证断言
- 断言
-
由认证器作为authenticatorGetAssertion操作的结果返回的经过加密签名的
AuthenticatorAssertionResponse
对象。这对应于[CREDENTIAL-MANAGEMENT-1]规范中的单次使用凭证。
- 认证器
- WebAuthn认证器
-
一个存在于硬件或软件中的加密实体,可以注册用户到指定的依赖方,并在依赖方请求时,断言持有已注册的公钥凭证,并可选择验证用户。认证器可以在注册期间通过证明报告其类型和安全特性。
WebAuthn认证器可以是漫游认证器,是集成在客户端设备中的专用硬件子系统,或者是客户端或客户端设备的软件组件。
通常情况下,认证器假定只有一个用户。如果多个自然人共享一个认证器,则在该认证器的上下文中,他们被视为同一个用户。如果认证器实现支持在分离的隔间中有多个用户,则每个隔间被视为单独的认证器,每个用户都是独立的,不可访问其他用户的凭证。
- 授权手势
-
授权手势是用户与认证器进行物理交互的一部分,通常在仪式中,如注册或身份验证。通过执行授权手势,用户提供了同意,即授权一个仪式继续进行。这可能涉及用户验证(如果使用的认证器支持),或可能仅涉及简单的用户存在性测试。
- 生物识别
-
基于个体生物和行为特征的自动识别 [ISOBiometricVocabulary]。
- 生物识别认证器
-
任何实现了生物识别功能的认证器。
- 绑定凭证
-
绑定凭证是指绑定到其管理认证器的公共密钥凭证源或公共密钥凭证。这意味着只有该管理认证器可以为其绑定的公共密钥凭证源生成断言。
- 仪式
-
仪式的概念是网络协议概念的扩展,具有包括人类节点在内的计算节点和通信链路,这些链路包括用户界面、人对人的通信以及携带数据的物理对象的传输。在此规范中,注册和身份验证是仪式,授权手势通常是这些仪式的组成部分。
- 客户端
- WebAuthn客户端
-
在此也简称为客户端。另见符合用户代理。WebAuthn客户端是一个中介实体,通常在用户代理中实现(全部或部分)。概念上,它位于Web身份验证API的基础之上,并实现了内部方法。它负责为底层认证器操作编组输入,并将后者操作的结果返回给Web身份验证API的调用者。
WebAuthn客户端运行在WebAuthn客户端设备上,并且与之不同。
- 客户端设备
- WebAuthn客户端设备
-
WebAuthn客户端运行的硬件设备,例如智能手机、笔记本电脑或台式电脑,以及运行在该硬件上的操作系统。
WebAuthn客户端设备和客户端之间的区别:
-
单个客户端设备可以支持运行多个客户端,即浏览器实现,所有这些都可以访问该客户端设备上的相同认证器,
-
平台认证器绑定到客户端设备而不是WebAuthn客户端。
客户端设备和客户端共同构成一个客户端平台。
-
- 客户端平台
-
客户端设备和客户端共同构成一个客户端平台。单个硬件设备可以通过运行不同的操作系统和/或客户端,成为多个不同客户端平台的一部分。
- 客户端
-
这通常指用户的客户端平台、认证器以及将其连接在一起的一切。
- 客户端可发现的公共密钥凭证源
- 客户端可发现的凭证
- 可发现的凭证
- [已弃用] 驻留凭证
- [已弃用] 驻留密钥
- 客户端可发现的凭证
-
注意:历史上,客户端可发现的凭证被称为驻留凭证或驻留密钥。由于ResidentKey和residentKey术语在WebAuthn API及身份认证模型中被广泛使用(例如,在字典成员名称、算法变量名和操作参数中),为了向后兼容,其名称中的resident用法未作更改。此外,驻留密钥在此定义为等同于客户端可发现的凭证。
客户端可发现的公共密钥凭证源,简称为可发现的凭证,是一个公共密钥凭证源,在身份验证仪式中可发现该凭证源,而依赖方不提供任何凭证ID,即依赖方调用navigator.credentials.get(),并传入空的allowCredentials参数。这意味着依赖方不一定需要首先识别用户。
因此,一个可发现凭证支持的认证器仅凭RP ID即可为可发现凭证生成断言签名,这反过来要求公共密钥凭证源存储在认证器或客户端平台中。这与服务器端公共密钥凭证源相反,后者要求认证器同时提供RP ID和凭证ID,但不需要客户端存储公共密钥凭证源。
另见:客户端凭证存储方式和不可发现凭证。
注意:客户端可发现凭证也可用于提供凭证ID的身份验证仪式中,即在调用navigator.credentials.get()时传入非空的allowCredentials参数。
- 符合用户代理
-
用户代理通过与底层客户端设备配合,实施本规范中给出的Web身份验证API和算法,并处理认证器和依赖方之间的通信。
- 凭证ID
-
用于标识公共密钥凭证源及其身份验证断言的具有概率唯一性的字节序列。
凭证ID由认证器生成,有两种形式:
-
至少16个字节,其中至少包含100位的熵,或
-
公共密钥凭证源,去除凭证ID或可变项后进行加密,使得只有其管理认证器可以解密。此形式允许认证器几乎无状态,因为依赖方可以存储任何必要的状态。
注意: [FIDO-UAF-AUTHNR-CMDS]中包括了在“安全指南”部分的加密技术指导。
依赖方不需要区分这两种凭证ID形式。
-
- 凭证密钥对
- 凭证私钥
- 凭证公钥
- 用户公钥
- 凭证私钥
-
凭证密钥对是由认证器生成并限定于特定WebAuthn依赖方的一对非对称加密密钥。它是公共密钥凭证的核心部分。
凭证公钥是凭证密钥对的公钥部分。凭证公钥在注册仪式中返回给依赖方。
凭证私钥是凭证密钥对的私钥部分。凭证私钥绑定到特定的认证器——即其管理认证器——并预计永远不会暴露给任何其他方,甚至不会暴露给认证器的所有者。
请注意,在自我证明的情况下,凭证密钥对也用作证明密钥对,详见自我证明。
注意: 凭证公钥在FIDO UAF协议和FIDO U2F消息格式及本规范中与之相关的部分中被称为用户公钥。
- 凭证属性
-
凭证属性是公共密钥凭证源的某种特性,如是否为客户端可发现的凭证或服务器端凭证。
- 人类可接受性
-
人类可接受的标识符旨在被典型的人类用户记住和再现,相对于例如随机生成的位序列。
- 不可发现的凭证
-
这是一个凭证,其凭证ID必须在调用navigator.credentials.get()时在allowCredentials中提供,因为它不可客户端发现。另见服务器端凭证。
- 公共密钥凭证源
-
公共密钥凭证源是认证器用于生成身份验证断言的凭证源。公共密钥凭证源由以下项组成:
- 类型
-
其值为PublicKeyCredentialType,默认为public-key。
- ID
-
凭证ID。
- 私钥
-
凭证私钥。
- RP ID
-
公共密钥凭证源限定的依赖方标识符。
- 用户句柄
-
在创建公共密钥凭证源时关联的用户句柄。该项是可空的。
- 其他UI
-
可选的其他信息,用于认证器的UI。例如,这可能包括用户的displayName。otherUI是可变项,不应绑定到公共密钥凭证源,以防止更新otherUI。
authenticatorMakeCredential操作创建一个绑定到管理认证器的公共密钥凭证源,并返回其凭证私钥关联的凭证公钥。依赖方可以使用此凭证公钥验证由此公共密钥凭证源创建的身份验证断言。
- 公共密钥凭证
-
一般而言,凭证是一个实体向另一个实体提交以证明前者身份的数据。公共密钥凭证这一术语指代以下之一:公共密钥凭证源、可能经过证明的凭证公钥或身份验证断言。具体是哪一种通常由上下文决定。
注意:这是对[RFC4949]的故意违背。英语中,凭证既可以是用于证明声明的事物,也可以是用于多次使用的事物。在公钥系统中,无法通过单一数据安全地实现这两者。RFC4949选择将凭证定义为可以多次使用的事物(即公钥),而本规范则赋予凭证这一英语术语的灵活性。本规范使用更具体的术语来标识与RFC4949凭证相关的数据:- "身份验证信息"(可能包括私钥)
-
公共密钥凭证源
- "签名值"
-
身份验证断言
- RFC4949 "凭证"
-
凭证公钥或证明对象
在注册时,认证器创建一个非对称密钥对,并将其私钥部分及来自依赖方的信息存储到公共密钥凭证源中。公钥部分返回给依赖方,后者将其与当前用户的账户一起存储。随后,只有该依赖方,才可以在身份验证仪式中使用该公共密钥凭证,方法是调用get()方法。依赖方使用其存储的凭证公钥副本验证生成的身份验证断言。
- 速率限制
-
通过限制给定时间段内连续身份验证失败次数的方式(也称为节流)来实施防止暴力破解攻击的控制。如果达到限制,认证器应施加一个延迟,该延迟随每次尝试递增,或禁用当前的身份验证模式,并提供其他认证因素(如果有)。速率限制通常作为用户验证的一个方面实施。
- 注册
- 注册仪式
-
在此仪式中,用户、依赖方和包含至少一个认证器的客户端共同合作,创建一个公共密钥凭证并将其与用户的依赖方账户关联。请注意,这包括进行用户存在性测试或用户验证。在成功的注册仪式后,用户可以通过身份验证仪式进行身份验证。
WebAuthn注册仪式定义在§ 7.1 注册新凭证中,由依赖方调用navigator.credentials.create()并传入publicKey参数来启动。参见§ 5 Web身份验证API了解介绍性概述以及§ 1.3.1 注册的实现示例。
- 依赖方
-
参见WebAuthn依赖方。
- 依赖方标识符
- RP ID
-
在WebAuthn API上下文中,依赖方标识符是标识WebAuthn依赖方的有效域名字符串,用于注册或身份验证仪式。公共密钥凭证只能用于与其注册时同一实体(由RP ID标识)的身份验证。
默认情况下,WebAuthn操作的RP ID设置为调用者的源的有效域名。此默认值可由调用者覆盖,只要调用者指定的RP ID值是调用者源的有效域名的可注册域名后缀或等于该域名。另见§ 5.1.3 创建新凭证 - PublicKeyCredential的[[Create]](origin, options, sameOriginWithAncestors)方法和§ 5.1.4 使用现有凭证进行断言 - PublicKeyCredential的[[Get]](options)方法。
注意:RP ID基于主机的域名。它本身不包括方案或端口,如同源那样。公共密钥凭证的RP ID决定其范围。即,它决定公共密钥凭证可以在哪些来源上使用,具体如下:-
RP ID必须等于源的有效域名,或是源的有效域名的可注册域名后缀。
-
源的方案必须为https。
-
源的端口不受限制。
例如,假设依赖方的源为https://login.example.com:1337,则以下RP ID有效:login.example.com(默认)和example.com,但m.login.example.com和com无效。
这是为了与广泛部署的环境凭证(例如,cookie,[RFC6265])的行为相匹配。请注意,这比document.domain的设置器提供的“同源”限制更宽松。
这些对源值的限制适用于WebAuthn客户端。
其他模仿WebAuthn API以在非Web平台(例如本地移动应用程序)上启用WebAuthn公共密钥凭证的规范,可能会定义不同的规则来将调用者绑定到依赖方标识符。尽管如此,RP ID语法必须符合有效域名字符串或URI [RFC3986] [URL]。
-
- 服务器端公共密钥凭证源
- 服务器端凭证
- [已弃用] 非驻留凭证
- 服务器端凭证
-
注意:历史上,服务器端凭证被称为非驻留凭证。为了向后兼容,WebAuthn API和认证器模型中的各种形式的resident名称未作更改。
服务器端公共密钥凭证源,简称为服务器端凭证,是在身份验证仪式中仅当依赖方在调用navigator.credentials.get()时提供其凭证ID时才可用的公共密钥凭证源。这意味着依赖方必须管理凭证的存储和发现,并能够首先识别用户,以便发现要在调用navigator.credentials.get()时提供的凭证ID。
不需要客户端存储公共密钥凭证源。这与客户端可发现的凭证相反,后者不需要首先识别用户即可为调用navigator.credentials.get()提供用户的凭证ID。
另见:服务器端凭证存储方式和不可发现凭证。
- 用户存在性测试
-
用户存在性测试是一种简单的授权手势形式和技术过程,用户通过(通常是)简单触摸认证器(其他形式可能也存在)与认证器交互,产生布尔结果。请注意,这不构成用户验证,因为用户存在性测试按定义无法实现生物识别,也不涉及密码或PIN等共享秘密的展示。
- 用户同意
-
用户同意意味着用户同意他们被要求的内容,即包括阅读和理解提示。授权手势是仪式的一个组成部分,通常用于表示用户同意。
- 用户句柄
-
用户句柄由依赖方指定,作为user.id的值,用于将特定的公共密钥凭证映射到依赖方的特定用户账户。认证器依次将RP ID和用户句柄对映射到公共密钥凭证源。
用户句柄是一个最大大小为64字节的不透明字节序列,并不打算显示给用户。
- 用户验证
-
用户验证是认证器在本地授权调用authenticatorMakeCredential和authenticatorGetAssertion操作的技术过程。用户验证可以通过各种授权手势形式启动,例如通过触摸加PIN码、密码输入或生物识别(例如,展示指纹)。目的是区分个别用户。
请注意,用户验证并未向依赖方提供用户的具体身份,但当使用相同凭证进行了两次或更多次具有用户验证的仪式时,它表明是同一个用户执行了所有这些仪式。然而,如果多个自然人共享同一个认证器,则相同用户不一定总是同一个自然人。
注意:区分自然人很大程度上取决于客户端平台和认证器的能力。例如,有些设备旨在供单个个体使用,但它们可能允许多个自然人注册指纹或知道相同的PIN,从而使用该设备访问相同的依赖方账户。
注意:调用authenticatorMakeCredential和authenticatorGetAssertion操作意味着使用认证器管理的密钥材料。此外,为了安全,用户验证和使用凭证私钥必须在定义认证器的逻辑安全边界内进行。
用户验证程序可以实施速率限制,作为防止暴力破解攻击的一种保护措施。
- 用户在场
- UP
-
在成功完成用户存在性测试后,用户被认为是“在场”。
- 用户已验证
- UV
-
在成功完成用户验证过程后,用户被认为是“已验证”。
- WebAuthn依赖方
-
其Web应用程序利用Web身份验证API注册和验证用户的实体。
依赖方实现通常由一些客户端脚本(在客户端中调用Web身份验证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, 而是返回对象中数据的base64url编码,[[identifier]]
内部槽。 rawId
-
此属性返回
ArrayBuffer
,包含在[[identifier]]
内部槽中。 -
适用于所有当前引擎。
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
"。注意:这通过
type
继承自Credential
的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对象 获取详细说明。
此 内部方法 接受三个参数:
origin
options
-
此参数是一个
CredentialCreationOptions
对象,其options.
成员包含一个publicKey
PublicKeyCredentialCreationOptions
对象,指定要创建的公钥凭证的期望属性。 sameOriginWithAncestors
-
此参数是一个布尔值,当且仅当调用者的环境设置对象与其祖先同源时为
true
。如果调用者是跨域的,则为false
。注意:此 内部方法的调用表明它已被权限策略允许,评估于[CREDENTIAL-MANAGEMENT-1]级别。 详见 § 5.9 权限策略集成。
注意: 此算法是同步的: Promise
的解决/拒绝由navigator.credentials.create()
处理。
注意:此算法中使用的所有BufferSource
对象必须在算法开始时进行快照,
以避免潜在的同步问题。算法实现应获取缓冲源持有的字节的副本并在算法的相关部分中使用该副本。
当调用此方法时,用户代理必须执行以下算法:
-
断言:
options.
是存在的。publicKey
-
如果sameOriginWithAncestors为
false
,则返回 "NotAllowedError
"DOMException
。注意:此"sameOriginWithAncestors"限制旨在解决在问题 #1336中提出的跟踪问题。此规范的未来版本可能会对此进行修订。
-
让options为
options.
的值。publicKey
-
如果
timeout
成员options存在,检查其值是否在客户端定义的合理范围内,如果不在,则将其调整为该范围内的最接近值。将计时器lifetimeTimer设置为此调整后的值。如果timeout
成员options不存在,则将lifetimeTimer设置为客户端特定的默认值。对于
timeout
成员options的推荐范围和默认值如下: 如果options.
authenticatorSelection
.userVerification
- 设置为
discouraged
-
推荐范围:30000 毫秒到 180000 毫秒。
推荐默认值:120000 毫秒(2 分钟)。
- 设置为
required
或preferred
-
推荐范围:30000 毫秒到 600000 毫秒。
推荐默认值:300000 毫秒(5 分钟)。
注意:用户代理应在考虑具有特殊需求的用户的认知指南后再确定超时。
- 设置为
-
设callerOrigin为
origin
。 如果callerOrigin是不透明的origin,则返回一个DOMException
其名称为 "NotAllowedError
", 并终止此算法。 -
设effectiveDomain为callerOrigin的有效域名。 如果有效域名不是有效域名,则返回一个
DOMException
其名称为 "SecurityError
", 并终止此算法。注意:一个有效域名可以解析为host,其表示形式多种多样, 如域名、IPv4 地址、 IPv6 地址、不透明的host或 空host。 此处仅允许域名格式的host。 这是为了简化,同时也 认识到使用直接IP地址识别与PKI-based安全结合使用的各种问题。
-
- 存在
-
如果
options.
不是注册域名后缀或不等于effectiveDomain, 返回一个rp
.id
DOMException
其名称为"SecurityError
", 并终止此算法。 - 不存在
注意:
options.
代表调用者的RP ID。RP ID默认情况下为调用者的origin的effective domain,除非调用者在调用rp
.id
create()
时显式设置了options.
。rp
.id
-
让credTypesAndPubKeyAlgs为一个新的列表,其项为
PublicKeyCredentialType
和 一个COSEAlgorithmIdentifier
。 -
如果
options.
的大小pubKeyCredParams
- 为零
-
附加以下
PublicKeyCredentialType
和COSEAlgorithmIdentifier
对到credTypesAndPubKeyAlgs:-
public-key
和-7
("ES256")。 -
public-key
和-257
("RS256")。
-
- 非零
-
对于每个current的
options.
:pubKeyCredParams
-
如果
current.
不包含此实现支持的type
PublicKeyCredentialType
, 则继续。 -
设alg为
current.
。alg
如果credTypesAndPubKeyAlgs为空,则返回
DOMException
其名称为 "NotSupportedError
", 并终止此算法。 -
-
如果options的
extensions
成员存在,则对于每个 extensionId → clientExtensionInput的options.
:extensions
-
让collectedClientData为一个新的
CollectedClientData
实例,其字段为:type
-
字符串 "webauthn.create"。
challenge
-
options的
challenge
的base64url 编码。 origin
-
callerOrigin的序列化。
crossOrigin
-
传递给此内部方法的
sameOriginWithAncestors
参数值的反转。 tokenBinding
-
让clientDataJSON为从collectedClientData构造的客户端数据的JSON兼容序列化。
-
让clientDataHash为由clientDataJSON表示的客户端数据序列化后的哈希值。
-
如果
options.
存在,并且其中止标志设置为signal
true
,则返回DOMException
其名称为"AbortError
", 并终止此算法。 -
让issuedRequests为一个新的有序集合。
-
让authenticators表示一个值,该值在任何给定时刻都是一个集合,其中每个项标识此客户端平台此时可用的认证器。
注意: 什么使认证器被视为"可用"是有意未指定的;这是为了表示如何通过各种机制认证器可以热插拔到(例如,通过USB)或被客户端发现(例如,通过NFC或蓝牙),或永久内置于客户端中。
-
启动lifetimeTimer。
-
当lifetimeTimer未过期时,依据lifetimeTimer、 状态和响应对于每个 authenticator 在 authenticators 中执行以下操作:
- 如果lifetimeTimer过期,
-
对于每个authenticator在 issuedRequests 中调用authenticatorCancel操作,并移除authenticator从 issuedRequests中。
- 如果用户行使用户代理用户界面选项来取消该过程,
-
对于每个authenticator在 issuedRequests中调用authenticatorCancel操作,并移除authenticator从 issuedRequests中。返回一个
DOMException
其名称为 "NotAllowedError
"。 - 如果
options.
存在并且其中止标志设置为signal
true
, -
对于每个authenticator在 issuedRequests中调用authenticatorCancel操作,并移除authenticator从 issuedRequests中。然后返回一个
DOMException
其名称为"AbortError
", 并终止此算法。 - 如果authenticator在此客户端设备上变得可用,
-
注意:这包括lifetimeTimer启动时authenticator已经可用的情况。
-
此authenticator现在是候选认证器。
-
如果
options.
存在:authenticatorSelection
-
如果
options.
存在且其值不等于authenticator的认证器连接方式,继续。authenticatorSelection
.authenticatorAttachment
-
如果
options.
authenticatorSelection
.residentKey
- 存在并设置为
required
-
如果authenticator无法存储客户端可发现的公钥凭证源,继续。
- 存在并设置为
preferred
或discouraged
-
无效。
- 不存在
-
如果
options.
设置为authenticatorSelection
.requireResidentKey
true
,且authenticator无法存储客户端可发现的公钥凭证源,继续。
- 存在并设置为
-
如果
options.
设置为authenticatorSelection
.userVerification
required
且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
-
设enterpriseAttestationPossible为
true
,如果用户代理希望支持企业证明对于options.
(参见步骤8,在上文中)。 否则设为rp
.id
false
。 - 否则
-
设enterpriseAttestationPossible为
false
。
- 设置为
-
让excludeCredentialDescriptorList为一个新的列表。
-
对于每个凭证描述符C在
options.
中:excludeCredentials
-
如果
C.
非空,并且 authenticator连接的传输方式不在transports
C.
中提到,客户端可继续。transports
注意:如果客户端选择继续,这可能会导致意外注册多个凭证绑定到同一个认证器,如果
C.
中的传输提示不准确。 例如,存储的传输提示可能会因为软件升级添加了新的连接选项而变得不准确。transports
-
否则,附加C到 excludeCredentialDescriptorList中。
-
在authenticator上调用authenticatorMakeCredential操作,并使用clientDataHash,
options.
,rp
options.
, requireResidentKey, userVerification, credTypesAndPubKeyAlgs, excludeCredentialDescriptorList, enterpriseAttestationPossible, 以及authenticatorExtensions作为参数。user
-
-
附加authenticator到 issuedRequests。
-
- 如果authenticator在此客户端设备上不再可用,
-
移除authenticator从 issuedRequests中。
- 如果任何authenticator返回状态指示用户取消了操作,
-
-
移除authenticator从 issuedRequests中。
-
对于每个剩余的authenticator 在issuedRequests中调用authenticatorCancel操作,并移除它从issuedRequests中。
注意:认证器可能会返回“用户取消了整个操作”的指示。 用户代理如何将此状态显示给用户是未指定的。
-
- 如果任何authenticator返回的错误状态等同于"
InvalidStateError
", -
-
移除authenticator从 issuedRequests中。
-
对于每个剩余的authenticator 在issuedRequests中调用authenticatorCancel操作,并移除它从issuedRequests中。
-
返回一个
DOMException
其名称为"InvalidStateError
", 并终止此算法。
注意:此错误状态单独处理,因为authenticator仅在 excludeCredentialDescriptorList标识了一个凭证绑定到authenticator,且用户已同意该操作时才会返回。 鉴于这种明确的同意,允许Relying Party识别此情况是可以接受的。
-
- 如果任何authenticator返回的错误状态不等同于"
InvalidStateError
", -
移除authenticator从 issuedRequests中。
注意:此情况并不意味着对该操作的用户同意, 因此错误的详细信息对Relying Party隐藏,以防止泄露可能识别用户的信息。 参见§ 14.5.1 注册仪式隐私以了解详细信息。
- 如果任何authenticator指示成功,
-
-
移除authenticator从 issuedRequests中。此认证器现在是已选认证器。
-
让credentialCreationData为一个结构体, 其中的项为:
-
attestationObjectResult
-
其值为从成功的authenticatorMakeCredential 操作返回的字节。
注意:此值为
attObj
,如在§ 6.5.4 生成证明对象中定义。 -
clientDataJSONResult
-
其值为clientDataJSON的字节。
-
attestationConveyancePreferenceOption
-
其值为options的
attestation
的值。 -
clientExtensionResults
-
其值为一个
AuthenticationExtensionsClientOutputs
对象,包含扩展标识符→客户端扩展输出 条目。条目是通过运行每个扩展的客户端扩展处理算法来创建客户端扩展输出,对于options的
中的每个客户端扩展。extensions
-
-
让constructCredentialAlg成为一个算法,该算法接受一个全局对象global, 其步骤为:
-
如果
credentialCreationData的attestationConveyancePreferenceOption
的值为- "none"
-
用非识别版本替换可能唯一识别的信息:
-
如果AAGUID在证明的凭证数据中为16个零字节,
credentialCreationData.attestationObjectResult.fmt
为"packed",且"x5c"不存在于credentialCreationData.attestationObjectResult
中,则正在使用自我证明且无需进一步操作。 -
否则
-
将
credentialCreationData的attestationObjectResult.fmt
设置为"none",并将credentialCreationData的attestationObjectResult.attStmt
设置为空的CBOR 映射。 (参见§ 8.7 无证明声明格式和§ 6.5.4 生成证明对象)。
-
- "indirect"
- "direct"或"enterprise"
-
让attestationObject为一个新的
ArrayBuffer
, 使用global的%ArrayBuffer%创建, 包含credentialCreationData的attestationObjectResult
的值的字节。 -
让id为
attestationObject.authData.attestedCredentialData.credentialId
。 -
让pubKeyCred为一个新的
PublicKeyCredential
对象,与global相关联,其字段为:[[identifier]]
-
id
response
-
一个新的
AuthenticatorAttestationResponse
对象,与global相关联,其字段为:clientDataJSON
-
一个新的
ArrayBuffer
, 使用global的%ArrayBuffer%创建, 包含credentialCreationData的clientDataJSONResult
的字节。 attestationObject
-
attestationObject
[[transports]]
-
一个或多个唯一的
DOMString
的序列, 按字典序排列,authenticator被认为支持这些值。 值应该是AuthenticatorTransport
的成员, 但客户端平台必须忽略未知的值。如果用户代理不希望透露此信息,则可以用设计用来保护隐私的任意序列代替。此序列仍必须有效,即按字典顺序排列且不重复。例如,它可以使用空序列。无论哪种方式,在这种情况下,用户代理需要承担Relying Party行为可能不理想的风险。
如果用户代理没有任何传输信息,它应将此字段设置为空序列。
注意:用户代理如何发现给定authenticator支持的传输方式超出了本规范的范围,但可能包括来自证明证书的信息(例如[FIDO-Transports-Ext]), 通过authenticator协议(如CTAP2)通信的元数据,或关于平台认证器的特例知识。
[[clientExtensionsResults]]
-
一个新的
ArrayBuffer
, 使用global的%ArrayBuffer%创建, 包含credentialCreationData的clientExtensionResults
的字节。
-
返回pubKeyCred。
-
-
对于每个剩余的authenticator 在issuedRequests中调用authenticatorCancel操作,并移除它从issuedRequests中。
-
返回constructCredentialAlg并终止此算法。
-
-
返回一个
DOMException
其名称为"NotAllowedError
"。 为了防止在没有用户同意的情况下泄露可能识别用户的信息, 此步骤必须在lifetimeTimer过期之前不执行。 参见§ 14.5.1 注册仪式隐私了解详细信息。
在上述过程中,用户代理应向用户展示一些UI,以指导他们选择和授权认证器的过程。
5.1.4.
使用现有凭证进行断言 - PublicKeyCredential 的
[[Get]](options)
方法
WebAuthn
依赖方调用
navigator.credentials.get({publicKey:..., ...})
来发现并使用现有的 公钥凭证,需要获得用户的同意。依赖方脚本可以选择指定一些
条件,指明哪些凭证来源是可接受的。客户端平台
定位符合指定条件的凭证来源,并引导
用户选择一个脚本允许使用的凭证。即使存在凭证来源,用户也可能选择拒绝整个交互,例如为了保护隐私。
如果用户选择了一个凭证来源,则用户代理会使用 § 6.3.3
认证器GetAssertion操作来签署由依赖方提供的挑战和其他收集的数据,将其作为一个凭证使用。
get()
实现 [CREDENTIAL-MANAGEMENT-1] 调用
PublicKeyCredential.
来收集任何凭证,这些凭证应在不需要用户干预的情况下可用(大致相当于本规范的授权手势),如果未找到
符合条件的凭证,则会调用
[[CollectFromCredentialStore]]()
PublicKeyCredential.
让
用户选择一个凭证来源。
[[DiscoverFromExternalSource]]()
由于本规范要求在创建任何授权手势时需要进行凭证创建,
PublicKeyCredential.
内部方法继承了
默认行为 [[CollectFromCredentialStore]](origin, options, sameOriginWithAncestors)
Credential.[[CollectFromCredentialStore]]()
,
返回一个空集合。
此 navigator.credentials.get()
操作可以通过使用 AbortController
中止;
详见 DOM §3.3 使用
AbortController 和 AbortSignal 对象在 API 中的集成 以获取详细说明。
5.1.4.1. PublicKeyCredential 的
[[DiscoverFromExternalSource]](origin, options, sameOriginWithAncestors)
方法
[[DiscoverFromExternalSource]](origin, options, sameOriginWithAncestors)
这个 内部方法接受三个参数:
origin
-
这个参数是相关设置对象的origin,由调用的
get()
实现决定,即CredentialsContainer
的 请求Credential
抽象操作。 options
-
这个参数是一个
CredentialRequestOptions
对象,其中options.
成员包含一个publicKey
PublicKeyCredentialRequestOptions
对象,指定要发现的 公钥凭证的期望属性。 sameOriginWithAncestors
-
这个参数是一个布尔值,当且仅当调用者的环境设置对象与其祖先同源时,它为
true
。如果调用者是跨源的,则它为false
。注意: 调用这个 内部方法 表明它已被权限策略允许,该策略在 [CREDENTIAL-MANAGEMENT-1] 级别进行评估。 参见§ 5.9 权限策略集成。
注意: 该算法是同步的: Promise
的解决/拒绝由navigator.credentials.get()
处理。
注意: 在此算法中使用的所有 BufferSource
对象必须在算法开始时进行快照,以避免潜在的同步问题。算法实现应获取缓冲区源所持有的字节的副本并在算法的相关部分使用该副本。
调用此方法时,用户代理必须执行以下算法:
-
断言:
options.
已存在。publicKey
-
令 options 为
options.
的值。publicKey
-
如果
timeout
成员出现在 options 中,检查其值是否在由 客户端定义的合理范围内,如果不在该范围内,将其校正为位于该范围内的最接近值。 将计时器 lifetimeTimer 设置为此调整后的值。如果timeout
成员未出现在 options 中,则将 lifetimeTimer 设置为 客户端特定的默认值。timeout
成员的推荐范围和默认值如下。 如果options.
userVerification
- 设置为
discouraged
-
推荐范围:30000 毫秒到 180000 毫秒。
推荐默认值:120000 毫秒(2 分钟)。
- 设置为
required
或preferred
-
推荐范围:30000 毫秒到 600000 毫秒。
推荐默认值:300000 毫秒(5 分钟)。
注意: 用户代理应考虑认知指南,针对有特殊需求的用户设置超时时间。
- 设置为
-
令 callerOrigin 为
origin
。 如果 callerOrigin 是一个不透明的 origin,则返回DOMException
, 其名称为 "NotAllowedError
", 并终止此算法。 -
令 effectiveDomain 为 callerOrigin 的 有效域。 如果 有效域 不是一个有效域,则返回
DOMException
,其名称为 "SecurityError
" 并终止此算法。注意: 有效域可能解析为一个host,它可以通过各种方式表示,如 域、ipv4 地址、ipv6 地址、不透明的 host、 或空的 host。 这里只允许 域 格式的 host。 这是为了简化操作,并且也认识到使用基于 PKI 的安全性与直接 IP 地址识别的各种问题。
-
如果 options.
rpId
未出现,则将 rpId 设置为 effectiveDomain。否则:
-
如果 options.
rpId
不是 effectiveDomain 的可注册域后缀或与其相等,则返回DOMException
, 其名称为 "SecurityError
", 并终止此算法。 -
将 rpId 设置为 options.
rpId
的值。注意: rpId 表示调用者的 RP ID。RP ID 默认是调用者的 origin 的有效域,除非调用者在调用
get()
时显式设置了 options.rpId
。
-
-
令 clientExtensions 为一个新的 映射,并且 令 authenticatorExtensions 为一个新的 映射。
-
如果
extensions
成员出现在 options 中,则为每个 extensionId → clientExtensionInput 的options.
:extensions
-
令 collectedClientData 为一个新的
CollectedClientData
实例,其字段如下:type
-
字符串 "webauthn.get"。
challenge
-
base64url 编码 的 options.
challenge
origin
-
origin 的序列化 的值 callerOrigin。
crossOrigin
-
与传递给此 内部方法 的参数
sameOriginWithAncestors
的值相反。 tokenBinding
-
客户端与 callerOrigin 之间的 Token Binding 的状态,以及与 callerOrigin 关联的 Token Binding ID,如果存在的话。
-
令 clientDataJSON 为 客户端数据的 JSON 兼容序列化的表示形式 collectedClientData。
-
令 clientDataHash 为 序列化客户端数据的哈希值 clientDataJSON。
-
如果
options.
出现并且其aborted 标志被设置为signal
true
, 则返回DOMException
, 其名称为 "AbortError
", 并终止此算法。 -
令 issuedRequests 为一个新的有序集合。
-
令 savedCredentialIds 为一个新的 映射。
-
令 authenticators 表示一个值,该值在任何给定时间内都是一个集合,其中每个 客户端平台 特定句柄 项 在该时间点识别出当前可用的一个认证器。
注意: 什么资格可以让一个 认证器 被认为是“可用的”并没有具体说明;这旨在表示认证器可以通过各种机制热插拔(例如,通过 USB) 或被客户端发现(例如,通过 NFC 或 Bluetooth),或者永久内置于客户端中。
-
启动 lifetimeTimer。
-
当 lifetimeTimer 未过期时, 执行 以下操作,取决于 lifetimeTimer, 以及状态和响应 每个 authenticator 在 authenticators 中:
- 如果 lifetimeTimer 过期,
-
对每个 authenticator 在 issuedRequests 中调用 authenticatorCancel 操作并且移除 authenticator 从 issuedRequests 中。
- 如果用户执行用户代理用户界面选项以取消过程,
-
对每个 authenticator 在 issuedRequests 中调用 authenticatorCancel 操作并且移除 authenticator 从 issuedRequests 中。返回
DOMException
,其名称为 "NotAllowedError
"。 - 如果
signal
成员存在并且 aborted 标志 设置为true
, -
对每个 authenticator 在 issuedRequests 中调用 authenticatorCancel 操作并且移除 authenticator 从 issuedRequests 中。然后 返回
DOMException
, 其名称为 "AbortError
", 并终止此算法。 - 如果 issuedRequests 为空,
options.
不为空,并且没有 authenticator 会变得可用用于其中的任何 公钥凭证,allowCredentials
-
向用户表明没有找到符合条件的凭证。当用户确认对话框后,返回
DOMException
, 其名称为 "NotAllowedError
"。注意: 一个客户端平台可以确定没有 authenticator 会变得可用的一种方法是检查当前的
成员 的transports
项PublicKeyCredentialDescriptor
options.
, 如果有的话。例如,如果所有allowCredentials
项 仅列出PublicKeyCredentialDescriptor
, 但是所有平台 authenticator 都已经尝试过,那么就没有可能满足请求。或者, 所有internal
项 可能列出PublicKeyCredentialDescriptor
, 而客户端平台不支持这些 transports。transports
- 如果 authenticator 变得在此客户端设备上可用,
-
注意: 这包括 authenticator 在 lifetimeTimer 启动时已可用的情况。
-
如果
options.
设置为userVerification
required
并且 authenticator 无法执行 用户验证,继续。 -
令 userVerification 为 有效用户验证要求,一个布尔值,如下所示。如果
options.
userVerification
- 设置为
required
-
令 userVerification 为
true
。 - 设置为
preferred
-
如果 authenticator
- 设置为
discouraged
-
令 userVerification 为
false
。
- 设置为
-
如果
options.
allowCredentials
- 不为空
-
-
令 allowCredentialDescriptorList 为一个新的 列表。
-
执行一个客户端平台特定 过程,确定是否存在匹配 rpId、
options.
、allowCredentials
options.
和id
options.
的 公钥凭证。 将 allowCredentialDescriptorList 设置为此过滤后的列表。type
-
令 distinctTransports 为一个新的 有序集合。
-
如果 allowCredentialDescriptorList 只有一个值,将
savedCredentialIds[authenticator]
设置为allowCredentialDescriptorList[0].id
的值(参见 此处 在 § 6.3.3 认证器获取断言操作 了解更多信息)。 -
对于每个 凭证描述符 C 在 allowCredentialDescriptorList 中,附加 每个值(如果有) 到 distinctTransports。
注意: 这将聚合 distinctTransports 中仅限的
transports
值 (对于此 认证器)由于有序集合的属性。 -
如果 distinctTransports
- 不为空
-
客户端从 distinctTransports 中选择一个 transport 值,可能会结合本地 配置知识以选择适合于与 authenticator 配合使用的 传输。
然后,使用 transport,调用 authenticatorGetAssertion 操作在 authenticator 上,带有 rpId、clientDataHash、 allowCredentialDescriptorList、 userVerification 和 authenticatorExtensions 作为参数。
- 为空
-
使用本地配置知识以选择适合于与 authenticator 配合使用的 传输,调用 authenticatorGetAssertion 操作在 authenticator 上带有 rpId、clientDataHash、allowCredentialDescriptorList、 userVerification 和 authenticatorExtensions 作为参数。
-
- 为空
-
使用本地配置知识选择适合于与 authenticator 配合使用的传输,调用 authenticatorGetAssertion 操作在 authenticator 上,带有 rpId、 clientDataHash、userVerification 和 authenticatorExtensions 作为参数。
注意: 在这种情况下,依赖方 未提供可接受的凭证描述符列表。因此,认证器被要求行使任何 凭证它可能 拥有 在 rpId 下标识的依赖方范围内。
-
附加 authenticator 到 issuedRequests。
-
- 如果 authenticator 不再在此客户端设备上可用,
-
移除 authenticator 从 issuedRequests 中。
- 如果任何 authenticator 返回一个状态,表示用户取消了操作,
-
-
移除 authenticator 从 issuedRequests 中。
-
对每个 剩余 authenticator 在 issuedRequests 中调用 authenticatorCancel 操作 并且 移除它从 issuedRequests 中。
注意: 认证器 可能 返回表示“用户取消了整个操作”的状态。 用户代理如何将此状态表现给用户未做具体说明。
-
- 如果任何 authenticator 返回错误状态,
-
移除 authenticator 从 issuedRequests 中。
- 如果任何 authenticator 指示成功,
-
-
移除 authenticator 从 issuedRequests 中。
-
令 assertionCreationData 为一个 结构 ,其 项 如下所示:
-
credentialIdResult
-
如果
savedCredentialIds[authenticator]
存在,将credentialIdResult 的值设置为savedCredentialIds[authenticator]
的字节数。 否则,将credentialIdResult 的值设置为从成功返回的 凭证 ID 的字节数authenticatorGetAssertion操作,在 § 6.3.3 认证器获取断言操作中定义的。 -
clientDataJSONResult
-
其值为 clientDataJSON 的字节数。
-
authenticatorDataResult
-
signatureResult
-
其值为 认证器 返回的签名值的字节数。
-
userHandleResult
-
如果认证器 返回了一个用户句柄,将 userHandleResult 的值设置为 返回的 用户句柄 的字节数。否则,将 userHandleResult 的值设置为 null。
-
clientExtensionResults
-
其值为一个
AuthenticationExtensionsClientOutputs
对象,包含 扩展标识符 → 客户端扩展输出 条目。条目是通过运行每个扩展的客户端扩展处理 算法创建的 客户端扩展输出, 对于 客户端扩展 中的每个options.
。extensions
-
-
令 constructAssertionAlg 为一个算法,它接收一个全局对象 global,其步骤如下:
-
令 pubKeyCred 为一个新的
PublicKeyCredential
对象,与 global 关联,其字段如下:[[identifier]]
-
一个新的
ArrayBuffer
,使用 global 的 %ArrayBuffer% 创建,包含assertionCreationData.credentialIdResult
的字节数。 response
-
一个新的
AuthenticatorAssertionResponse
对象,与 global 关联,其字段如下:clientDataJSON
-
一个新的
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。
-
-
对每个 剩余 authenticator 在 issuedRequests 中调用 authenticatorCancel 操作 并且 移除它从 issuedRequests 中。
-
返回 constructAssertionAlg 并终止此算法。
-
-
返回
DOMException
, 其名称为 "NotAllowedError
"。 为了防止泄露可能在未经用户同意的情况下识别用户的信息,此步骤不得在 lifetimeTimer 到期之前执行。有关详细信息,请参见 § 14.5.2 认证隐私。
在上述过程中,用户代理应向用户显示一些 UI,以指导他们完成选择和授权一个认证器以完成操作的过程。
5.1.5.
存储现有凭证 - PublicKeyCredential 的
[[Store]](credential, sameOriginWithAncestors)
方法
[[Store]](credential, sameOriginWithAncestors)
方法不支持 Web 身份验证的 PublicKeyCredential
类型,因此它总是返回一个错误。
注意: 该算法是同步的;Promise
的解决/拒绝由 navigator.credentials.store()
处理。
这个内部方法接受两个参数:
credential
-
此参数是一个
PublicKeyCredential
对象。 sameOriginWithAncestors
-
此参数是一个布尔值,当且仅当调用者的环境设置对象与其祖先具有相同的源时,该值为
true
。
当调用此方法时,用户代理必须执行以下算法:
-
返回一个
DOMException
, 其名称为 "NotSupportedError
", 并终止此算法
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
注意: 从一个 浏览上下文 中调用此方法,而该上下文中的 Web 身份验证 API
根据 允许使用 算法被“禁用”,即通过权限策略,将导致 promise 被拒绝,并抛出 DOMException
,
其名称为 "NotAllowedError
"。
另见 § 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 Mobile无
AuthenticatorAttestationResponse
接口表示 认证器 对客户端请求创建新 公钥凭证
的响应。它包含有关新凭证的信息,可用于
以后识别它,以及 WebAuthn 依赖方 在注册过程中用来评估凭证特征的元数据。
AuthenticatorAttestationResponse/getTransports
在无当前引擎中可用。
Opera无Edge无
Edge (旧版)无IE无
Firefox for Android无iOS Safari无Chrome for Android无Android WebView无Samsung Internet无Opera Mobile无
[SecureContext ,Exposed =Window ]interface AuthenticatorAttestationResponse :AuthenticatorResponse { [SameObject ]readonly attribute ArrayBuffer attestationObject ;sequence <DOMString >();
getTransports ArrayBuffer ();
getAuthenticatorData ArrayBuffer ?();
getPublicKey COSEAlgorithmIdentifier (); };
getPublicKeyAlgorithm
clientDataJSON
-
此属性继承自
AuthenticatorResponse
, 包含 JSON兼容的客户端数据序列化(参见 § 6.5 认证), 这些数据由客户端传递给认证器以生成该凭证。必须保留确切的 JSON 序列化,因为已经计算了 序列化客户端数据的哈希值。 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) 格式中,
在 credentialPublicKey 成员中,
位于 attestedCredentialData 内,
位于 认证器数据 内,
位于 认证对象 内,由 AuthenticatorAttestationResponse
的 attestationObject
传递。
希望使用 认证 的 依赖方 必须解析 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
在所有当前的引擎中。
OperaNoneEdge79+
Edge (Legacy)18IENone
Firefox for Android60+iOS Safari13.3+Chrome for Android70+Android WebView70+Samsung InternetNoneOpera MobileNone
AuthenticatorAssertionResponse
接口表示 认证器 对客户端请求生成新的 认证断言
时的响应,给出 WebAuthn 依赖方 的
挑战和可选的已知凭证列表。此响应包含证明持有 凭证私钥 的加密签名,
以及可选的用户同意特定交易的证据。
[SecureContext ,Exposed =Window ]interface AuthenticatorAssertionResponse :AuthenticatorResponse { [SameObject ]readonly attribute ArrayBuffer authenticatorData ; [SameObject ]readonly attribute ArrayBuffer signature ; [SameObject ]readonly attribute ArrayBuffer ?userHandle ; };
clientDataJSON
-
从
AuthenticatorResponse
继承的该属性包含传递给认证器以生成该断言的 与 JSON 兼容的客户端数据序列化(见 § 5.8.1 用于 WebAuthn 签名的客户端数据(词典 CollectedClientData))。 必须保留精确的 JSON 序列化格式,因为已经计算了 已序列化客户端数据的哈希值。 -
AuthenticatorAssertionResponse/authenticatorData
在所有当前的引擎中。
Firefox60+Safari13+Chrome67+
OperaNoneEdge79+
Edge (Legacy)18IENone
Firefox for Android60+iOS Safari13.3+Chrome for Android70+Android WebView70+Samsung InternetNoneOpera MobileNoneauthenticatorData
, 类型为 ArrayBuffer,只读 -
该属性包含由认证器返回的 认证器数据。参见 § 6.1 认证器数据。
-
AuthenticatorAssertionResponse/signature
在所有当前的引擎中。
Firefox60+Safari13+Chrome67+
OperaNoneEdge79+
Edge (Legacy)18IENone
Firefox for Android60+iOS Safari13.3+Chrome for Android70+Android WebView70+Samsung InternetNoneOpera MobileNonesignature
, 类型为 ArrayBuffer,只读 -
该属性包含由认证器返回的原始签名。参见 § 6.3.3 认证器获取断言操作。
-
AuthenticatorAssertionResponse/userHandle
在所有当前的引擎中。
Firefox60+Safari13+Chrome67+
OperaNoneEdge79+
Edge (Legacy)18IENone
Firefox for Android60+iOS Safari13.3+Chrome for Android70+Android WebView70+Samsung InternetNoneOpera MobileNoneuserHandle
, 类型为 ArrayBuffer,只读,可为空 -
该属性包含由认证器返回的 用户句柄,如果认证器未返回 用户句柄,则为 null。参见 § 6.3.3 认证器获取断言操作。
5.3.
凭证生成参数 (字典 PublicKeyCredentialParameters
)
dictionary PublicKeyCredentialParameters {required DOMString type ;required COSEAlgorithmIdentifier alg ; };
type
, 类型为 DOMString-
该成员指定要创建的凭证类型。值应为
PublicKeyCredentialType
的成员,但 客户端平台必须忽略未知的值,忽略任何具有未知PublicKeyCredentialParameters
的type
。 alg
, 类型为 COSEAlgorithmIdentifier-
该成员指定新生成凭证将使用的加密签名算法,因此也指定了要生成的非对称密钥对的类型,例如 RSA 或椭圆曲线。
注意: 我们使用“alg”作为后一个成员名称,而不是拼出“algorithm”,因为它将被序列化为发给认证器的消息,这可能通过低带宽链接发送。
5.4.
凭证创建选项(字典 PublicKeyCredentialCreationOptions
)
PublicKeyCredentialCreationOptions
在所有当前引擎中。
Opera54+Edge79+
Edge (旧版)无IE无
Android 版 Firefox?iOS 版 Safari13.3+Android 版 Chrome67+Android WebView无三星互联网无Opera 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无
Android 版 Firefox?iOS Safari13.3+Android 版 Chrome67+Android WebView无三星 Internet无Opera Mobile48+rp
, 类型为 PublicKeyCredentialRpEntity -
此成员包含有关发出请求的 依赖方 的数据。
其值的
name
成员是必需的。有关详细信息,请参阅 § 5.4.1 公钥实体描述(字典 PublicKeyCredentialEntity)。其值的
id
成员指定了应将凭证 限定 为的 RP ID。如果省略, 其值将是CredentialsContainer
对象的 相关设置对象 的 来源 的 有效域。有关详细信息,请参阅 § 5.4.2 凭证生成的依赖方参数(字典 PublicKeyCredentialRpEntity)。 -
PublicKeyCredentialCreationOptions/user
在所有当前引擎中。
Firefox60+Safari13+Chrome67+
Opera54+Edge79+
Edge (旧版)无IE无
Android 版 Firefox?iOS Safari13.3+Android 版 Chrome67+Android WebView无三星 Internet无Opera Mobile48+user
, 类型 为 PublicKeyCredentialUserEntity -
此成员包含有关 依赖方 请求 的用户帐户的 数据。
其值的
name
、displayName
和id
成员是必需的。有关详细信息,请参阅 § 5.4.1 公钥实体描述(字典 PublicKeyCredentialEntity) 和 § 5.4.3 用户帐户凭证生成参数(字典 PublicKeyCredentialUserEntity)。 -
PublicKeyCredentialCreationOptions/challenge
在所有当前引擎中。
Firefox60+Safari13+Chrome67+
Opera54+Edge79+
Edge (旧版)无IE无
Android 版 Firefox?iOS Safari13.3+Android 版 Chrome67+Android WebView无三星 Internet无Opera Mobile48+challenge
, 类型为 BufferSource -
此成员包含用于生成新创建的凭证的 证明对象 的挑战。有关安全性注意事项,请参阅 § 13.4.3 加密挑战。
-
PublicKeyCredentialCreationOptions/pubKeyCredParams
在所有当前引擎中。
Firefox60+Safari13+Chrome67+
Opera54+Edge79+
Edge (旧版)无IE无
Android 版 Firefox?iOS Safari13.3+Android 版 Chrome67+Android WebView无三星 Internet无Opera Mobile48+pubKeyCredParams
, 类型为 sequence<PublicKeyCredentialParameters> -
此成员包含有关要创建的凭证所需属性的信息。序列按优先顺序排列,从最优先到最不优先。客户端 会尽力创建它所能创建的最优先凭证。
-
PublicKeyCredentialCreationOptions/timeout
在所有当前引擎中。
Firefox60+Safari13+Chrome67+
Opera54+Edge79+
Edge (旧版)无IE无
Android 版 Firefox?iOS Safari13.3+Android 版 Chrome67+Android WebView无三星 Internet无Opera Mobile48+timeout
, 类型为 unsigned long -
此成员指定调用者愿意等待调用完成的时间,以毫秒为单位。这被视为提示,可能会被 客户端 覆盖。
-
PublicKeyCredentialCreationOptions/excludeCredentials
在所有当前引擎中。
Firefox60+Safari13+Chrome67+
Opera54+Edge79+
Edge (旧版)无IE无
Android 版 Firefox?iOS Safari13.3+Android 版 Chrome67+Android WebView无三星 Internet无Opera Mobile48+excludeCredentials
, 类型为 sequence<PublicKeyCredentialDescriptor>,默认为[]
-
此成员供希望限制在单个验证器上为同一帐户创建多个凭证的 依赖方 使用。如果新凭证将在已包含此参数中列出的凭证之一的验证器上创建,客户端 被请求返回错误。
-
PublicKeyCredentialCreationOptions/authenticatorSelection
在所有当前引擎中。
Firefox60+Safari13+Chrome67+
Opera54+Edge79+
Edge (旧版)无IE无
Android 版 Firefox?iOS Safari13.3+Android 版 Chrome67+Android WebView无三星 Internet无Opera Mobile48+authenticatorSelection
, 类型为 AuthenticatorSelectionCriteria -
PublicKeyCredentialCreationOptions/attestation
在所有当前引擎中。
Firefox60+Safari13+Chrome67+
Opera54+Edge79+
Edge (旧版)无IE无
Android 版 Firefox?iOS Safari13.3+Android 版 Chrome67+Android WebView无三星 Internet无Opera Mobile48+attestation
, 类型为 DOMString,默认为"none"
-
此成员供希望表达其对 证明传输 的偏好的 依赖方 使用。其值应为
AttestationConveyancePreference
的成员。客户端平台 必须忽略未知值,将未知值视为 成员不存在。 其默认值为 "none"。 extensions
, 类型为 AuthenticationExtensionsClientInputs-
此成员包含请求客户端和验证器执行额外处理的附加参数。例如,调用者可以请求仅使用具有某些能力的验证器来创建凭证,或请求在 证明对象 中返回特定信息。一些扩展定义在 § 9 WebAuthn 扩展 中;有关最新注册 WebAuthn 扩展 的列表,请参阅由 [RFC8809] 建立的 IANA "WebAuthn 扩展标识符" 注册表 [IANA-WebAuthn-Registries]。
5.4.1.
公钥实体描述 (字典 PublicKeyCredentialEntity
)
字典 PublicKeyCredentialEntity
描述了与 公钥凭证
相关联的用户帐户或 WebAuthn 依赖方。
dictionary PublicKeyCredentialEntity {required DOMString name ; };
name
, 类型为 DOMString-
该实体的 可读性良好的 名称。其功能取决于
PublicKeyCredentialEntity
所代表的内容:-
当继承自
PublicKeyCredentialRpEntity
时,它是用于显示的 可读性良好的 依赖方标识符。例如,“ACME Corporation”、“Wonderful Widgets, Inc.”或“ОАО Примертех”。-
依赖方 在设置
name
的值或向用户显示值时,应按照 [RFC8266] 的第 2.3 节中对 PRECIS FreeformClass 的昵称配置文件规定的要求执行。 -
该字符串可以包含语言和方向元数据。依赖方 应考虑提供此信息。有关如何编码此元数据的详细信息,请参阅 § 6.4.2 语言和方向编码。
-
客户端 在向用户显示值之前,或在作为 authenticatorMakeCredential 操作的参数包含值之前,应按照 [RFC8266] 的第 2.3 节对 PRECIS FreeformClass 的昵称配置文件规定的要求执行。
-
-
当继承自
PublicKeyCredentialUserEntity
时,它是用户帐户的 可读性良好的 标识符。它仅用于显示,帮助用户区分具有类似displayName
的用户帐户。 例如,“alexm”、“alex.mueller@example.com”或“+14255551234”。-
依赖方 可以允许用户选择该值。依赖方 在设置
name
的值或向用户显示值时,应按照 [RFC8265] 的第 3.4.3 节中对 PRECIS IdentifierClass 的 UsernameCasePreserved 配置文件规定的要求执行。 -
该字符串可以包含语言和方向元数据。依赖方 应考虑提供此信息。有关如何编码此元数据的详细信息,请参阅 § 6.4.2 语言和方向编码。
-
客户端 在向用户显示值之前,或在作为 authenticatorMakeCredential 操作的参数包含值之前,应按照 [RFC8265] 的第 3.4.3 节对 PRECIS IdentifierClass 的 UsernameCasePreserved 配置文件规定的要求执行。
-
当 客户端、客户端平台 或 验证器 显示
name
的值时,应始终使用 UI 元素提供明确的边界,并且不要允许溢出到其他元素 [css-overflow-3]。验证器可以截断
name
成员的值,以便在验证器存储值时将其限制在 64 字节内。有关截断及其他注意事项的详细信息,请参阅 § 6.4.1 字符串截断。 -
5.4.2.
依赖方凭证生成参数 (字典 PublicKeyCredentialRpEntity
)
字典 PublicKeyCredentialRpEntity
用于在创建新凭证时提供额外的 依赖方 属性。
dictionary PublicKeyCredentialRpEntity :PublicKeyCredentialEntity {DOMString id ; };
5.4.3.
用户帐户凭证生成参数 (字典 PublicKeyCredentialUserEntity
)
字典 PublicKeyCredentialUserEntity
用于在创建新凭证时提供额外的用户帐户属性。
dictionary PublicKeyCredentialUserEntity :PublicKeyCredentialEntity {required BufferSource id ;required DOMString displayName ; };
id
, 类型为 BufferSource-
用户帐户实体的 用户句柄。用户句柄 是一个不透明的 字节序列,最大长度为 64 字节,不应向用户显示。
为了确保安全操作,认证和授权决策必须基于该
id
成员,而不是基于displayName
或name
成员。参见 [RFC8266] 的第 6.1 节。用户句柄不得包含有关用户的个人身份信息,例如用户名或电子邮件地址;详见 § 14.6.1 用户句柄内容。用户句柄不得为空,尽管它可以为 null。
注意:用户句柄 不应 在不同帐户之间是常量值,即使对于 不可发现的凭证 也是如此,因为某些验证器始终创建 可发现的凭证。因此,常量用户句柄将阻止用户在同一 依赖方 上使用这样的验证器与多个帐户。
displayName
, 类型为 DOMString-
用户帐户的 易理解 名称,仅用于显示。例如,“Alex Müller” 或 “田中倫”。依赖方 应允许用户选择此名称,并且不应限制选择超过必要范围。
-
依赖方 应进行强制检查,按照 [RFC8266] 的第 2.3 节规定的 Nickname Profile of the PRECIS FreeformClass [RFC8264],在设置
displayName
的值时,或在显示该值给用户时。 -
此字符串可以包含语言和方向元数据。依赖方 应考虑提供此信息。关于此元数据如何编码,请参见 § 6.4.2 语言和方向编码。
-
客户端 应进行强制检查,按照 [RFC8266] 的第 2.3 节规定的 Nickname Profile of the PRECIS FreeformClass [RFC8264], 在显示
displayName
值给用户之前,或在 authenticatorMakeCredential 操作的参数中包含该值之前进行检查。
当 客户端,客户端平台,或 验证器 显示
displayName
的值时,应该始终使用 UI 元素提供明确的边界,并且不要允许溢出到其他元素 [css-overflow-3]。验证器 必须接受并存储至少 64 字节长度的
displayName
成员值。验证器可以截断displayName
成员值,使其适应 64 字节的长度。关于截断及其他注意事项的详细信息,请参阅 § 6.4.1 字符串截断。 -
5.4.4.
认证器选择标准 (字典 AuthenticatorSelectionCriteria
)
WebAuthn
依赖方 可以使用字典 AuthenticatorSelectionCriteria
指定他们对认证器属性的要求。
dictionary AuthenticatorSelectionCriteria {DOMString authenticatorAttachment ;DOMString residentKey ;boolean requireResidentKey =false ;DOMString userVerification = "preferred"; };
authenticatorAttachment
, 类型为 DOMString-
如果存在此成员,则仅筛选具有指定 § 5.4.5 认证器附件枚举 (enum AuthenticatorAttachment) 的认证器。值应为
AuthenticatorAttachment
的成员,但 客户端平台 必须忽略未知值,并将未知值视为该 成员不存在。 residentKey
, 类型为 DOMString-
指定依赖方在创建 客户端可发现的凭证 时的要求。由于历史原因,命名保留了已弃用的“resident”术语。值应为
ResidentKeyRequirement
的成员,但 客户端平台 必须忽略未知值,并将未知值视为该 成员不存在。如果未给出值,则当requireResidentKey
为true
时,其有效值为required
,如果为false
或不存在,其有效值为discouraged
。参见
ResidentKeyRequirement
了解residentKey
的值和语义的描述。 requireResidentKey
, 类型为 boolean,默认值为false
-
此成员保留用于与 WebAuthn 第 1 级的向后兼容,并且由于历史原因,其命名保留了已弃用的“resident”术语以指代 可发现的凭证。依赖方 应该仅在
residentKey
设置为required
时,才将其设置为true
。 userVerification
, 类型为 DOMString,默认值为"preferred"
-
此成员描述依赖方对于
create()
操作的 用户验证 要求。仅筛选能够满足此要求的认证器。值应为UserVerificationRequirement
的成员,但 客户端平台 必须忽略未知值,并将未知值视为该 成员不存在。
5.4.5. 认证器附件枚举 (枚举 AuthenticatorAttachment
)
此枚举的值描述了认证器的附件模式。依赖方在调用navigator.credentials.create()
创建凭证时,使用它来表示首选的认证器附件模式。
enum AuthenticatorAttachment {"platform" ,"cross-platform" };
注意: AuthenticatorAttachment
枚举被故意忽略引用,请参见 § 2.1.1
枚举作为 DOMString 类型。
注意: 认证器附件模式选择选项仅在 [[Create]](origin, options,
sameOriginWithAncestors)
操作中可用。依赖方可以使用它,例如,确保用户有一个 漫游凭证用于在其他 客户端设备上进行身份验证;或专门注册一个 平台凭证,以便在特定 客户端设备上更轻松地重新验证。[[DiscoverFromExternalSource]](origin, options, sameOriginWithAncestors)
操作没有认证器附件模式选择选项,因此依赖方应该接受用户注册的任何凭证。客户端和用户将使用当时可用且方便的凭证。
5.4.6.
常驻密钥要求枚举 (枚举 ResidentKeyRequirement
)
enum ResidentKeyRequirement {"discouraged" ,"preferred" ,"required" };
注意: ResidentKeyRequirement
枚举被故意忽略引用,请参见 § 2.1.1
枚举作为 DOMString 类型。
此枚举的值描述了依赖方对于客户端可发现的凭证(以前称为常驻凭证或常驻密钥)的要求:
注意: 依赖方可以通过检查凭证属性扩展的返回值,结合提供的值
options.
,了解认证器是否创建了客户端可发现的凭证。当authenticatorSelection
.residentKey
discouraged
或preferred
用于options.
时,这很有用,因为在这些情况下,认证器可能会创建客户端可发现的凭证或服务器端凭证中的任意一个。
authenticatorSelection
.residentKey
5.4.7.
证明传递偏好枚举 (枚举 AttestationConveyancePreference
)
WebAuthn
依赖方可以使用AttestationConveyancePreference
来指定其在凭证生成过程中关于证明传递的偏好。
enum AttestationConveyancePreference {"none" ,"indirect" ,"direct" ,"enterprise" };
注意: AttestationConveyancePreference
枚举被故意忽略引用,请参见 § 2.1.1 枚举作为 DOMString 类型。
none
-
此值表示依赖方对认证器证明不感兴趣。例如,为了可能避免获得用户同意以将识别信息转发给依赖方,或节省与证明 CA或匿名化 CA之间的往返通信。
这是默认值。
indirect
-
此值表示依赖方倾向于获得可验证的证明传递,但允许客户端决定如何获取此类证明声明。客户端可以用匿名化 CA生成的证明声明替换认证器生成的证明声明,以保护用户隐私,或帮助依赖方在异构生态系统中进行证明验证。
direct
enterprise
-
此值表示依赖方希望接收到可能包含唯一识别信息的证明声明。这适用于企业内部的受控部署,组织希望将注册与特定的认证器绑定。用户代理不得提供此类证明,除非用户代理或认证器配置允许为请求的RP ID提供此类证明。
5.5.
断言生成选项 (字典 PublicKeyCredentialRequestOptions
)
PublicKeyCredentialRequestOptions
在所有当前引擎中。
Opera54+Edge79+
Edge (旧版)无IE无
Firefox for Android?iOS Safari13.3+Chrome for Android67+Android WebView67+三星 Internet无Opera 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+三星 Internet无Opera Mobile48+challenge
, 类型 BufferSource -
此成员表示选定的认证器在生成 身份验证断言时签名的挑战及其他数据。请参见 § 13.4.3 加密挑战 的安全考量。
-
PublicKeyCredentialRequestOptions/timeout
在所有当前引擎中。
Firefox60+Safari13+Chrome67+
Opera54+Edge79+
Edge (旧版)无IE无
Firefox for Android?iOS Safari13.3+Chrome for Android67+Android WebView67+三星 Internet无Opera Mobile48+timeout
, 类型 unsigned long -
此可选成员指定调用完成所愿等待的时间(以毫秒为单位)。该值被视为提示,且可能会被客户端覆盖。
-
PublicKeyCredentialRequestOptions/rpId
在所有当前引擎中。
Firefox60+Safari13+Chrome67+
Opera54+Edge79+
Edge (旧版)无IE无
Firefox for Android?iOS Safari13.3+Chrome for Android67+Android WebView67+三星 Internet无Opera Mobile48+rpId
, 类型 USVString -
此可选成员指定调用方声称的依赖方标识符。如果省略,其值将为
CredentialsContainer
对象的相关设置对象的来源的有效域。 -
PublicKeyCredentialRequestOptions/allowCredentials
在所有当前引擎中。
Firefox60+Safari13+Chrome67+
Opera54+Edge79+
Edge (旧版)无IE无
Firefox for Android?iOS Safari13.3+Chrome for Android67+Android WebView67+三星 Internet无Opera 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+三星 Internet无Opera Mobile48+userVerification
, 类型 DOMString, 默认值为"preferred"
-
此可选成员描述依赖方对用户验证的要求, 用于
get()
操作。该值应为UserVerificationRequirement
的成员, 但客户端平台必须忽略未知值,将未知值视为该成员不存在。只会过滤符合该要求的认证器。 -
PublicKeyCredentialCreationOptions/extensions
在所有当前引擎中。
Firefox60+Safari13+Chrome67+
Opera54+Edge79+
Edge (旧版)无IE无
Firefox for Android?iOS Safari13.3+Chrome for Android67+Android WebView67+三星 Internet无Opera Mobile48+PublicKeyCredentialRequestOptions/extensions
在所有当前引擎中。
Firefox60+Safari13+Chrome67+
Opera54+Edge79+
Edge (旧版)无IE无
Firefox for Android?iOS Safari13.3+Chrome for Android67+Android WebView67+三星 Internet无Opera Mobile48+extensions
, 类型 AuthenticationExtensionsClientInputs -
此可选成员包含请求客户端和认证器进行额外处理的额外参数。例如,如果需要从用户那里获得交易确认,则提示字符串可能包含在扩展中。
5.6. 使用 AbortSignal
中止操作
鼓励开发者利用 AbortController
来管理 [[Create]](origin, options, sameOriginWithAncestors)
和 [[DiscoverFromExternalSource]](origin, options, sameOriginWithAncestors)
操作。
详细说明请参见 DOM §3.3 使用
AbortController 和 AbortSignal 对象在API中部分。
注意: DOM §3.3 使用 AbortController 和
AbortSignal 对象在API中部分规定,集成了 AbortController
的 Web 平台 API 一旦设置了中止标志,必须立即拒绝 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) 方法中,在 认证器会话开始前检查,
最后在 认证器会话期间检查。对于 [[DiscoverFromExternalSource]](origin, options, sameOriginWithAncestors)
方法来说,也是如此。
可见性和焦点状态决定了窗口对象是否应该继续 [[Create]](origin, options, sameOriginWithAncestors)
和 [[DiscoverFromExternalSource]](origin, options, sameOriginWithAncestors)
操作。当与该窗口对象关联的[文档]失去焦点时,
[[Create]](origin, options, sameOriginWithAncestors)
和 [[DiscoverFromExternalSource]](origin, options, sameOriginWithAncestors)
操作应被中止。
WHATWG HTML 工作组正在讨论是否在浏览上下文获得或失去焦点时提供一个钩子。 如果提供了钩子,上述段落将会被更新以包括该钩子。 更多详情参见 WHATWG HTML 工作组问题 #2711。
5.7. WebAuthn 扩展输入和输出
下面的小节定义了用于传递 WebAuthn 扩展输入和输出的数据类型。
注意:认证器扩展输出作为认证器数据的一部分传递 (参见表 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 扩展请求参数中描述添加成员。
5.7.4. 认证扩展认证器输出
(CDDL 类型 AuthenticationExtensionsAuthenticatorOutputs
)
AuthenticationExtensionsAuthenticatorOutputs = { * $$extensionOutput .within ( tstr => any ) }
CDDL 类型
AuthenticationExtensionsAuthenticatorOutputs
定义了一个 CBOR 映射
,包含零个或多个认证器扩展输出值,用于 WebAuthn 扩展。
扩展可以按§ 9.3 扩展请求参数中描述添加成员。
5.8. 支持的数据结构
公钥凭证类型使用某些在支持规范中定义的数据结构。如下所示。
5.8.1.
WebAuthn 签名中使用的客户端数据(字典 CollectedClientData
)
客户端数据表示 WebAuthn 依赖方和客户端的上下文绑定。这是一个键值对映射,其中键为字符串。值可以是任何在 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-
此成员包含依赖方提供的挑战的 base64url 编码。见§ 13.4.3 加密挑战安全注意事项。
origin
, 类型 DOMStringcrossOrigin
, 类型 boolean-
此成员包含传递给内部方法的
sameOriginWithAncestors
参数值的反值。 tokenBinding
, 类型 TokenBinding-
此可选成员包含关于与依赖方通信时使用的令牌绑定协议[TokenBinding]状态的信息。它的缺失表示客户端不支持令牌绑定。
status
, 类型 DOMString-
此成员应该是
TokenBindingStatus
的成员,但客户端平台必须忽略未知的值,将未知的值视为tokenBinding
成员不存在。已知时,此成员是以下之一:注意:
TokenBindingStatus
枚举故意不被引用,见§ 2.1.1 枚举作为 DOMString 类型。 id
, 类型 DOMString-
如果
status
为present
,则此成员必须存在,并且必须是使用与依赖方通信时使用的令牌绑定 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,然后追加四个小写的十六进制数字,这些数字表示该代码点的基数为16的数字。
-
将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长至少一个字节,则验证失败。
-
如果clientDataJSON在与expected长度相等的偏移处的字节:
- 是0x7d
-
验证成功。
- 是0x2c
-
验证成功。
- 否则
-
验证失败。
5.8.1.3. 未来开发
为了与有限验证算法保持兼容,未来版本的规范不得删除type
、
challenge
、
origin
或crossOrigin
字段从CollectedClientData
中。
规范也不得更改序列化算法中这些字段的序列化顺序。
如果向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
, 类型为 BufferSource-
此成员包含调用者所指的 凭证 ID。
transports
, 类型为 sequence<DOMString>-
此可选成员包含客户端与管理 身份验证器 进行通信的提示信息。该值应为
AuthenticatorTransport
枚举的成员,但 客户端平台 必须忽略未知值。getTransports()
操作可以为此成员提供合适的值。在注册新凭证时, 依赖方 应该存储从getTransports()
返回的值。当为该凭证创建PublicKeyCredentialDescriptor
时, 依赖方 应该检索存储的值并将其设置为transports
成员的值。
5.8.4. 认证器传输枚举 (枚举 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.
用户验证要求枚举 (枚举 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]
一个文档
的
权限策略决定了该文档中的任何内容是否
允许成功调用Web 认证 API,
即通过navigator.credentials.get({publicKey:..., ...})
。
如果在任何文档中禁用了此功能,则该文档中的所有内容都将无法使用上述方法:尝试这样做将返回错误。
注意: 在 [CREDENTIAL-MANAGEMENT-1]中指定的算法执行实际的权限策略评估。这是因为当需要访问当前设置对象时,需要进行此类策略评估。[[Create]](origin, options, sameOriginWithAncestors)
和[[DiscoverFromExternalSource]](origin, options, sameOriginWithAncestors)
内部方法没有这样的访问权限,因为它们是
并行调用的(通过 [CREDENTIAL-MANAGEMENT-1]中指定的算法)。
5.10.
在iframe
元素中使用 Web 认证
Web
认证
API在跨域的iframe
中默认被禁用。
要覆盖此默认策略并指示允许跨域iframe
调用 Web 认证
API的[[DiscoverFromExternalSource]](origin, options, sameOriginWithAncestors)
方法,请在
allow
属性中指定
publickey-credentials-get
特征标识符令牌。
在嵌入上下文中使用 WebAuthn API 的依赖方应查看§ 13.4.2 嵌入式使用的可见性注意事项,了解关于UI 重定向及其可能的缓解措施。
6. WebAuthn 认证器模型
Web 认证 API隐含了一个针对WebAuthn 认证器的特定抽象功能模型。本节描述了该认证器模型。
客户端平台可以以任何方式实现并公开这个抽象模型。但是,当客户端的 Web 认证 API 实现在其支持的客户端平台上操作时,其行为必须与 § 5 Web 认证 API中指定的行为无异。
注意: [FIDO-CTAP] 是该模型的一个具体实例,但它与该规范中的数据有所不同。CTAP2 响应消息是使用整数键构建的 CBOR 映射,而不是该规范中定义的相同对象的字符串键。预期客户端会对这些数据进行必要的转换。[FIDO-CTAP] 规范在§6.2. Responses中详细说明了 CTAP2 整数键与 WebAuthn 字符串键之间的映射关系。
对于认证器,本模型定义了它们必须支持的逻辑操作,以及它们向客户端和WebAuthn 依赖方公开的数据格式。然而,它不定义认证器与客户端设备之间通信的细节,除非这些细节是与依赖方的互操作性所必需的。例如,该抽象模型不定义通过 USB 或 NFC 等传输协议连接认证器的协议。同样,该抽象模型也不定义特定的错误代码或返回它们的方法;然而,它确实定义了基于客户端需求的错误行为。因此,特定的错误代码被提及,作为显示哪些错误条件必须(或不必)从彼此区分的手段,以实现兼容且安全的客户端实现。
依赖方可以通过在创建凭据和/或生成声明时,使用凭据创建选项或声明生成选项来规定各种认证器特性,从而在需要时影响认证器的选择。WebAuthn API的底层算法会组织这些选项并将其传递给下文定义的适用认证器操作。
在该抽象模型中,认证器提供密钥管理和加密签名。它可以嵌入到 WebAuthn 客户端中,也可以完全封装在一个独立的设备中。认证器本身可以包含一个在安全级别上高于认证器其他部分的加密模块。这对嵌入在 WebAuthn 客户端中的认证器尤其重要,因为在这些情况下,该加密模块(例如 TPM)可能被认为比认证器的其他部分更可信。
每个认证器都存储一个 凭据映射,它是一个从 (rpId, [userHandle]) 到 公钥凭据源的映射。
此外,每个认证器都有一个 AAGUID,它是一个 128 位的标识符,用于指示认证器的类型(例如制造商和型号)。制造商必须选择 AAGUID,使其在同一制造商制造的所有本质上相同的认证器中保持相同,并且与所有其他类型的认证器的 AAGUID 不同(具有高概率)。给定类型的认证器的 AAGUID 应随机生成以确保这一点。依赖方可以使用其他来源的信息,通过 AAGUID 推断认证器的某些属性,例如认证级别和密钥保护的强度。
认证器的主要功能是提供与各种上下文数据绑定的 WebAuthn 签名。这些数据在签名请求从服务器传递到认证器的过程中,在堆栈的不同级别上被观察并添加。在验证签名时,服务器会将这些绑定与预期值进行检查。这些上下文绑定分为两部分:一部分由依赖方或客户端添加,称为客户端数据;另一部分由认证器添加,称为认证器数据。认证器对客户端数据进行签名,但除此之外对其内容不感兴趣。为了节省认证器的带宽和处理要求,客户端对客户端数据进行哈希,并仅将结果发送给认证器。认证器对客户端数据序列化后的哈希值与其自身的认证器数据的组合进行签名。
该设计的目标可以总结如下。
-
生成签名的方案应适应客户端设备和认证器之间的链接非常有限的情况,无论是带宽还是延迟。示例包括蓝牙低功耗和近场通信。
-
认证器处理的数据应小且易于在低级代码中解释。特别是,认证器不应解析诸如 JSON 之类的高级编码。
-
客户端和认证器都应具有根据需要添加上下文绑定的灵活性。
-
设计旨在尽可能多地重用现有的编码格式,以促进采纳和实施。
认证器生成的加密签名有两个不同的目的:
-
当通过 authenticatorMakeCredential 操作创建新的 公钥凭据 时,会生成一个认证签名。认证签名为认证器和凭据的某些属性提供加密证明。例如,认证签名声明了认证器类型(如其 AAGUID 所表示)和凭据公钥。认证签名由认证私钥签名,该私钥根据所需的认证类型选择。有关认证的更多详细信息,请参阅§ 6.5 认证。
-
当调用 authenticatorGetAssertion 方法时,会生成一个声明签名。它表示认证器对用户同意特定事务(如登录或完成购买)的声明。因此,声明签名表示持有特定凭据私钥的认证器已经尽其所能确认请求此事务的用户与创建该特定公钥凭据时同意的用户是同一人。它还断言了额外的信息,即称为客户端数据,这对调用者可能有用,例如用户同意的方式,以及认证器向用户显示的提示。声明签名的格式如图 4所示。
WebAuthn 签名一词指的是认证签名和声明签名。这些签名的格式以及生成它们的过程将在下文中指定。
6.1. 认证器数据
认证器数据结构编码了由认证器生成的上下文绑定。这些绑定由认证器本身控制,并从WebAuthn 依赖方对认证器安全属性的评估中获得信任。在一种极端情况下,认证器可能嵌入在客户端中,其绑定的可信度可能不会超过客户端数据。在另一种极端情况下,认证器可能是具有高安全硬件和软件的独立实体,通过安全通道连接到客户端。在这两种情况下,依赖方以相同的格式接收认证器数据,并根据对认证器的了解做出信任决策。
认证器数据具有紧凑但可扩展的编码。这是期望的,因为认证器可能是具有有限能力和低功耗需求的设备,其软件栈远比客户端平台简单得多。
名称 | 长度(字节) | 描述 |
---|---|---|
rpIdHash | 32 | RP ID的 SHA-256 哈希值,该凭据的作用域。 |
标志 | 1 | 标志(第0位是最低有效位): |
签名计数 | 4 | 签名计数器,32位无符号大端整数。 |
认证的凭据数据 | 可变(如果存在) | 认证的凭据数据(如果存在)。详细信息请参见§ 6.5.1 认证的凭据数据。其长度取决于凭据 ID 长度和正在认证的凭据公钥。 |
扩展 | 可变(如果存在) | 扩展定义的认证器数据。这是一个CBOR [RFC8949]映射,扩展标识符为键,认证器扩展输出为值。详细信息请参见§ 9 WebAuthn 扩展。 |
RP ID最初是从客户端接收到的,当创建凭据时,以及当生成声明时再次接收。然而,它与其他客户端数据在一些重要方面有所不同。首先,不同于客户端数据,凭据的RP ID在操作之间不会更改,而是在该凭据的整个生命周期内保持不变。其次,在authenticatorGetAssertion操作期间,认证器通过验证请求的凭据的RP ID与客户端提供的RP ID完全匹配来验证它。
确定认证凭证数据的长度是可变的,涉及确定凭证公钥
的起始位置,取决于前面的凭证ID
的长度,然后确定凭证公钥
的长度(参见RFC8152第7节)。
6.1.1. 签名计数器注意事项
认证器应实现签名计数器功能。这些计数器在概念上由认证器为每个凭据存储,或全局存储于整个认证器。凭据的签名计数器的初始值由认证器数据中的signCount
值指定,该数据由authenticatorMakeCredential返回。签名计数器在每次成功的authenticatorGetAssertion操作后增加某个正值,并再次在认证器数据中返回给WebAuthn
依赖方。签名计数器的目的是帮助依赖方检测克隆的认证器。对于保护措施有限的认证器,克隆检测尤为重要。
依赖方存储最近的authenticatorGetAssertion操作的签名计数器值。(或者,如果凭据上从未执行过authenticatorGetAssertion,则存储authenticatorMakeCredential操作中的计数器值。)在随后的authenticatorGetAssertion操作中,依赖方将存储的签名计数器值与声明的认证器数据中返回的新signCount
值进行比较。如果两者中任意一个非零,并且新的signCount
值小于或等于存储的值,则可能存在克隆的认证器,或者认证器可能出现故障。
检测到签名计数器不匹配并不能表明当前操作是由克隆的认证器还是原始认证器执行的。依赖方应根据其个别情况(即其风险承受能力)适当地处理这种情况。
认证器:
-
应实现按凭据的签名计数器。这可防止签名计数器值在依赖方之间共享,并可能被用作用户的关联句柄。认证器可以实现全局的签名计数器,即按认证器基础实现,但这对用户来说隐私性较差。
-
应确保签名计数器值不会意外减少(例如,由于硬件故障)。
6.1.2. FIDO U2F 签名格式兼容性
用于签署authenticator data
结构和序列化客户端数据的哈希值的声明签名格式与FIDO
U2F认证签名格式兼容(参见第5.4节,在[FIDO-U2F-Message-Formats]中)。
这是因为FIDO U2F认证响应消息中已签署数据的前37个字节构成了有效的认证器数据结构,其余32个字节则是序列化客户端数据的哈希值。在此认证器数据结构中,rpIdHash
是FIDO
U2F的应用参数,除了UP
外,所有标志
始终为零,认证凭据数据
和扩展
从不出现。因此,FIDO
U2F认证签名可以通过与其他由authenticatorMakeCredential操作生成的声明签名相同的程序进行验证。
6.2. 认证器分类
许多使用案例取决于所使用的认证器的功能。 本节定义了这些功能的一些术语、它们的重要组合及其启用的使用案例。
例如:
-
在同一客户端设备上进行后续重新身份验证时,平台认证器可能是最方便的,因为它直接内置在客户端设备中,而不是用户可能需要寻找的独立设备。
-
笔记本电脑可能支持通过USB和蓝牙连接漫游认证器,而手机可能只支持NFC。
以上示例说明了主要的认证器类型特征:
这些特征是独立的,理论上可以以任何方式组合,但表 列出了特别感兴趣的一些认证器类型并命名了它们。
认证器类型 | 认证器附着模式 | 凭证存储模式 | 身份验证因素能力 |
---|---|---|---|
第二因素平台认证器 | 平台 | 任意 | 单因素能力 |
用户验证平台认证器 | 平台 | 任意 | 多因素能力 |
第二因素漫游认证器 | 跨平台 | 服务器端存储 | 单因素能力 |
第一因素漫游认证器 | 跨平台 | 客户端存储 | 多因素能力 |
一个第二因素平台认证器在同一客户端设备上重新进行身份验证时使用方便,并且可以在启动新会话和恢复现有会话时增加一层额外的安全性。一个第二因素漫游认证器更有可能在特定的客户端设备上首次进行身份验证,或者在多个用户共享的客户端设备上使用。
用户验证平台认证器和第一因素漫游认证器支持无密码多因素身份验证。除了证明凭证私钥的持有之外,这些认证器还支持作为第二身份验证因素的用户验证,通常是PIN码或生物识别。认证器因此可以作为两种身份验证因素,从而实现多因素身份验证,同时无需与依赖方共享密码。
在表 中未命名的四种组合的使用案例较少:
-
对于平台认证器来说,凭证存储模式不如对漫游认证器重要,因为使用平台认证器的用户通常可以通过会话Cookie或类似方式(即环境凭证)进行识别。
-
一个具备可发现凭证功能但不具备多因素能力的漫游认证器可以用于无用户名的单因素身份验证,其中用户通过用户句柄自动识别,并且持有凭证私钥作为唯一的身份验证因素。在某些情况下,这可能很有用,但使用户特别容易受到认证器被盗的威胁。
-
一个具备多因素能力但不具备可发现凭证功能的漫游认证器可以用于多因素身份验证,但首先需要识别用户,这可能会泄露个人识别信息;请参见§ 14.6.3 凭证ID隐私泄漏。
以下小节更深入地定义了认证器附着模式、凭证存储模式和身份验证因素能力的各个方面。
6.2.1. 认证器附着模式
客户端可以通过多种机制与认证器通信。例如,客户端可以使用客户端设备特定的API与物理绑定到客户端设备的认证器通信。另一方面,客户端可以使用各种标准化的跨平台传输协议(例如蓝牙,参见§ 5.8.4 认证器传输枚举 (enum AuthenticatorTransport))来发现和通信与跨平台附着的认证器。我们将作为客户端设备一部分的认证器称为平台认证器,而那些通过跨平台传输协议可访问的则称为漫游认证器。
-
平台认证器使用称为平台附着的客户端设备特定传输方式连接,通常无法从客户端设备中移除。绑定到平台认证器的公钥凭证称为平台凭证。
-
漫游认证器使用称为跨平台附着的跨平台传输方式连接。这类认证器是可移除的,并且可以在客户端设备之间“漫游”。绑定到漫游认证器的公钥凭证称为漫游凭证。
某些平台认证器在某些情况下也可以作为漫游认证器。例如,集成到移动设备中的平台认证器可以通过蓝牙作为漫游认证器提供服务。在这种情况下,运行在移动设备上的客户端将识别该认证器为平台认证器,而通过蓝牙与同一认证器通信的不同客户端设备上运行的客户端则会将其识别为漫游认证器。
平台认证器的主要使用场景是将特定的客户端设备注册为“受信任设备”,使得该客户端设备本身作为未来您拥有的某物 身份验证因素进行身份验证。这使得用户无需在未来的身份验证仪式中使用漫游认证器,例如,用户不必在口袋里翻找钥匙扣或手机。
漫游认证器的使用场景包括:首次在新客户端设备上进行身份验证,在很少使用的客户端设备上进行身份验证,在多个用户共享的客户端设备上进行身份验证,或者在不包含平台认证器的客户端设备上进行身份验证;以及当策略或偏好要求认证器与其使用的客户端设备分离时使用。漫游认证器还可以用来持有备份的凭证,以防另一个认证器丢失。
6.2.2. 凭证存储模式
-
在嵌入认证器、客户端或客户端设备中的持久性存储中,例如在安全元素中。这是客户端可发现的公钥凭证源的技术要求。
-
通过加密(即封装)凭证私钥,使得只有这个认证器能够解密(即解封装)它,并让生成的密文成为凭证ID,用于公钥凭证源。凭证ID由依赖方存储,并通过
allowCredentials
选项在get()
操作中返回给认证器,允许认证器解密并使用凭证私钥。这使得认证器能够拥有无限的凭证私钥存储容量,因为加密的凭证私钥由依赖方而非认证器存储——但这意味着以这种方式存储的凭证必须先从依赖方检索回来,认证器才能使用它。
这些存储策略中的哪一种由认证器支持,定义了该认证器的凭证存储模式,具体如下:
-
如果认证器支持客户端可发现的公钥凭证源,则该认证器具有客户端凭证存储模式。具有客户端凭证存储模式的认证器也称为可发现凭证能力。
请注意,具有可发现凭证能力的认证器可以同时支持这两种存储策略。在这种情况下,认证器可以自行决定对不同的凭证使用不同的存储策略,但必须遵守residentKey
或requireResidentKey
选项的要求。
6.2.3. 认证因子能力
在认证过程中,用于证明身份的认证因子主要有三大类:所持物,所知物,和所是物。例如,分别对应物理钥匙、密码和指纹。
所有WebAuthn 认证器都属于所持物类,但如果一个认证器支持用户验证,它也可以作为一种或两种额外的认证因子。例如,如果认证器可以验证 PIN 码,则 PIN 码属于所知物,而生物识别认证器可以验证所是物。因此,一个支持用户验证的认证器被称为多因子能力。反之,一个不具备多因子能力的认证器被称为单因子能力。请注意,单个多因子能力的认证器可能支持多种用户验证模式,这意味着它可以作为所有三种认证因子。
虽然用户验证是在认证器上本地执行的,而不是由依赖方执行的,但认证器通过在返回给依赖方的签名响应中设置UV 标志来指示是否进行了用户验证。因此,依赖方可以使用UV标志来验证在注册或认证过程中是否使用了额外的认证因子。UV 标志的真实性可以通过检查认证器的认证声明来评估。
6.3. 认证器操作
一个WebAuthn 客户端必须连接到认证器,才能调用该认证器的任何操作。此连接定义为认证器会话。认证器必须在会话之间保持隔离。它可以通过仅允许一个会话在任何特定时间存在,或者通过提供更复杂的会话管理来实现这一点。
客户端可以在认证器会话中调用以下操作。
6.3.1. 通过凭据 ID 查找凭据源算法
在认证器 authenticator中查找凭据 ID credentialId的结果是以下算法的结果:
-
如果authenticator可以将credentialId解密为公钥凭据源 credSource:
-
将credSource.id设置为credentialId。
-
返回credSource。
-
-
对于每个 公钥凭据源 credSource,在authenticator的凭据映射中:
-
如果credSource.id是credentialId,则返回credSource。
-
-
返回
null
。
6.3.2. The authenticatorMakeCredential 操作
此操作接受以下输入参数:
- hash
-
由客户端提供的序列化客户端数据的哈希。
- rpEntity
- userEntity
-
用户账户的
PublicKeyCredentialUserEntity
, 包含用户句柄,由依赖方提供。 - requireResidentKey
-
凭据创建的有效常驻密钥要求,由客户端确定的布尔值。
- requireUserPresence
-
布尔常量值
true
。 它作为伪参数包含在此处,以简化将此抽象认证器模型应用于可能希望使用户存在测试可选的实现,尽管 WebAuthn 并不要求这样做。 - requireUserVerification
-
凭据创建的有效用户验证要求,由客户端确定的布尔值。
- credTypesAndPubKeyAlgs
-
由依赖方请求的
PublicKeyCredentialType
和公钥算法(COSEAlgorithmIdentifier
)对的序列。此序列按从最优先到最不优先的顺序排列。认证器尽最大努力创建其可以支持的最优先的凭据。 - excludeCredentialDescriptorList
-
由依赖方提供的
PublicKeyCredentialDescriptor
对象的可选列表,意图是如果认证器已知其中的任何一个,则不应创建新凭据。excludeCredentialDescriptorList包含已知凭据的列表。 - enterpriseAttestationPossible
-
一个布尔值,指示认证器可能返回单独标识的认证。
- extensions
注意:在执行此操作之前,必须通过运行认证器取消操作,终止在认证器会话中进行的所有其他操作。
当调用此操作时,认证器必须执行以下过程:
-
检查所有提供的参数是否在语法上格式正确且长度正确。如果不正确,返回等效于"
UnknownError
"的错误代码并终止操作。 -
检查credTypesAndPubKeyAlgs中指定的至少一个
PublicKeyCredentialType
和密码参数组合是否受支持。如果不支持,返回等效于"NotSupportedError
"的错误代码并终止操作。 -
对于每个descriptor在excludeCredentialDescriptorList中:
-
如果查找
descriptor.
在此认证器中返回非空,并且返回的项的RP ID和类型分别与id
rpEntity.
和id
excludeCredentialDescriptorList.
匹配, 然后收集一个确认创建新凭据的授权手势。授权手势必须包括用户存在测试。如果用户类型
- 确认同意创建新凭据
-
返回等效于"
InvalidStateError
"的错误代码并终止操作。 - 不同意创建新凭据
-
返回等效于"
NotAllowedError
"的错误代码并终止操作。
注意:此授权手势的目的是为了隐私原因授权披露
descriptor.
被绑定到此认证器的事实,而不是继续创建凭据。如果用户同意,客户端和依赖方可以检测到这一点,并指导用户使用不同的认证器。如果用户不同意,认证器不会披露id
descriptor.
被绑定到它,并表现得像用户只是拒绝同意创建凭据一样。id
-
-
如果requireResidentKey为
true
且认证器无法存储客户端可发现的公钥凭据源, 返回等效于"ConstraintError
"的错误代码并终止操作。 -
如果requireUserVerification为
true
且认证器无法执行用户验证,返回等效于"ConstraintError
"的错误代码并终止操作。 -
收集确认创建新凭据的授权手势。
如果认证器有自己的输出功能,则由认证器显示授权手势的提示,否则由用户代理显示。提示应显示
rpEntity.
、id
rpEntity.
、name
userEntity.
和name
userEntity.
,如果可能的话。displayName
如果requireUserVerification为
true
,授权手势必须包括用户验证。如果requireUserPresence为
true
,授权手势必须包括用户存在测试。如果用户未同意或用户验证失败, 返回等效于"
NotAllowedError
"的错误代码并终止操作。 -
-
令(publicKey, privateKey)为一对新的加密密钥,使用
PublicKeyCredentialType
和由此认证器支持的credTypesAndPubKeyAlgs中的第一个项目表示的加密参数组合生成。 -
让userHandle成为
userEntity.
。id
-
让credentialSource成为新的公钥凭据源,其字段如下:
-
如果requireResidentKey为
true
或认证器选择创建客户端可发现的公钥凭据源: -
否则:
-
让credentialId成为序列化并加密的credentialSource,以便只有此认证器可以解密它。
-
-
-
如果在创建新凭据对象时发生任何错误,返回等效于"
UnknownError
"的错误代码并终止操作。 -
让processedExtensions成为结果,认证器扩展处理的结果,对于每个支持的扩展标识符→认证器扩展输入在extensions中。
-
如果认证器:
-
让attestedCredentialData成为包括credentialId和publicKey的认证凭据数据字节数组。
-
让authenticatorData成为字节数组,如§ 6.1 认证器数据中所述,包括attestedCredentialData作为
attestedCredentialData
和processedExtensions(如果有的话)作为扩展
。 -
为新凭据创建认证对象,使用§ 6.5.4 生成认证对象中规定的程序,使用由认证器选择的认证声明格式、authenticatorData和hash,并
考虑到
enterpriseAttestationPossible的值。有关认证的更多详细信息,请参见§ 6.5 认证。
成功完成此操作后,认证器将认证对象返回给客户端。
6.3.3. authenticatorGetAssertion 操作
它接受以下输入参数:
- rpId
- hash
-
客户端提供的序列化客户端数据的哈希值。
- allowCredentialDescriptorList
-
一个可选的列表,包含描述Relying Party可接受的凭据的
PublicKeyCredentialDescriptor
对象(可能由客户端过滤),如果有的话。 - requireUserPresence
-
常量布尔值
true
。 这里将其作为伪参数包含在内,以简化将此抽象认证器模型应用于可能希望使用户在场测试可选的实现,尽管 WebAuthn 不允许这样做。 - requireUserVerification
-
用于断言的有效用户验证要求,由客户端提供的布尔值。
- extensions
-
由客户端基于Relying Party请求的扩展(如果有)创建的CBOR 映射,从扩展标识符到其认证器扩展输入。
注意: 在执行此操作之前,必须通过运行authenticatorCancel操作终止认证器会话中的所有其他正在进行的操作。
当调用此方法时,认证器必须执行以下步骤:
-
检查所有提供的参数是否在语法上正确且长度正确。如果不正确,返回等效于"
UnknownError
"的错误代码并终止操作。 -
如果提供了allowCredentialDescriptorList,则对每个allowCredentialDescriptorList中的descriptor执行以下操作:
-
否则(未提供allowCredentialDescriptorList),对每个此认证器的凭据映射中的key→credSource执行操作,并将credSource附加到credentialOptions。
-
从credentialOptions中删除rpId不等于指定rpId的所有项。
-
如果credentialOptions现在为空,则返回等效于"
NotAllowedError
"的错误代码并终止操作。 -
提示用户从credentialOptions中选择一个公钥凭据源 selectedCredential。 收集一个授权手势,确认用户同意使用selectedCredential。 如果认证器具有自己的输出能力,则授权手势提示可以由认证器显示,否则由用户代理显示。
如果requireUserVerification为
true
,则授权手势必须包括用户验证。如果requireUserPresence为
true
,则授权手势必须包括用户在场测试。如果用户不同意,返回等效于"
NotAllowedError
"的错误代码并终止操作。 -
让processedExtensions成为认证器扩展处理的结果,对每个在extensions中的支持的扩展标识符→认证器扩展输入。
-
增加与凭据相关的签名计数器或全局签名计数器值,具体取决于认证器实现的方式,通过某个正值。如果认证器不实现签名计数器,则让签名计数器的值保持为零。
-
让authenticatorData成为字节数组,如§ 6.1 认证器数据中所述,包括processedExtensions(如果有的话)作为
扩展
,并排除认证的凭据数据
。 -
让signature成为使用selectedCredential的privateKey对
authenticatorData || hash
串联生成的断言签名。此处可以安全地使用简单的未分隔串联,因为认证器数据描述了自己的长度。序列化客户端数据的哈希(可能具有可变长度)始终是最后一个元素。 -
如果在生成断言签名时发生任何错误,返回等效于"
UnknownError
"的错误代码并终止操作。 -
返回给用户代理:
-
selectedCredential.id,如果客户端提供了长度为2或更长的凭据列表(即allowCredentialDescriptorList)或未提供此类列表。
注意: 如果客户端在allowCredentialDescriptorList中仅提供了一个凭据,并且成功使用了该凭据,则不会返回其凭据 ID,因为客户端已经知道它。这可以节省在可能是常见情况下通过可能受限连接传输这些字节的资源。
-
authenticatorData
-
signature
-
selectedCredential.userHandle
注意: 返回的userHandle值可能为
null
,请参见:userHandleResult。
-
如果认证器找不到与指定Relying Party匹配的任何符合指定条件的凭据,则它会终止操作并返回错误。
6.3.4. authenticatorCancel 操作
此操作不接受任何输入参数,也不返回任何结果。
当客户端在认证器会话中调用此操作时,它会终止该认证器会话中当前正在进行的任何authenticatorMakeCredential或authenticatorGetAssertion操作。认证器停止提示或接受与已取消操作相关的任何用户输入。客户端忽略认证器对已取消操作的任何进一步响应。
如果在没有正在进行的authenticatorMakeCredential或authenticatorGetAssertion操作的认证器会话中调用此操作,则此操作会被忽略。
6.4. 字符串处理
认证器可能需要存储由Relying
Party选择的任意字符串,例如在name
和displayName
字段中的PublicKeyCredentialUserEntity
对象。本节讨论了处理可能呈现给人类的任意字符串的一些实际影响。
6.4.1. 字符串截断
API中的每个任意字符串都会考虑到认证器可能可用的有限资源。如果选择字符串值截断作为适应措施,则认证器可以截断字符串以使其适合等于或大于指定的最小支持长度的长度。此类截断还应尊重UTF-8序列边界或字素簇边界[UTR29]。这定义了允许的最大截断,认证器不得进一步截断。
例如,在图 中,字符串长度为65字节。如果截断到64字节,则必须出于空间原因删除最后的0x88字节。由于这留下了部分UTF-8序列,因此该序列的剩余部分也可能会被删除。由于这留下了部分字素簇,认证器可以删除该簇的其余部分。
符合标准的用户代理负责确保Relying Party观察到的认证器行为在字符串处理方面符合此规范。例如,如果已知认证器在被要求存储大字符串时表现不正确,用户代理应为其执行截断以保持从Relying Party视角来看的一致性。执行此操作的用户代理应在字素簇边界处截断。
基于UTF-8序列的截断可能会导致字素簇被截断。这可能导致字素簇呈现为不同的字形,潜在地改变字符串的含义,而不是完全删除字形。
此外,仅在字节边界上截断会导致一个已知问题,用户代理应该意识到这一点:如果认证器使用[FIDO-CTAP],那么来自认证器的未来消息可能包含无效的CBOR,因为该值被类型化为CBOR字符串,因此需要有效的UTF-8。用户代理的任务是处理此问题,以避免让认证器理解字符编码和Unicode字符属性的负担。因此,当与认证器交互时,用户代理应:
-
确保发送给认证器的任何字符串都是有效编码的。
-
处理字符串截断导致的无效编码情况。例如,可以删除或用U+FFFD替换末尾的任何部分代码点。
6.4.2. 语言和方向编码
为了在上下文中正确显示,字符串的语言和基本方向可能是必需的。此API中的字符串可能需要写入固定功能的认证器,然后再读取并显示在不同的平台上。因此,语言和方向的元数据被编码在字符串本身中,以确保它们原子性地传输。
要在记录为允许语言和方向元数据的字符串中编码这些信息,请在其代码点后附加两个代码点序列:
第一个序列使用代码点U+E0001编码一个语言标签,后跟将语言标签中的ASCII值每个都加上U+E0000。例如,语言标签“en-US”将成为代码点U+E0001、U+E0065、U+E006E、U+E002D、U+E0055、U+E0053。
第二个序列由一个代码点组成,可能是U+200E(“左向右标记”)、U+200F(“右向左标记”)或U+E007F(“取消标签”)。前两个可以用来指示方向性,但只应在需要产生正确结果时使用。(例如,一个RTL字符串以LTR-强字符开头。)值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. Attested Credential Data
已认证的凭证数据 是在生成给定凭证的 证明对象 时添加到 认证器数据 中的一个可变长度字节数组。其格式如 表 所示。
Name | Length (in bytes) | Description |
---|---|---|
aaguid | 16 | 认证器的 AAGUID。 |
credentialIdLength | 2 | Credential ID 的字节长度 L,16 位无符号大端整数。 |
credentialId | L | Credential ID |
credentialPublicKey | variable | 凭证公钥,使用 [RFC8152] 第 7 节定义的 COSE_Key 格式编码,并使用 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] 的其他章节中定义。
以下是一个 COSE_Key 编码的椭圆曲线公钥的示例,使用 EC2 格式(见 [RFC8152] 第 13.1 节),在 P-256 曲线上,与 ES256 签名算法(使用 ECDSA w/ SHA-256,见 [RFC8152] 第 8.1 节 一起使用):
{
1
:
2
,
; kty: EC2 key type3
:
-7
,
; alg: ES256 signature algorithm-1
:
1
,
; crv: P-256 curve-2
:
x,
; x-coordinate as byte string 32 bytes in length ; e.g., in hex: 65eda5a12577c2bae829437fe338701a10aaa375e1bb5b5de108de439c08551d-3
:
y ; y-coordinate as byte string 32 bytes in length ; e.g., in hex: 1e52ed75701163f7f9e40ddf9f341b3dc9ba860af7e0ca7ca7e9eecd0084d19c}
以下是上述椭圆曲线公钥在 CTAP2 规范的 CBOR 编码形式中的编码示例,包含了空白和换行符以便于理解并与上文的 CDDL [RFC8610] 的展示相匹配:
A5
01
02
03
26
20
01
21
58
20
65eda5a12577c2bae829437fe338701a10aaa375e1bb5b5de108de439c08551d
22
58
20
1e52ed75701163f7f9e40ddf9f341b3dc9ba860af7e0ca7ca7e9eecd0084d19c
以下是一个 COSE_Key 编码的 2048 位 RSA 公钥示例(见 [RFC8230] 第 4 节),与 PS256 签名算法(使用 RSASSA-PSS 和 SHA-256,见 [RFC8230] 第 2 节一起使用):
{
1
:
3
,
; kty: RSA key type3
:
-37
,
; alg: PS256-1
:
n
,
; n: RSA modulus n byte string 256 bytes in length ; e.g., in hex (middle bytes elided for brevity): DB5F651550...6DC6548ACC3-2
:
e ; e: RSA public exponent e byte string 3 bytes in length ; e.g., in hex: 010001}
以下是与 RS256 签名算法(使用 RSASSA-PKCS1-v1_5 和 SHA-256)一起使用的相同 COSE_Key 编码 RSA 公钥示例:
{
1
:
3
,
; kty: RSA key type3
:
-257
,
; alg: RS256-1
:
n
,
; n: RSA modulus n byte string 256 bytes in length ; e.g., in hex (middle bytes elided for brevity): DB5F651550...6DC6548ACC3-2
:
e ; e: RSA public exponent e byte string 3 bytes in length ; e.g., in hex: 010001}
6.5.2. 证明声明格式
如上所述,证明声明格式是指由验证器对一组上下文绑定进行加密签名的数据格式。每个证明声明格式必须使用以下模板定义:
-
支持的证明类型:
-
语法:使用 CDDL [RFC8610] 为在 § 6.5.4 生成证明对象 中定义的扩展点
$attStmtFormat
定义的该格式生成的证明声明的语法。 -
签名过程:给定要证明的公钥凭证、包含用于证明的验证器数据的验证器数据结构,以及序列化客户端数据的哈希,计算该格式下证明声明的签名过程。
-
验证过程:验证证明声明的过程,包含以下验证过程输入:
-
attStmt:证明声明结构
-
authenticatorData:声称用于证明的验证器数据
-
clientDataHash:序列化客户端数据的哈希
该过程返回以下之一:
-
指定的证明声明格式的初始列表在 § 8 定义的证明声明格式 中。
6.5.3. 证明类型
WebAuthn 支持几种证明类型,定义了证明声明及其底层信任模型的语义:
注意: 本规范未定义显式表达证明类型的数据结构,这些类型由验证器使用。信赖方在从事证明声明验证时——即调用navigator.credentials.create()
时选择一个证明传递,而不是none
,并验证接收到的证明声明,将确定使用的证明类型作为验证的一部分。请参阅§ 8
已定义的证明声明格式中的“验证过程”小节。另见§ 14.4.1 证明隐私。对于本节中定义的除自我证明和无以外的所有证明类型,信赖方的验证将遵循§ 7.1 注册新凭证步骤 21 中的匹配信任路径至可接受的根证书。区分这些证明类型主要是作为确定证明是否符合信赖方政策的手段。
- 基本证明 (基本)
-
在基本证明的情况下[UAFProtocol],验证器的证明密钥对特定于验证器的“型号”,即一批验证器。因此,相同或类似型号的验证器通常共享相同的证明密钥对。有关更多信息,请参阅§ 14.4.1 证明隐私。
基本证明也称为批次证明。
- 自我证明 (自我)
-
在自我证明的情况下,也称为替代基本证明[UAFProtocol],验证器没有任何特定的证明密钥对。相反,它使用凭证私钥来创建证明签名。没有有意义的证明私钥保护措施的验证器通常使用这种证明类型。
- 证明 CA (AttCA)
-
在这种情况下,验证器基于可信平台模块(TPM),并持有验证器特定的“背书密钥”(EK)。此密钥用于与可信的第三方,即证明 CA [TCG-CMCProfile-AIKCertEnroll](以前称为“隐私 CA”)进行安全通信。验证器可以生成多个证明身份密钥对(AIK),并请求证明 CA为每个密钥对颁发 AIK 证书。使用这种方法,这样的验证器可以将 EK(这是一个全局关联句柄)的暴露限制在证明 CA 之内。AIK 可以为每个验证器生成的公钥凭证单独请求,并作为证明证书传递给信赖方。
注意: 这一概念通常会导致多个证明证书。最近请求的证明证书称为“活动”证书。
- 匿名化 CA (AnonCA)
-
在这种情况下,验证器使用匿名化 CA,该 CA 动态生成每个凭证的证明证书,以确保向信赖方展示的证明声明不会提供可能用于跟踪的唯一可识别信息。
注意: 传递证明为类型的AttCA或AnonCA的证明声明使用与类型类型为基本的证明声明相同的数据结构,因此这三种证明类型通常只能通过外部提供的有关证明证书内容的知识来区分。
- 无证明声明 (无)
-
在这种情况下,不提供证明信息。另见§ 8.7 无证明声明格式。
6.5.4. 生成证明对象
验证器必须:
-
让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 进行编码。示例: 30 44 ; SEQUENCE (68 字节) 02 20 ; INTEGER (32 字节) | 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 字节) | 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 证明对象 操作
一个注册
或认证仪式开始于WebAuthn
证明对象 创建一个PublicKeyCredentialCreationOptions
或PublicKeyCredentialRequestOptions
对象,这些对象分别编码了仪式的参数。证明对象
应该注意在这个阶段不要泄露敏感信息;详细信息见§ 14.6.2 用户名枚举。
在成功执行create()
或get()
后,
证明对象的脚本会接收到一个PublicKeyCredential
,其中包含一个AuthenticatorAttestationResponse
或AuthenticatorAssertionResponse
结构,这些结构分别来自客户端。然后,它必须使用本规范之外的方法将这些结构的内容传送到证明对象服务器。这一节描述了证明对象在接收到这些结构后必须执行的操作。
7.1. 注册一个新的凭证
-
让options成为一个新的
PublicKeyCredentialCreationOptions
结构,并根据证明对象的需求进行配置。 -
调用
navigator.credentials.create()
并将options作为
选项传递。让credential成为成功解决的promise的结果。如果promise被拒绝,则使用用户可见的错误中止仪式,或根据拒绝的promise中的可用上下文引导用户体验。例如,如果promise因错误代码等同于publicKey
InvalidStateError
而被拒绝,用户可能会被指示使用不同的认证器。有关不同错误上下文及导致它们的情况的信息,请参见§ 6.3.2 认证器创建凭证操作。 -
让response成为
credential.
。如果response不是response
AuthenticatorAttestationResponse
的实例,则使用用户可见的错误中止仪式。 -
让clientExtensionResults成为调用
credential.
的结果。getClientExtensionResults()
-
让JSONtext成为通过UTF-8解码
response.
值的结果。clientDataJSON
注意: 使用任何UTF-8解码的实现是可以接受的,只要它产生的结果与UTF-8解码算法产生的结果相同。特别是,必须去除任何前导字节顺序标记(BOM)。
-
让C,即在凭证创建期间收集的客户端数据,成为在JSONtext上运行实现特定的JSON解析器的结果。
注意: C可以是任何实现特定的数据结构表示,只要C的组件可以被引用,如本算法所要求的那样。
-
验证
C.
的值是否为type
webauthn.create
。 -
验证
C.
的值是否与获取令牌绑定的TLS连接的状态相匹配。如果在该TLS连接上使用了令牌绑定,还应验证tokenBinding
.status
C.
的值是否与连接的base64url编码的令牌绑定ID匹配。tokenBinding
.id
-
让hash成为使用SHA-256对
response.
值进行哈希计算的结果。clientDataJSON
-
对
attestationObject
字段中的AuthenticatorAttestationResponse
结构执行CBOR解码,以获取证明对象格式fmt、认证器数据authData以及证明对象attStmt。 -
验证authData中的凭证公钥中的"alg"参数是否与
alg
属性匹配,options.
。pubKeyCredParams
-
验证clientExtensionResults中的客户端扩展输出与authData中的认证器扩展输出是否符合预期,考虑给出的客户端扩展输入值
options.
,以及证明对象关于未经请求的扩展的特定政策,即那些未作为扩展
options.
的一部分指定的扩展。一般情况下,"符合预期"的含义取决于证明对象以及所使用的扩展。扩展
注意: 客户端平台可能会实施本地策略,该策略会设置额外的认证器扩展或客户端扩展,从而导致在authData中的认证器扩展输出或clientExtensionResults中的客户端扩展输出中出现原本未在
options.
部分指定的值。证明对象必须做好处理此类情况的准备,无论是忽略这些未经请求的扩展还是拒绝认证。证明对象可以根据本地政策和所使用的扩展做出此决定。扩展
-
通过在fmt与支持的WebAuthn证明对象格式标识符值集合之间执行USASCII区分大小写匹配来确定证明对象格式。WebAuthn证明对象格式标识符值的最新注册列表由IANA "WebAuthn Attestation Statement Format Identifiers"注册表[IANA-WebAuthn-Registries]维护,该注册表由[RFC8809]建立。
-
验证attStmt是否为正确的证明对象,传递一个有效的证明签名,通过使用fmt的验证过程,给定attStmt、authData和hash。
注意: 每个证明对象格式都指定了其自己的验证过程。参见§ 8 定义的证明对象格式以获取最初定义的格式,[IANA-WebAuthn-Registries]以获取最新列表。
-
如果验证成功,请从可信来源或政策中获取该证明类型和证明对象格式fmt的可接受信任锚(即证明根证书)列表。例如,FIDO Metadata Service [FIDOMetadataService]提供了一种获取此类信息的方法,使用authData中的
aaguid
。 -
使用步骤19中验证过程的输出评估证明的可信度,如下所示:
-
检查
credentialId
是否尚未注册到任何其他用户。如果请求为已注册到其他用户的凭证注册,证明对象应当失败此注册仪式,或可能决定接受注册,例如删除旧注册。 -
如果证明对象attStmt成功验证且被视为可信,则将新凭证注册到在
options.
中指定的帐户中:user
-
将用户的帐户与
credentialId
和credentialPublicKey
在authData.attestedCredentialData
中关联,如适用于证明对象的系统。 -
将
credentialId
与一个新存储的签名计数器值关联,该值初始化为authData.signCount
的值。
建议还要:
-
将
credentialId
与通过调用credential.
返回的传输提示关联。此值不应在存储前后修改。建议使用此值填充response
.getTransports()
transports
,以及未来get()
调用中的allowCredentials
选项,以帮助客户端找到合适的认证器。
-
-
如果证明对象attStmt成功验证但在步骤21中未被视为可信,证明对象应当失败此注册仪式。
注意: 但是,如果政策允许,证明对象可能会注册
credential ID
和凭证公钥,但将凭证视为具有自我证明的凭证(参见§ 6.5.3 证明类型)。如果这样做,证明对象正在断言,没有公钥凭证是由特定认证器型号生成的密码学证明。参见[FIDOSecRef]和[UAFProtocol]以获取更详细的讨论。
证明对象的验证需要证明对象在上面的步骤20中有一种可信的方法来确定可接受的信任锚。此外,如果使用了证书,证明对象必须访问中间CA证书的证书状态信息。如果客户端在证明信息中未提供此链,证明对象还必须能够构建证明证书链。
7.2. 验证认证声明
-
将options设为一个新的
PublicKeyCredentialRequestOptions
结构,配置为证明对象所需的仪式。如果
options.
存在,allowCredentials
transports
成员的每个项应设置为注册相应凭据时通过调用credential.
返回的值。response
.getTransports()
-
调用
navigator.credentials.get()
并将options作为
选项传递。让credential成为成功解决的承诺的结果。如果承诺被拒绝,则以用户可见的错误终止仪式,或以其他方式根据拒绝的承诺中可用的上下文引导用户体验。有关不同错误上下文及其导致情况的信息,请参见§ 6.3.3 认证器获取声明操作。publicKey
-
将response设为
credential.
。如果response不是response
AuthenticatorAssertionResponse
的实例,则以用户可见的错误终止仪式。 -
将clientExtensionResults设为调用
credential.
的结果。getClientExtensionResults()
-
如果
options.
非空,验证allowCredentials
credential.
是否标识id
options.
中列出的公钥凭证之一。allowCredentials
-
识别正在进行身份验证的用户并验证该用户是否为
credentialSource
标识的公钥凭证源的所有者:- 如果在启动认证仪式之前已识别用户,例如通过用户名或cookie,
-
验证识别的用户是否为credentialSource的所有者。如果
response.
存在,则将userHandle设为其值。验证userHandle是否也映射到同一用户。userHandle
- 如果在启动认证仪式之前未识别用户,
-
验证
response.
是否存在,并且该值标识的用户是否为credentialSource的所有者。userHandle
-
使用
credential.
(或id
credential.
,如果不适合使用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.
的值是否为字符串type
webauthn.get
。 -
验证
C.
的值是否与获取证明的TLS连接的令牌绑定状态匹配。如果在该TLS连接上使用了令牌绑定,还验证tokenBinding
.status
C.
是否与该连接的base64url编码的令牌绑定ID匹配。tokenBinding
.id
-
验证
rpIdHash
在authData中的值是否为证明对象期望的RP ID的SHA-256哈希值。注意: 如果使用了appid扩展,这一步需要一些特殊逻辑。详见§ 10.1 FIDO AppID扩展(appid)。
-
根据clientExtensionResults中的客户端扩展输出和authData中的认证器扩展输出验证值是否如预期,考虑
options.
中给出的客户端扩展输入值以及证明对象关于未请求的扩展(即那些未作为扩展
options.
的一部分指定的)政策。扩展
注意: 客户端平台可以制定本地政策,设置额外的认证器扩展或客户端扩展,从而导致在认证器扩展输出或客户端扩展输出中出现未在
options.
中指定的值。证明对象必须准备处理这些情况,无论是忽略未请求的扩展还是拒绝声明,证明对象可以基于本地政策和所使用的扩展作出决定。扩展
注意: 由于扩展对于客户端和认证器都是可选的,因此证明对象也必须准备处理没有执行任何或所有请求扩展的情况。
-
将hash设为对cData使用SHA-256计算的哈希结果。
-
使用credentialPublicKey验证sig是否为authData和hash二进制连接的有效签名。
注意: 此验证步骤与FIDO U2F认证器生成的签名兼容。参见§ 6.1.2 FIDO U2F签名格式兼容性。
-
将storedSignCount设为与
credential.
关联的存储签名计数器值。如果authData.id
signCount
为非零或storedSignCount为非零,则运行以下子步骤: -
如果以上所有步骤均成功,则根据需要继续进行认证仪式。否则,认证仪式失败。
8. 定义的证明声明格式
WebAuthn 支持可插拔的证明声明格式。本节定义了一组初始的此类格式。
8.1. 证明声明格式标识符
证明声明格式通过一个字符串标识,称为证明声明格式标识符,由证明声明格式的作者选择。
证明声明格式标识符应在 IANA 的 "WebAuthn 证明声明格式标识符" 注册表中注册 [IANA-WebAuthn-Registries],该注册表由[RFC8809]建立。 所有注册的证明声明格式标识符彼此之间都是唯一的。
未注册的证明声明格式标识符应使用小写的反向域名命名,使用 开发人员注册的域名,以确保标识符的唯一性。所有证明声明格式标识符必须 最多为32个八位字节,且只能包含可打印的USASCII字符,不包括反斜杠和双引号, 即,在[RFC5234]中定义的VCHAR,但不包括 %x22 和 %x5c。
注意:这意味着基于域名的证明声明格式标识符必须仅包含LDH标签[RFC5890]。
实现必须区分大小写地匹配 WebAuthn 证明声明格式标识符。
可能存在多个版本的证明声明格式应在其标识符中包含一个版本。实际上,
不同的版本因此被视为不同的格式,例如packed2
作为
§ 8.2 打包证明声明格式的新版本。
以下各节展示了一组当前定义和注册的证明声明格式及其标识符。 注册的WebAuthn 扩展的最新列表由 IANA 的 "WebAuthn 证明声明格式标识符" 注册表维护 [IANA-WebAuthn-Registries],该注册表由[RFC8809]建立。
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表示序列化客户端数据的哈希值。
-
如果使用基本或AttCA 证明, 验证器通过连接authenticatorData 和clientDataHash来生成sig,并使用通过验证器特定机制选择的证明私钥对结果进行签名。它将x5c设置为attestnCert,后面跟随相关的 证书链(如果有)。它将alg设置为 证明私钥的算法。
-
如果使用自我证明,验证器通过连接authenticatorData和clientDataHash来生成sig, 并使用凭证私钥对结果进行签名。它将alg设置为 凭证私钥的算法,并省略其他字段。
-
- 验证过程
-
给定验证过程的输入 attStmt, authenticatorData 和 clientDataHash,验证过程 如下:
-
验证attStmt是否为符合上述语法定义的有效CBOR,并对其执行CBOR解码以提取 包含的字段。
-
如果x5c存在:
-
验证sig是否是使用 alg中指定的算法,通过attestnCert中的证明公钥对 authenticatorData和clientDataHash的连接进行签名的有效签名。
-
验证attestnCert是否符合§ 8.2.1 打包证明声明 证书要求中的要求。
-
如果attestnCert包含OID为
1.3.6.1.4.1.45724.1.1.4
(id-fido-gen-ce-aaguid
)的扩展,验证 该 扩展的值是否与aaguid
中的值一致authenticatorData。
-
-
如果x5c不存在,则使用自我证明。
-
验证alg是否与authenticatorData中的
credentialPublicKey
的算法匹配。 -
验证sig是否是使用alg的算法,通过凭证公钥对 authenticatorData和clientDataHash的连接进行签名的有效签名。
-
-
8.2.1. 打包证明声明证书要求
证明证书必须具有以下字段/扩展:
-
版本必须设置为3(由值为2的ASN.1整数表示)。
-
主题字段必须设置为:
- 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
)必须存在, 包含AAGUID作为16字节的OCTET STRING。 该扩展不能标记为关键。请注意,X.509扩展将值的DER编码编码在OCTET STRING中。 因此,AAGUID必须被包裹在两个 OCTET STRING中以使其有效。以下是一个示例, 编码的 扩展结构:
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
。 -
可选的Authority Information Access(AIA)扩展项
id-ad-ocsp
和 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
-
aikCert后面是其证书链,以X.509编码。
- aikCert
-
用于证明的AIK证书,以X.509编码。
- sig
-
证明签名,形式为 TPMT_SIGNATURE 结构,如[TPMv2-Part2]第11.3.4节中所规定。
- certInfo
-
TPMS_ATTEST结构,其中包含上面生成的签名,如[TPMv2-Part2]第 10.12.8节中规定。
- pubArea
-
TPMT_PUBLIC结构(见[TPMv2-Part2]第12.2.4节),由TPM用于 表示凭证公钥。
- 签名过程
-
令authenticatorData表示证明的验证器数据, 令clientDataHash表示序列化客户端数据的哈希值。
将authenticatorData与clientDataHash连接 形成 attToBeSigned。
使用[TPMv2-Part3]第18.2节中规定的过程生成签名, 使用证明私钥 并将
extraData
参数设置为使用"alg"签名算法的哈希算法生成的attToBeSigned摘要。 (对于"RS256"算法,这将是SHA-256摘要。)将pubArea字段设置为凭证公钥的公共区域,将 certInfo字段设置为相同名称的 输出参数,并将sig字段设置为从上述过程获得的签名。
- 验证过程
-
给定验证过程的输入 attStmt, authenticatorData 和 clientDataHash,验证过程如下:
验证attStmt是否为符合上述语法定义的有效CBOR,并对其执行 CBOR解码以提取 包含的字段。
验证由
parameters
和unique
字段指定的 公钥是否与credentialPublicKey
中的公钥一致attestedCredentialData
在 authenticatorData中。将authenticatorData与clientDataHash连接形成 attToBeSigned。
验证certInfo是否有效:
-
验证
magic
是否设置为TPM_GENERATED_VALUE
。 -
验证
type
是否设置为TPM_ST_ATTEST_CERTIFY
。 -
验证
extraData
是否设置为使用"alg"中使用的哈希算法生成的 attToBeSigned的哈希值。 -
验证
attested
是否包含TPMS_CERTIFY_INFO
结构,如[TPMv2-Part2]第 10.12.3节中规定, 其name
字段包含pubArea的有效名称, 如使用pubArea中的nameAlg
字段指定的算法,使用[TPMv2-Part1]第16节中规定的过程生成的有效名称。 -
验证x5c是否存在。
-
请注意"标准证明结构"中的其余字段[TPMv2-Part1]第31.2节中, 即
qualifiedSigner
、clockInfo
和firmwareVersion
被忽略。 这些字段可以用作风险引擎的输入。 -
验证sig是否为certInfo上的有效签名,使用 证明 公钥aikCert,并使用 alg中指定的算法。
-
验证aikCert是否符合§ 8.3.1 TPM 证明声明证书 要求中的要求。
-
如果aikCert包含OID为
1.3.6.1.4.1.45724.1.1.4
的扩展 (id-fido-gen-ce-aaguid
),验证该扩展的值是否与aaguid
中 authenticatorData的一致。
-
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
。 -
权威信息访问(AIA)扩展包含
id-ad-ocsp
条目和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)
请求Android密钥证明,提供clientDataHash作为挑战值(例如,通过使用setAttestationChallenge)。将x5c设置为返回值。认证器通过连接authenticatorData和clientDataHash生成sig,并使用凭据私钥对结果进行签名。它将alg设置为签名格式的算法。
- 验证过程
-
给定验证过程输入attStmt,authenticatorData和clientDataHash,验证过程如下:
-
验证attStmt是符合上述语法定义的有效CBOR,并对其进行CBOR解码以提取包含的字段。
-
验证sig是对连接authenticatorData和clientDataHash的结果使用x5c中第一个证书中的公钥及alg指定的算法进行的有效签名。
-
验证x5c中第一个证书中的公钥与authenticatorData中的凭据公钥一致。
-
验证证明证书扩展数据中的
attestationChallenge
字段与clientDataHash一致。 -
使用证明证书扩展数据中的授权列表验证以下内容:
-
AuthorizationList.allApplications
字段不应出现在任何一个授权列表中(softwareEnforced
和teeEnforced
),因为PublicKeyCredential必须与RP ID相关联。 -
如果RP只接受来自可信执行环境的密钥,则仅使用
teeEnforced
授权列表,否则使用teeEnforced
和softwareEnforced
的并集。-
AuthorizationList.origin
字段的值应等于KM_ORIGIN_GENERATED
。 -
AuthorizationList.purpose
字段的值应等于KM_PURPOSE_SIGN
。
-
-
-
如果成功,返回表示证明类型基础和证明信任路径x5c的实现特定值。
-
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
-
UTF-8编码的SafetyNet API的getJwsResult()调用结果。该值是一个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服务。
-
如果成功,返回表示证明类型基础和证明信任路径x5c的实现特定值。
-
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节)转换为Raw ANSI X9.62公钥格式(参见[FIDO-Registry]的第3.6.2节公钥表示格式)。
-
将对应于credentialPublicKey中“-2”键(表示x坐标)的值设为x,并确认其大小为32字节。如果大小不同或找不到“-2”键,终止此算法并返回相应的错误。
-
将对应于credentialPublicKey中“-3”键(表示y坐标)的值设为y,并确认其大小为32字节。如果大小不同或找不到“-3”键,终止此算法并返回相应的错误。
-
将publicKeyU2F设为
0x04 || x || y
的连接。注意:这表示未压缩的ECC密钥格式。
-
-
将verificationData设为(0x00 || rpIdHash || clientDataHash || credentialId || publicKeyU2F)的连接(参见[FIDO-U2F-Message-Formats]第4.3节)。
-
按照[SEC1]第4.1.4节的要求,使用SHA-256作为第二步中的哈希函数,使用certificate public key对verificationData进行sig验证。
-
8.7. 无证明声明格式
无证明声明格式用于替换任何认证器提供的证明声明,当WebAuthn依赖方表示不希望接收证明信息时,参见§ 5.4.7 证明传递偏好枚举(enum AttestationConveyancePreference)。
如果认证器不支持证明,认证器也可以直接生成这种格式的证明声明。
- 证明声明格式标识符
-
none
- 支持的证明类型
- 语法
-
无证明声明的语法定义如下:
$$attStmtType //= ( fmt: "none", attStmt: emptyMap ) emptyMap = {}
- 签名过程
-
返回上面定义的固定证明声明。
- 验证过程
8.8. 苹果匿名证明声明格式
此证明声明格式专为支持WebAuthn的某些类型的苹果设备使用。
- 证明声明格式标识符
-
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。
-
让苹果匿名证明CA生成一个用于凭证公钥的X.509证书,并将nonce作为OID为
1.2.840.113635.100.8.2
的证书扩展名包含在内。credCert表示此证书。credCert因此作为证明的证明,并且包含的nonce证明证明是实时的。此外,nonce还保护了authenticatorData和客户端数据的完整性。 -
将x5c设置为credCert及其证书链。
-
- 验证过程
-
给定验证过程输入attStmt、authenticatorData和clientDataHash,验证过程如下:
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整数,如果认证器希望扩展在没有实际客户端支持的情况下始终有效。当使用的浮点值恰好是整数时,这将发生。
同样,当客户端接收到它们不识别的扩展传递的输出时,认证器扩展输出中的CBOR值将转换为客户端扩展输出中的JavaScript值。当CBOR值是字节字符串时,它将转换为JavaScript %ArrayBuffer%(而不是base64url编码的字符串)。否则,当CBOR类型对应于JSON类型时,转换将使用[RFC8949]第6.1节中定义的规则进行(从CBOR到JSON的转换),但产生JavaScript类型值的输出,而不是JSON类型值的输出。
请注意,某些客户端可能会选择在功能标志下实现这种传递能力。支持这种能力可以促进创新,允许认证器在客户端明确支持它们之前尝试新扩展,并允许依赖方使用它们。
IANA "WebAuthn扩展标识符"注册表[IANA-WebAuthn-Registries]由[RFC8809]建立,可以查询最新的注册WebAuthn扩展列表。
9.1. 扩展标识符
扩展通过一个字符串来标识,这个字符串称为扩展标识符,由扩展作者选择。
扩展标识符应注册在由[RFC8809]建立的IANA "WebAuthn扩展标识符"注册表中[IANA-WebAuthn-Registries]。所有注册的扩展标识符在它们之间是唯一的。
未注册的扩展标识符应尽量确保全局唯一,例如,通过包括定义实体如myCompany_extension
。
所有扩展标识符必须最长为32个八位字节,并且只能包含可打印的USASCII字符,排除反斜杠和双引号,即[RFC5234]中定义的VCHAR,但不包括%x22和%x5c。实现必须以区分大小写的方式匹配WebAuthn扩展标识符。
可能存在多个版本的扩展应注意在其标识符中包括一个版本。实际上,不同版本因此被视为不同的扩展,例如myCompany_extension_01
§ 10 定义的扩展定义了一组附加的扩展及其标识符。有关已注册WebAuthn扩展标识符的最新列表,请参阅IANA "WebAuthn扩展标识符"注册表[IANA-WebAuthn-Registries],由[RFC8809]建立。
9.2. 定义扩展
扩展的定义必须指定一个扩展标识符,一个通过get()
或create()
调用发送的客户端扩展输入参数,客户端扩展处理规则以及一个客户端扩展输出值。如果扩展与认证器通信(即它是一个认证器扩展),它还必须指定通过authenticatorGetAssertion或authenticatorMakeCredential调用发送的CBOR 认证器扩展输入参数,认证器扩展处理规则以及CBOR 认证器扩展输出值。
任何由客户端处理的客户端扩展必须返回一个客户端扩展输出值,以便WebAuthn依赖方知道客户端处理了该扩展。同样,任何需要认证器处理的扩展必须返回一个认证器扩展输出,以便依赖方知道认证器处理了该扩展。如果一个扩展不需要其他结果值,则应定义为返回一个JSON布尔型客户端扩展输出结果,设置为true
以表示该扩展已被理解并处理。同样,任何不需要其他结果值的认证器扩展必须返回一个值,并且应返回一个CBOR布尔型认证器扩展输出结果,设置为true
以表示该扩展已被理解并处理。
9.3. 扩展请求参数
扩展定义一个或两个请求参数。客户端扩展输入是一个可以编码为JSON的值,从WebAuthn依赖方传递给客户端的get()
或create()
调用中,而CBOR
认证器扩展输入在这些调用的处理过程中从客户端传递给认证器用于认证器扩展。
依赖方通过在extensions
选项中包括一个条目同时请求使用扩展并设置其客户端扩展输入。条目键是扩展标识符,值是客户端扩展输入。
注意: 其他文档已指定扩展,其中扩展输入不总是使用扩展标识符作为条目键。新的扩展应遵循上述约定。
var assertionPromise= navigator. credentials. get({ publicKey: { // 其他成员为了简洁省略 extensions: { // 标识"webauthnExample_foobar"扩展的“条目键”, // 其值是一个包含两个输入参数的映射: "webauthnExample_foobar" : { foo: 42 , bar: "barfoo" } } } });
扩展定义必须指定其客户端扩展输入的有效值。客户端应忽略具有无效客户端扩展输入的扩展。如果扩展不需要来自依赖方的任何参数,它应定义为接收布尔型客户端参数,设置为true
以表示依赖方请求了该扩展。
仅影响客户端处理的扩展不需要指定认证器扩展输入。具有认证器处理的扩展必须指定从客户端扩展输入计算认证器扩展输入的方法,并且必须定义用于CDDL类型的扩展,通过使用扩展标识符作为条目键为$$extensionInput
和$$extensionOutput
组套件定义一个附加的选择。定义为接收布尔型客户端扩展输入值并设置为true
的扩展应同样将认证器扩展输入定义为常量布尔值true
(CBOR主要类型7,值21)。
以下示例定义了一个标识符为webauthnExample_foobar
的扩展,它接收一个无符号整数作为认证器扩展输入,并返回至少一个字节字符串的数组作为认证器扩展输出:
$$extensionInput //= ( webauthnExample_foobar: uint ) $$extensionOutput //= ( webauthnExample_foobar: [+ bytes] )
注意: 扩展应尽量定义尽可能小的认证器参数。一些认证器通过低带宽的链接通信,如蓝牙低能量或NFC。
9.4. 客户端扩展处理
扩展可以定义在创建凭据或生成断言期间对客户端的附加处理要求。扩展的客户端扩展输入用作此客户端处理的输入。对于每个支持的客户端扩展,客户端将扩展标识符作为键,扩展的客户端扩展输入作为值,添加一个条目到clientExtensions地图。
同样,客户端扩展输出在getClientExtensionResults()
的结果中表示为一个字典,其中扩展标识符作为键,扩展的客户端扩展输出值作为值。与客户端扩展输入一样,客户端扩展输出是一个可以编码为JSON的值。对于忽略的扩展,不得返回任何值。
需要认证器处理的扩展必须定义从客户端扩展输入确定CBOR 认证器扩展输入的过程以及从CBOR 认证器扩展输出确定客户端扩展输出的过程。
9.5. 认证器扩展处理
每个处理的认证器扩展的认证器扩展输入值都包含在authenticatorMakeCredential和authenticatorGetAssertion操作的extensions参数中。extensions参数是一个CBOR映射,其中每个键是一个扩展标识符,相应的值是该扩展的认证器扩展输入。
同样,扩展输出在扩展部分的认证器数据中表示。认证器数据的extensions部分是一个CBOR映射,其中每个键是一个扩展标识符,相应的值是该扩展的认证器扩展输出。
对于每个支持的扩展,使用该扩展的认证器扩展处理规则从认证器扩展输入以及可能的其他输入中创建认证器扩展输出。对于被忽略的扩展,不得返回任何值。
10. 定义的扩展
本节定义了一组要在IANA "WebAuthn Extension Identifiers"注册表[IANA-WebAuthn-Registries]中注册的附加扩展,由[RFC8809]建立。 这些扩展可以由目标为广泛互操作性的用户代理实现。
10.1. FIDO AppID 扩展(appid)
该扩展允许先前使用传统FIDO U2F JavaScript API [FIDOU2FJavaScriptAPI]注册凭据的WebAuthn依赖方请求声明。 FIDO API使用替代标识符作为依赖方,称为AppID [FIDO-APPID],并且使用这些API创建的任何凭据将被限定到该标识符。 如果没有此扩展,它们将需要重新注册以便限定到RP ID。
除了设置appid
扩展输入外,
使用此扩展需要依赖方进行一些额外处理,以便允许用户使用其注册的U2F凭据进行身份验证:
-
在
allowCredentials
选项中列出所需的U2F凭据 在get()
方法中:-
将
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。
这可能与将依赖方的WebAuthnRP ID转换为AppID格式的结果不同,
例如,以前使用的AppID可能是“https://accounts.example.com”,
但当前使用的RP ID可能是“example.com”。
- 扩展标识符
-
appid
- 操作适用性
- 客户端扩展输入
-
指定FIDO AppID的单个USVString。
partial dictionary AuthenticationExtensionsClientInputs {USVString
; };appid - 客户端扩展处理
-
-
让facetId成为将调用者的来源传递到 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的值。如果为true,则使用了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成为将调用者的来源传递给 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 创建的,该消息的“5个部分”设置为以下值: -
如果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, )
- 认证器扩展处理
-
认证器将认证器扩展输出设置为一个或多个用户验证方法,指示用户用于授权操作的方法,如下定义。此扩展可以添加到证明对象和断言中。
- 认证器扩展输出
-
认证器可以报告在单次身份验证实例中使用的最多 3 种不同的用户验证方法(因素),使用以下定义的 CBOR 语法:
$$extensionOutput //= ( uvm: [ 1*3 uvmEntry ], ) uvmEntry = [ userVerificationMethod: uint .size 4, keyProtectionType: uint .size 2, matcherProtectionType: uint .size 2 ]
每个
uvmEntry
中字段的语义如下:- userVerificationMethod
-
认证器用于验证用户的身份验证方法/因素。可用值在第 3.1 节 用户验证方法中定义[FIDO-Registry]。
- keyProtectionType
-
认证器用于保护 FIDO 注册私钥材料的方法。可用值在第 3.2 节 密钥保护类型中定义[FIDO-Registry]。
- matcherProtectionType
-
认证器用于保护执行用户验证的匹配器的方法。可用值在第 3.3 节 匹配器保护类型中定义[FIDO-Registry]。
如果在一次身份验证实例中可以使用超过 3 种因素,认证器供应商必须选择其认为最相关的 3 种因素以包括在 UVM 中。
包含一个 UVM 扩展的认证器数据示例,适用于使用了 2 种因素的多因素身份验证实例:
... -- RP ID 哈希(32 字节) 81 -- 设置了 UP 和 ED 00 00 00 01 -- (初始)签名计数器 ... -- 所有公钥算法等。 A1 -- 扩展:一个元素的 CBOR 映射 63 -- 键 1:3 字节的 CBOR 文本字符串 75 76 6d -- "uvm" [=UTF-8 编码=] 字符串 82 -- 值 1:长度为 2 的 CBOR 数组,表示使用了两种因素 83 -- 项 1:长度为 3 的 CBOR 数组 02 -- 子项 1:用于用户验证方法指纹的 CBOR 整数 04 -- 子项 2:用于密钥保护类型 TEE 的 CBOR 短整数 02 -- 子项 3:用于匹配器保护类型 TEE 的 CBOR 短整数 83 -- 项 2:长度为 3 的 CBOR 数组 04 -- 子项 1:用于用户验证方法密码的 CBOR 整数 01 -- 子项 2:用于密钥保护类型软件的 CBOR 短整数 01 -- 子项 3:用于匹配器保护类型软件的 CBOR 短整数
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. 大数据块存储扩展 (largeBlob)
此客户端注册扩展和身份验证扩展允许依赖方存储与凭据关联的不透明数据。由于认证器只能存储少量数据,而大多数依赖方是可以为用户存储任意状态的在线服务,这仅在特定情况下有用。例如,依赖方可能希望颁发证书,而不是运行集中式身份验证服务。
注意:依赖方可以假设在写入空间有限的设备时,不透明数据将被压缩,因此无需自行压缩。
由于证书系统需要签署凭据的公钥,而该公钥仅在创建后可用,因此此扩展不会增加在注册上下文中写入数据块的能力。然而,如果依赖方希望稍后使用身份验证扩展,依赖方应在创建凭据时使用注册扩展。
由于证书相对于典型认证器的存储能力较大,用户代理应考虑合适的指示和确认,以最好地指导用户分配这一有限资源并防止滥用。
注意:为了实现互操作性,用户代理在使用[FIDO-CTAP]的认证器上存储大数据块时,应使用该规范中详细说明的用于存储大数据块的条款。
- 扩展标识符
-
largeBlob
- 操作适用性
- 客户端扩展输入
-
partial dictionary AuthenticationExtensionsClientInputs {AuthenticationExtensionsLargeBlobInputs
; };largeBlob enum
{LargeBlobSupport
,"required"
, };"preferred" dictionary
{AuthenticationExtensionsLargeBlobInputs DOMString support ;boolean read ;BufferSource write ; };support
, 类型 DOMString-
一个 DOMString,取
LargeBlobSupport
的值之一。 (参见§ 2.1.1 DOMString 类型的枚举。)仅在注册期间有效。 read
, 类型 booleanwrite
, 类型 BufferSource
- 客户端扩展处理 (注册)
-
-
-
返回一个
DOMException
,其名称为“NotSupportedError
”。
-
-
-
将
supported
设置为true
。注意:这是为了预期能够存储大数据块的认证器可用的情况。它发生在
[[Create]]()
的步骤 11 中的扩展处理期间。如果没有可用的满意认证器,AuthenticationExtensionsLargeBlobOutputs
将被放弃。
-
-
- 客户端扩展处理 (身份验证)
-
-
如果
support
存在:-
返回一个
DOMException
,其名称为“NotSupportedError
”。
-
-
-
返回一个
DOMException
,其名称为“NotSupportedError
”。
-
-
如果
read
存在且值为true
:-
如果任何认证器指示成功(在
[[DiscoverFromExternalSource]]()
),尝试读取与断言的凭据关联的任何largeBlob数据。 -
如果成功,将
blob
设置为结果。注意:如果读取不成功,
largeBlob
将在AuthenticationExtensionsClientOutputs
中存在,但blob
成员将不存在。
-
如果
write
存在:-
如果
allowCredentials
不包含完全一项:-
返回一个
DOMException
,其名称为“NotSupportedError
”。
-
-
如果成功,将
written
设置为true
,否则设置为false
。
-
-
- 客户端扩展输出
-
partial dictionary AuthenticationExtensionsClientOutputs {AuthenticationExtensionsLargeBlobOutputs
; };largeBlob dictionary
{AuthenticationExtensionsLargeBlobOutputs boolean supported ;ArrayBuffer blob ;boolean written ; }; - 认证器扩展处理
11. 用户代理自动化
为了用户代理自动化和web应用程序测试,本文件定义了一些[WebDriver] 扩展命令。
11.1. WebAuthn WebDriver 扩展功能
为了宣传下面定义的扩展命令的可用性,定义了一个新的扩展功能。
当验证功能时,验证"webauthn:virtualAuthenticators"
和value
的特定扩展步骤如下:
-
如果
value
不是boolean,返回WebDriver错误,并附带WebDriver错误代码 无效参数。 -
否则,将
deserialized
设置为value
。
当匹配功能时,匹配"webauthn:virtualAuthenticators"
和value
的特定扩展步骤如下:
11.1.1. 认证器扩展功能
此外,为本规范中定义的每个认证器扩展(即那些定义了认证器扩展处理的扩展)定义了扩展功能:
功能 | 键 | 值类型 | 描述 |
---|---|---|---|
用户验证方法扩展支持 | "webauthn:extension:uvm"
| boolean | 指示端点节点 WebAuthn WebDriver实现是否支持用户验证方法扩展。 |
大数据存储扩展支持 | "webauthn:extension:largeBlob"
| boolean | 指示端点节点 WebAuthn WebDriver实现是否支持largeBlob 扩展。 |
当验证功能时,验证认证器扩展功能key
和value
的特定扩展步骤如下:
-
如果
value
不是boolean,返回WebDriver错误,并附带WebDriver错误代码 无效参数。 -
否则,将
deserialized
设置为value
。
当匹配
功能时,匹配认证器扩展功能key
和value
的特定扩展步骤如下:
11.2. 虚拟验证器
这些WebDriver 扩展命令 用来创建和交互 虚拟验证器:验证器模型 的软件实现。虚拟验证器 存储在 虚拟验证器数据库 中。 每个存储的虚拟验证器 具有以下属性:
- 验证器ID
- protocol
-
虚拟验证器 支持的协议之一:
"ctap1/u2f"
,"ctap2"
或"ctap2_1"
[FIDO-CTAP]。 - transport
- 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
|
验证器配置 是一个 JSON 对象,通过 远程端步骤 作为参数传递。它包含以下键和 值 对:
键 | 值类型 | 有效值 | 默认值 |
---|---|---|---|
protocol | 字符串 | "ctap1/u2f" , "ctap2" , "ctap2_1"
| 无 |
transport | 字符串 | 验证器传输
值
| 无 |
hasResidentKey | 布尔值 | true , false
| false
|
hasUserVerification | 布尔值 | true , false
| false
|
isUserConsenting | 布尔值 | true , false
| true
|
isUserVerified | 布尔值 | true , false
| false
|
extensions | 字符串数组 | 包含 扩展标识符 的数组 | 空数组 |
uvm | UvmEntries
| 最多包含3个 用户验证方法 条目 | 空数组 |
远程端步骤 如下:
-
如果 parameters 不是 JSON 对象,返回一个 WebDriver 错误,错误代码为 WebDriver 错误代码 无效参数。
注意: parameters 是一个 验证器配置 对象。
-
令 authenticator 为新的 虚拟验证器。
-
对于 parameters 中的每个可枚举 自有属性:
-
令 key 为属性名称。
-
令 value 为 获取属性 parameters 中名为 key 的属性的结果。
-
如果 parameters 中没有与 key 匹配的
key
,返回 WebDriver 错误,错误代码为 WebDriver 错误代码 无效参数。 -
如果 value 不是该 key 的
有效值
之一,返回 WebDriver 错误,错误代码为 WebDriver 错误代码 无效参数。 -
设置属性 key 为 authenticator 上的 value。
-
-
对于 验证器配置 中定义了默认值的每个属性:
-
如果 authenticator 没有定义的
key
属性,设置属性key
为 authenticator 上的default
。
-
-
对于 验证器配置 中的每个属性:
-
如果 authenticator 没有定义的
key
属性,返回 WebDriver 错误,错误代码为 WebDriver 错误代码 无效参数。
-
-
对于 authenticator.extensions 中的每个 extension:
-
如果 extension 不是由 扩展标识符 支持的 端点节点 WebAuthn WebDriver 实现,返回 WebDriver 错误,错误代码为 WebDriver 错误代码 不支持的操作。
-
-
生成有效唯一的 authenticatorId。
-
设置属性
authenticatorId
为 authenticator 上的 authenticatorId。 -
将 authenticator 存储在 虚拟验证器数据库 中。
-
返回 成功,数据为 authenticatorId。
11.4. 移除虚拟验证器
移除虚拟验证器 WebDriver 扩展命令 移除先前创建的 虚拟验证器。 定义如下:
HTTP 方法 | URI 模板 |
---|---|
DELETE | /session/{session id}/webauthn/authenticator/{authenticatorId}
|
远程端步骤如下:
-
如果 authenticatorId 不匹配存储在 虚拟验证器中的任何记录, 返回 WebDriver 错误,并附带 WebDriver 错误代码 无效参数。
-
从 虚拟验证器数据库中移除由 authenticatorId标识的虚拟验证器条目。
-
返回 成功。
11.5. 添加凭证
添加凭证 WebDriver 扩展命令 将 公钥凭证来源 注入到现有的 虚拟验证器中。定义如下:
HTTP 方法 | URI 模板 |
---|---|
POST | /session/{session id}/webauthn/authenticator/{authenticatorId}/credential
|
凭证参数 是一个 JSON 对象,作为 parameters 传递给 远程端步骤。它包含以下 key 和 value 对:
键 | 描述 | 值类型 |
---|---|---|
credentialId | 使用 凭证 ID编码,采用 Base64url 编码。 | 字符串 |
isResidentCredential | 如果设置为 true ,则创建 客户端可发现凭证。
如果设置为 false ,则创建 服务器端凭证。
| 布尔值 |
rpId | 凭证范围内的 依赖方 ID。 | 字符串 |
privateKey | 一个包含单个 私钥的非对称密钥包,符合 [RFC5958],使用 Base64url 编码。 | 字符串 |
userHandle | 与凭证关联的 userHandle,使用 Base64url 编码。 此属性可能未定义。 | 字符串 |
signCount | 与 签名计数器 关联的初始值,用于 公钥凭证来源。 | 数字 |
largeBlob | 与 每个凭证的大块 blob 关联,采用 Base64url 编码。 此属性可能未定义。 | 字符串 |
远程端步骤如下:
-
如果 parameters 不是 JSON 对象, 返回 WebDriver 错误, 并附带 WebDriver 错误代码 无效参数。
注意: parameters 是一个 凭证参数 对象。
-
让 credentialId 成为使用 Base64url 编码 对 parameters 的 credentialId 属性进行解码的结果。
-
如果 credentialId 解码失败,返回 WebDriver 错误, 并附带 WebDriver 错误代码 无效参数。
-
让 isResidentCredential 成为 parameters 的 isResidentCredential 属性。
-
如果 isResidentCredential 未定义,返回 WebDriver 错误, 并附带 WebDriver 错误代码 无效参数。
-
让 rpId 成为 parameters 的 rpId 属性。
-
如果 rpId 不是有效的 RP ID, 返回 WebDriver 错误, 并附带 WebDriver 错误代码 无效参数。
-
让 privateKey 成为使用 Base64url 编码 对 parameters 的 privateKey 属性进行解码的结果。
-
如果 privateKey 解码失败,返回 WebDriver 错误, 并附带 WebDriver 错误代码 无效参数。
-
如果 privateKey 不是包含单个 ECDSA 私钥的有效编码的非对称密钥包,符合 [RFC5958] 的 P-256 曲线标准, 返回 WebDriver 错误, 并附带 WebDriver 错误代码 无效参数。
-
如果 parameters 的 userHandle 属性已定义:
-
让 userHandle 成为使用 Base64url 编码 对 parameters 的 userHandle 属性进行解码的结果。
-
如果 userHandle 解码失败,返回 WebDriver 错误, 并附带 WebDriver 错误代码 无效参数。
-
-
否则:
-
如果 isResidentCredential 为
true
,返回 WebDriver 错误, 并附带 WebDriver 错误代码 无效参数。 -
让 userHandle 为
null
。
-
-
如果 authenticatorId 不匹配存储在 虚拟验证器中的任何记录, 返回 WebDriver 错误, 并附带 WebDriver 错误代码 无效参数。
-
让 authenticator 成为与 authenticatorId 匹配的 虚拟验证器。
-
如果 isResidentCredential 为
true
,且 authenticator 的 hasResidentKey 属性为false
, 返回 WebDriver 错误, 并附带 WebDriver 错误代码 无效参数。 -
如果 authenticator 支持 largeBlob 扩展,并且 parameters 的 largeBlob 特性已定义:
-
让 largeBlob 成为使用 Base64url 编码 对 parameters 的 largeBlob 属性进行解码的结果。
-
如果 largeBlob 解码失败,返回 WebDriver 错误, 并附带 WebDriver 错误代码 无效参数。
-
-
否则:
-
让 largeBlob 为
null
。
-
-
让 credential 成为一个新的 客户端可发现的公钥凭证来源, 如果 isResidentCredential 为
true
,否则让其成为 服务器端公钥凭证来源, 其项包括:- 类型
- id
-
credentialId
- privateKey
-
privateKey
- rpId
-
rpId
- userHandle
-
userHandle
-
将一个与 credential 关联的 签名计数器 counter, 其初始值等于 parameters 的 signCount, 如果 signCount 为
null
,则默认为0
。 -
如果 largeBlob 不为
null
, 将与 credential 关联的 大块 blob 设置为 largeBlob。 -
将 credential 和 counter 存储在 authenticator 的数据库中。
-
返回 成功。
11.6. 获取凭证
获取凭证 WebDriver 扩展命令 返回每个存储在虚拟验证器中的凭证参数对象,无论它们是通过添加凭证还是通过navigator.credentials.create()
存储的。
定义如下:
HTTP 方法 | URI 模板 |
---|---|
GET | /session/{session id}/webauthn/authenticator/{authenticatorId}/credentials
|
远程端步骤如下:
-
如果 authenticatorId 不匹配存储在 虚拟验证器中的任何记录, 返回 WebDriver 错误, 并附带 WebDriver 错误代码 无效参数。
-
让 credentialsArray 成为空数组。
-
对于由 authenticatorId 标识的验证器管理的每个 公钥凭证来源 credential, 构造一个对应的凭证参数 对象并将其添加到 credentialsArray 中。
-
返回包含 credentialsArray 的数据的成功。
11.7. 移除凭证
移除凭证 WebDriver 扩展命令 移除存储在 虚拟验证器上的公钥凭证来源。定义如下:
HTTP 方法 | URI 模板 |
---|---|
DELETE | /session/{session id}/webauthn/authenticator/{authenticatorId}/credentials/{credentialId}
|
远程端步骤如下:
-
如果 authenticatorId 不匹配存储在 虚拟验证器中的任何记录, 返回 WebDriver 错误, 并附带 WebDriver 错误代码 无效参数。
-
让 authenticator 成为由 authenticatorId 标识的 虚拟验证器。
-
如果 credentialId 不匹配 authenticator 管理的任何公钥凭证来源, 返回 WebDriver 错误, 并附带 WebDriver 错误代码 无效参数。
-
移除由 credentialId 标识并由 authenticator 管理的公钥凭证来源。
-
返回 成功。
11.8. 移除所有凭证
移除所有凭证 WebDriver 扩展命令 移除存储在 虚拟验证器上的所有公钥凭证来源。定义如下:
HTTP 方法 | URI 模板 |
---|---|
DELETE | /session/{session id}/webauthn/authenticator/{authenticatorId}/credentials
|
远程端步骤如下:
-
如果 authenticatorId 不匹配存储在 虚拟验证器中的任何记录, 返回 WebDriver 错误, 并附带 WebDriver 错误代码 无效参数。
-
返回 成功。
11.9. 设置用户已验证
设置用户已验证 扩展命令 设置虚拟验证器上的 isUserVerified 属性。定义如下:
HTTP 方法 | URI 模板 |
---|---|
POST | /session/{session id}/webauthn/authenticator/{authenticatorId}/uv
|
远程端步骤如下:
-
如果 parameters 不是 JSON 对象,返回 WebDriver 错误 并附带 WebDriver 错误代码 无效参数。
-
如果 authenticatorId 不匹配存储在 虚拟验证器中的任何记录, 返回 WebDriver 错误, 并附带 WebDriver 错误代码 无效参数。
-
如果 parameters 中没有定义 isUserVerified 属性,返回 WebDriver 错误, 并附带 WebDriver 错误代码 无效参数。
-
让 authenticator 成为由 authenticatorId 标识的 虚拟验证器。
-
将 authenticator 的 isUserVerified 属性设置为 parameters 中的 isUserVerified 属性。
-
返回 成功。
12. IANA 考虑
12.1. WebAuthn Attestation 声明格式标识符注册更新
本节更新了在 IANA "WebAuthn Attestation 声明格式标识符" 注册表中定义的以下列举的声明格式(详见§ 8 定义的声明格式),并指向此规范。此注册表由 [RFC8809] 创建,最初注册于 [WebAuthn-1]。
-
WebAuthn Attestation 声明格式标识符:packed
-
描述:“packed” 声明格式是一种针对 声明 的 WebAuthn 优化格式。它使用了一种非常紧凑但仍可扩展的编码方法。此格式可由资源有限的验证器(例如, 安全元素)实现。
-
规范文档:本规范的 § 8.2 Packed 声明格式
-
WebAuthn Attestation 声明格式标识符:tpm
-
描述:TPM 声明格式返回的声明与 packed 声明格式相同,但 rawData 和 signature 字段的计算方式不同。
-
规范文档:本规范的 § 8.3 TPM 声明格式
-
WebAuthn Attestation 声明格式标识符:android-key
-
描述:版本 "N" 及更高版本的 平台验证器 可能会提供此专有的“硬件声明”格式。
-
规范文档:本规范的 § 8.4 Android Key 声明格式
-
WebAuthn Attestation 声明格式标识符:android-safetynet
-
描述:基于 Android 的 平台验证器 可以(MAY)生成基于 Android SafetyNet API 的声明格式。
-
规范文档:本规范的 § 8.5 Android SafetyNet 声明格式
-
WebAuthn Attestation 声明格式标识符:fido-u2f
-
描述:用于 FIDO U2F 验证器
-
规范文档:本规范的 § 8.6 FIDO U2F 声明格式
12.2. WebAuthn Attestation 声明格式标识符注册
本节在 IANA "WebAuthn Attestation 声明格式标识符" 注册表中注册以下列举的声明格式,这些格式在 § 8 定义的声明格式 中新定义,由 [RFC8809] 创建。
-
WebAuthn Attestation 声明格式标识符:apple
-
描述:用于 Apple 设备的 平台验证器
-
规范文档:本规范的 § 8.8 Apple Anonymous 声明格式
-
WebAuthn Attestation 声明格式标识符:none
-
描述:当 WebAuthn 依赖方表示不希望接收声明信息时,用于替代任何验证器提供的声明。
-
规范文档:本规范的 § 8.7 None 声明格式
12.3. WebAuthn 扩展标识符注册更新
本节更新了 IANA "WebAuthn 扩展标识符" 注册表中定义的以下列举的 扩展标识符 值(详见 § 10 定义的扩展), 该注册表由 [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 扩展标识符" 注册表中注册以下列举的 扩展标识符 值,这些值在 § 10 定义的扩展 中新定义,由 [RFC8809] 创建。
-
WebAuthn 扩展标识符:appidExclude
-
描述:此注册扩展允许 WebAuthn 依赖方 排除包含使用旧版 FIDO U2F JavaScript API [FIDOU2FJavaScriptAPI] 创建的指定凭证的验证器。
-
规范文档:本规范的 § 10.2 FIDO AppID 排除扩展 (appidExclude)
-
WebAuthn 扩展标识符:credProps
-
描述:此 客户端 注册 扩展 使得客户端能够将新创建的凭证的属性报告给调用的 WebAuthn 依赖方 的 网络应用。
-
规范文档:本规范的 § 10.4 凭证属性扩展 (credProps)
-
WebAuthn 扩展标识符:largeBlob
-
规范文档:本规范的 § 10.5 大块数据存储扩展 (largeBlob)
13. 安全性考虑
本规范定义了一个 Web API 和一个加密对等实体身份验证协议。 Web Authentication API 允许 Web 开发人员(即 "作者")在其 注册 和 身份验证 流程 中利用 Web Authentication 协议。 Web Authentication 协议端点的组成实体是用户控制的 WebAuthn 验证器 和 WebAuthn 依赖方 的计算环境,该环境托管着 依赖方 的 网络应用。 在此模型中,用户代理与 WebAuthn 客户端 一起,充当 验证器 和 依赖方 之间的中介。 此外,验证器 可以向 依赖方 证明其来源。
目前,本规范没有详细的安全性考虑。然而,[FIDOSecRef] 文档提供了一个总体适用于本规范的安全分析。 另外,[FIDOAuthnrSecReqs] 文档套件提供了关于 验证器 安全特性的有用信息。
以下小节包含当前特定于 Web Authentication 的安全性考虑。 它们按受众划分;一般的安全性考虑是本节的直接小节,而特定针对 验证器、客户端 和 依赖方 实现者的安全性考虑分组在各自的小节中。
13.1. 凭证 ID 未签名
凭证 ID 未签名。 这不是一个问题,因为如果 验证器 返回错误的 凭证 ID, 或者攻击者拦截并篡改了 凭证 ID,则 WebAuthn 依赖方 将无法查找正确的 凭证公钥 来验证返回的签名的 验证器数据 (即 断言), 于是交互将以错误告终。
13.2. 客户端和验证器之间的物理接近性
在 WebAuthn 验证器模型 中,通常假定 漫游验证器 与 客户端 物理上接近并直接通信。 这种安排有一些重要的优点。
客户端和 验证器 之间的物理接近性的保证是 所拥有的某物 身份验证因素 的关键优势。 例如,如果 漫游验证器 只能通过 USB 或蓝牙通信, 这些传输方式的有限范围确保了任何恶意行为者都必须在该范围内才能与 验证器 交互。 这不一定适用于可以远程调用的 验证器 — 即使 验证器 验证 用户在场, 用户仍然可能被欺骗,授权远程发起的恶意请求。
客户端和 验证器 之间的直接通信意味着 客户端 可以强制执行 范围 限制,以管理 凭证。 相比之下,如果 客户端 和 验证器 之间的通信由第三方中介, 则 客户端 必须信任该第三方来执行 范围 限制并控制访问 验证器。 未能做到这一点可能导致恶意的 依赖方 接收到对其他 依赖方 有效的 身份验证断言, 或者导致恶意用户获取其他用户的 身份验证断言。
如果设计一种不要求 验证器 必须与 客户端 物理接近的解决方案, 或者 客户端 和 验证器 不直接通信, 设计者应考虑这如何影响 范围 限制的执行 以及 验证器 作为 所拥有的某物 身份验证因素的强度。
13.3. 验证器 的安全性考虑
13.3.1. 证明书证书层级
推荐使用三层证明书证书层级(即证明书根、证明书颁发CA、证明书证书)。同样推荐的是,对于每个WebAuthn验证器设备线(即型号),使用单独的颁发CA,以帮助隔离特定版本验证器型号的问题。
如果证明书根证书并未专用于某一WebAuthn验证器设备线(即AAGUID),则应在证明书证书本身中指定AAGUID,以便可以对照验证器数据进行验证。
13.3.2. 证明书证书和证明书证书CA泄露
当用于签发证明书证书的中间CA或根CA遭到泄露时,尽管其证书不再可信,WebAuthn验证器 证明书密钥对仍然是安全的。WebAuthn验证器制造商可以为这些密钥从新的中间CA或新的根CA签发新的证明书证书,前提是其已记录了其证明书公钥。如果根CA发生更改,WebAuthn依赖方必须相应更新其受信任的根证书。
如果私钥已被泄露,则颁发CA必须吊销该WebAuthn验证器的证明书证书。如果泄露是由于固件漏洞造成的,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. 嵌入式使用的可见性考虑
在嵌入式环境中简化使用WebAuthn(例如,在iframe
中使用,参见§ 5.10 在iframe元素中使用Web身份验证)可能使用户容易受到UI重定向攻击,也称为“点击劫持”。这是指攻击者在依赖方的预期UI之上覆盖他们自己的UI,并试图诱使用户在依赖方执行非预期操作。例如,使用这些技术,攻击者可能能够诱使用户购买商品、转账等。
尽管WebAuthn特定的UI通常由客户端平台处理,因此不容易受到UI重定向的影响,但对于嵌入WebAuthn内容的依赖方来说,确保其内容的UI对用户可见可能非常重要。一种新兴的方法是观察实验性交叉观察者v2的isVisible
属性的状态。例如,嵌入式环境中运行的依赖方脚本可以在检测到isVisble
被设置为false
时预先加载自己到弹出窗口中,从而绕过其内容的遮挡。
13.4.3. 加密挑战
作为一种加密协议,Web身份验证依赖随机挑战来避免重放攻击。因此,PublicKeyCredentialCreationOptions
.challenge
和PublicKeyCredentialRequestOptions
.challenge
的值必须由依赖方在其信任的环境中(例如在服务器端)随机生成,并且客户端响应中的返回challenge
值必须与生成的值匹配。这应该以不依赖于客户端行为的方式进行,例如,依赖方应暂时存储挑战,直到操作完成。容忍不匹配会损害协议的安全性。
为了防止重放攻击,挑战必须包含足够的熵以使猜测它们变得不可行。因此,挑战应至少为16个字节长。
13.4.4. 证明书的局限性
本节不是规范性的。
在注册新凭证时,如果存在证明书声明,WebAuthn依赖方可以从中推导出关于各种验证器质量的保证。例如,验证器型号,或其如何存储和保护凭证私钥。然而,重要的是要注意,仅凭证明书声明,依赖方无法验证证明书对象是否由用户意图的验证器生成,而不是由中间人攻击者生成。例如,此类攻击者可以利用注入到依赖方脚本中的恶意代码。依赖方因此必须依赖其他手段,例如TLS和相关技术,来保护证明书对象免受中间人攻击。
假设完成了安全的注册流程,并且验证器保持凭证私钥的机密性,则使用该公钥凭证的后续身份验证流程对中间人攻击具有抵抗力。
上述讨论适用于所有证明书类型。在所有情况下,中间人攻击者都可能替换PublicKeyCredential
对象,包括证明书声明和要注册的凭证公钥,并随后篡改针对同一依赖方的未来身份验证声明,这些声明通过同一个攻击者进行传递并scope
。
这种攻击可能是可以检测到的;因为依赖方注册了攻击者的凭证公钥,而不是用户的凭证公钥,攻击者必须篡改该依赖方的所有后续身份验证流程:未受到攻击的流程将失败,从而可能揭示攻击。
除了自我证明和无之外的证明书类型可以增加此类攻击的难度,因为依赖方可能会向用户显示验证器信息,例如型号。攻击者因此可能需要使用与用户的验证器相同型号的真实验证器,否则用户可能会注意到依赖方报告的型号与用户预期的型号不同。
注意:上述所有描述的中间人攻击的变体对于攻击者来说比对常规密码身份验证进行的中间人攻击更难进行。
13.4.5. 被吊销的证明书证书
如果证明书证书验证因中间证明书CA证书被吊销而失败,并且依赖方的策略要求在这种情况下拒绝注册/身份验证请求,则建议依赖方还应取消注册(或将其信任级别标记为等同于“自我证明”)在CA泄露日期后使用与同一中间CA链接的证明书证书注册的公钥凭证。因此,建议依赖方在注册期间记住中间证明书CA证书,以便在吊销此类证书后取消注册相关的公钥凭证,如果该注册是在吊销此类证书后进行的。
另请参见验证器在§ 13.3.2 证明书证书和证明书证书CA泄露中的相关安全性考虑。
13.4.6. 凭证丢失和密钥移动性
本规范未定义备份凭证私钥或在验证器之间共享它们的协议。一般来说,凭证私钥永远不会离开创建它的验证器。因此,丢失验证器通常意味着丢失与丢失的验证器相关联的所有凭证,如果用户仅在依赖方注册了一个凭证,这可能会导致用户无法访问账户。与备份或共享私钥不同,Web身份验证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认证器可能具备动态生成不同证明密钥对(并请求相关的证书)的能力,按每个凭证进行生成,如匿名化CA方法所述。例如,认证器可以配备一个主证明私钥(及证书),并结合云操作的匿名化CA,动态生成按每个凭证的证明密钥对和证明证书。
注意:在本规范以外的各个地方,“隐私CA”这个术语用于指代此处称为“匿名化CA”的内容。因为可信计算组(TCG)也使用过“隐私CA”一词来指代现在称为证明CA(ACA)的内容[TCG-CMCProfile-AIKCertEnroll],我们在此特定背景下使用“匿名化CA”一词以尽量减少混淆。
14.4.2. 存储在认证器中的个人身份信息隐私
认证器可以为客户端提供规范之外的附加信息,例如,允许客户端提供一个丰富的UI,供用户选择用于认证仪式的凭证。如果认证器选择这样做,它不应暴露个人身份信息,除非已成功执行了用户验证。如果认证器支持多个用户的并发注册,则认证器不应暴露当前已验证用户以外的其他用户的个人身份信息。因此,不支持用户验证的认证器不应存储个人身份信息。
对于本文讨论的目的,作为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 存储在认证器中的个人识别信息的隐私中未被视为个人识别信息,依赖方不得在用户句柄中包含个人识别信息,如电子邮件地址或用户名。这包括个人识别信息的哈希值,除非哈希函数使用加盐并且盐值对依赖方是私有的,因为哈希并不能防止可猜测输入值的探测。建议让用户句柄为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
响应时,使其无法区分验证失败是因为签名无效还是因为没有注册此用户或凭证。 -
执行多步骤的认证仪式,例如,先提供用户名和密码或会话Cookie,然后作为后续步骤启动WebAuthn仪式。这将用户名枚举问题从WebAuthn步骤移至前面的认证步骤,在那里可能更容易解决。
-
14.6.3. 通过凭证ID的隐私泄漏
本节不是规范性内容。
本隐私注意事项适用于支持认证仪式且第一个认证步骤使用非空的allowCredentials
参数的依赖方。例如,如果使用服务器端凭证作为第一个认证步骤。
在这种情况下,allowCredentials
参数存在泄露个人识别信息的风险,因为它将用户的凭证ID暴露给未认证的调用者。凭证ID旨在无法在依赖方之间进行关联,但凭证ID的长度可能暗示创建它的认证器类型。用户很可能会为多个依赖方使用相同的用户名和一组认证器,因此凭证ID的数量和长度可能成为一个全局关联标识,以去匿名化用户。了解用户的凭证ID还可以使得在仅瞬间接触到用户的一个认证器的情况下确认用户身份的猜测。
为了防止此类信息泄漏,依赖方可以例如:
-
使用客户端可发现凭证,这样就不需要
allowCredentials
参数。
如果上述预防措施不可用,即如果allowCredentials
需要在仅提供用户名的情况下暴露,依赖方可以使用返回虚拟凭证ID的方法来减轻隐私泄漏,如在§ 14.6.2 用户名枚举中讨论的那样。
15. 可访问性注意事项
用户验证功能的认证器,无论是漫游认证器还是平台认证器,都应为用户提供多种用户验证方法。例如,既可以使用指纹传感器,也可以输入PIN码。当选择的方法因某种原因无法使用时,这样可以切换到其他用户验证方式。请注意,在漫游认证器的情况下,认证器和平台可能会协作提供用户验证方法,如PIN码输入[FIDO-CTAP]。
依赖方在注册时,应提供便利措施,以便用户在将来能够正确完成授权手势。这可能涉及为认证器命名、选择与设备相关联的图片,或输入自由格式的文本说明(例如,作为自我提醒)。
依赖于时间的操作流程,例如注册流程(参见超时时间
)或认证流程(参见超时时间
),应遵循[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 认证工作组共同主席的贡献。
我们还感谢 Wendy Seltzer、Samuel Weiler 和 Harry Halpin 作为 W3C 团队联系人所做的贡献。