W3C

Web身份验证:
访问公钥凭证的API
第二级

W3C推荐标准,

此版本:
https://www.w3.org/TR/2021/REC-webauthn-2-20210408/
最新发布版本:
https://www.w3.org/TR/webauthn-2/
编辑草案:
https://w3c.github.io/webauthn/
以前的版本:
实施报告:
https://www.w3.org/2020/12/webauthn-report.html
问题跟踪:
GitHub
编辑:
(谷歌)
(Mozilla)
(微软)
(微软)
(Yubico)
前任编辑:
(谷歌)
(微软)
(谷歌)
(谷歌)
(贝宝)
(微软)
(Nok Nok实验室)
贡献者:
John Bradley (Yubico)
Christiaan Brand (谷歌)
Adam Langley (谷歌)
Giridhar Mandyam (高通)
Nina Satragno (谷歌)
Nick Steele (Gemini)
Jiewen Tan (苹果)
Shane Weeden (IBM)
Mike West (谷歌)
Jeffrey Yasskin (谷歌)
测试:
web-platform-tests webauthn/ (持续工作)

请查看勘误表,以获取自发布以来报告的任何错误或问题。


摘要

本规范定义了一个API,允许Web应用程序创建和使用基于公钥的、强大的、可证明的范围限定的凭证,用于强用户身份验证。从概念上讲,一个或多个公钥凭证,每一个都范围限定到给定的WebAuthn依赖方,由Web应用程序请求并绑定认证器。用户代理介导对认证器及其公钥凭证的访问,以保护用户隐私。认证器负责确保没有在未经用户同意的情况下执行的操作。认证器通过证明依赖方提供其属性的密码学证明。本规范还描述了符合WebAuthn标准的认证器的功能模型,包括其签名和证明功能。

本文档状态

本节描述了本文档在出版时的状态。其他文档可能会取代本文档。当前 W3C出版物和本技术报告的最新修订版列表可在 W3C技术报告索引找到:https://www.w3.org/TR/。

本文档由Web身份验证工作组发布为推荐标准。

欢迎对本规范提供反馈和意见。请使用Github问题。 讨论也可以在public-webauthn@w3.org archives中找到。

W3C推荐标准是一项规范,在经过广泛的共识构建后,得到了W3C及其成员的认可。W3C建议将此规范广泛部署为Web的标准。

本文档已由W3C成员、软件开发人员及其他W3C小组和感兴趣的各方进行审查,并已获得主管的认可为W3C推荐标准。这是一个稳定的文档,可用作参考材料或被其他文档引用。W3C在制定推荐标准中的角色是引起对该规范的注意,并促进其广泛部署。这增强了Web的功能性和互操作性。

本文档由一个根据2017年8月1日 W3C 专利政策运作的小组制作。W3C维护一个公开的专利披露列表,其中列出了与该小组的成果相关的任何专利披露;该页面还包括披露专利的说明。个人如果实际知道某项专利,并且认为该专利包含必要的声明,则必须根据 W3C 专利政策第6节披露相关信息。

本文档受2020年9月15日 W3C 流程文档的管理。

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身份验证API本身一起,本规范定义了一种请求-响应的加密协议——WebAuthn/FIDO2协议——在WebAuthn依赖方服务器和认证器之间,依赖方的请求包括挑战和由依赖方提供并发送给认证器的其他输入数据。请求通过HTTPS、依赖方Web应用程序WebAuthn API和用户代理与认证器之间的特定平台通信通道组合传递。认证器通过数字签名的认证器数据消息和其他输出数据进行回复,这些数据通过相同的路径反向传递回依赖方服务器。协议细节根据身份验证注册操作是否由依赖方调用而有所不同。另见图1图2

对于Web身份验证部署的端到端安全性,至关重要的是,所有组件——依赖方服务器、客户端认证器——的角色,以及§ 13 安全注意事项§ 14 隐私注意事项,都被所有受众理解。

1.2. 使用案例

以下使用案例场景展示了两种非常不同类型的认证器的使用,并概述了进一步的场景。其他场景,包括示例代码,稍后将在§ 1.3 API使用场景示例中给出。

1.2.1. 注册

1.2.2. 身份验证

1.2.3. 新设备注册

此使用案例场景展示了依赖方如何利用漫游认证器(例如USB安全密钥)和平台认证器(例如内置指纹传感器)的组合,以便用户具有:

注意: 为帐户注册多个认证器的方法在帐户恢复使用案例中也很有用。

1.2.4. 其他使用案例和配置

还可以实现各种其他使用案例和配置,包括(但不限于):

1.3. API使用场景示例

本节不具规范性。

在本节中,我们将介绍公钥凭证生命周期中的一些事件,并提供使用该API的相应示例代码。请注意,这只是一个示例流程,并不限制API的使用范围。

如前面章节所述,该流程专注于涉及具有自己显示屏的第一因素漫游认证器的使用案例。此类认证器的一个示例是智能手机。此API还支持其他类型的认证器,具体取决于客户端平台的实现。例如,此流程在没有任何修改的情况下也适用于嵌入到客户端设备中的认证器。对于没有自己显示屏的认证器(类似于智能卡)的情况,该流程在特定实现考虑的前提下也适用。具体而言,客户端平台需要显示原本由认证器显示的任何提示,并且认证器需要允许客户端平台枚举所有认证器的凭证,以便客户端能够显示适当的提示信息。

1.3.1. 注册

这是首次流程,其中创建并向服务器注册新凭证。在此流程中,WebAuthn 依赖方平台认证器漫游认证器没有偏好。

  1. 用户访问example.com,加载脚本。此时,用户可能已经使用传统的用户名和密码、其他认证器或其他依赖方接受的方法登录,或者用户可能正在创建新帐户。

  2. 依赖方脚本运行下面的代码片段。

  3. 客户端平台搜索并定位认证器。

  4. 客户端连接到认证器,必要时执行任何配对操作。

  5. 认证器显示适当的用户界面,用户提供生物识别或其他授权手势

  6. 认证器向客户端返回响应,客户端则向依赖方脚本返回响应。如果用户拒绝选择认证器或提供授权,则返回相应的错误。

  7. 如果创建了新凭证,

    • 依赖方脚本将新生成的凭证公钥发送到服务器,并附带其他信息,如认证器的来源和特征的声明。

    • 服务器将凭证公钥存储在其数据库中,并将其与用户以及认证中通过声明表明的特征关联起来,还存储一个友好名称以供后续使用。

    • 脚本可以将凭证ID等数据存储在本地存储中,以通过缩小用户选择凭证的范围来改进未来的用户体验。

生成并注册新密钥的示例代码如下:

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 依赖方特别希望使用 用户验证平台认证器 创建公钥凭证时的示例流程。

  1. 用户访问example.com并点击登录按钮,系统将用户重定向到login.example.com。

  2. 用户输入用户名和密码进行登录。登录成功后,用户被重定向回example.com。

  3. 依赖方脚本运行下面的代码片段。

    1. 用户代理检查是否有可用的用户验证平台认证器。如果没有,则终止此流程。

    2. 依赖方询问用户是否希望使用它创建凭证。如果用户拒绝,则终止此流程。

    3. 用户代理和/或操作系统显示适当的UI,并引导用户使用其中一个可用的平台认证器创建凭证。

    4. 凭证成功创建后,依赖方脚本将新凭证传送到服务器。

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. 认证

这是当已注册凭证的用户访问网站并希望使用该凭证进行认证时的流程。

  1. 用户访问example.com,网站提供一个脚本。

  2. 脚本向客户端请求认证断言,尽可能多地提供信息以缩小用户可接受的凭证选择范围。这些信息可以从注册后存储在本地的数据中获得,或者通过其他方式,例如提示用户输入用户名。

  3. 依赖方脚本运行下面的代码片段之一。

  4. 客户端平台搜索并定位认证器。

  5. 客户端连接到认证器,如有必要,执行任何配对操作。

  6. 认证器向用户显示一个通知,表明需要他们的注意。打开通知后,用户将看到一个友好的凭证选择菜单,该菜单使用创建凭证时提供的帐户信息,并显示请求这些密钥的来源的相关信息。

  7. 认证器从用户处获得生物特征或其他授权手势

  8. 认证器向客户端返回响应,客户端再将响应返回给依赖方脚本。如果用户拒绝选择凭证或提供授权,将返回适当的错误。

  9. 如果成功生成并返回了断言,

    • 脚本将断言发送到服务器。

    • 服务器检查断言,提取凭证ID,查找其数据库中注册的公钥,并验证断言签名。如果有效,它会查找与断言的凭证ID关联的身份;该身份现在已被认证。如果服务器不识别该凭证ID(例如,由于不活跃而已被注销),那么认证将失败;每个依赖方将以自己的方式处理此问题。

    • 服务器现在将执行任何其他操作,例如返回成功页面、设置认证cookie等。

如果依赖方脚本没有任何可用提示(例如,本地存储的数据)来帮助它缩小凭证列表,则执行这种认证的示例代码可能如下所示:

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.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

本规范使用CBOR数据定义语言(CDDL[RFC8610]描述所有CBOR编码数据的语法。

COSE

CBOR对象签名和加密(COSE)[RFC8152]。此规范建立的IANA COSE算法注册表[IANA-COSE-ALGS-REG]也被使用。

凭据管理

本文档描述的API是[CREDENTIAL-MANAGEMENT-1]中定义的Credential概念的扩展。

DOM

DOMException及本规范中使用的DOMException值定义在[DOM4]中。

ECMAScript

%ArrayBuffer%定义在[ECMAScript]中。

HTML

浏览上下文不透明源元组源相关设置对象以及是否是可注册域的后缀或相等的概念定义在[HTML]中。

URL

同站点的概念定义在[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由认证器生成,有两种形式:

  1. 至少16个字节,其中至少包含100位的熵,或

  2. 公共密钥凭证源,去除凭证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 接口

PublicKeyCredential

适用于所有当前引擎。

Firefox60+Safari13+Chrome67+
OperaEdge79+
Edge (旧版)18IE
Firefox for Android60+iOS Safari13.3+Chrome for Android70+Android WebView70+Samsung InternetOpera Mobile

PublicKeyCredential 接口继承自Credential [CREDENTIAL-MANAGEMENT-1],并包含在创建新凭证或请求新断言时返回给调用者的属性。

PublicKeyCredential/getClientExtensionResults

适用于所有当前引擎。

Firefox60+Safari13+Chrome67+
OperaEdge79+
Edge (旧版)18IE
Firefox for Android60+iOS Safari13.3+Chrome for Android70+Android WebView70+Samsung InternetOpera Mobile

PublicKeyCredential/rawId

适用于所有当前引擎。

Firefox60+Safari13+Chrome67+
OperaEdge79+
Edge (旧版)18IE
Firefox for Android60+iOS Safari13.3+Chrome for Android70+Android WebView70+Samsung InternetOpera 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]] 内部槽中。

PublicKeyCredential/response

适用于所有当前引擎。

Firefox60+Safari13+Chrome67+
OperaEdge79+
Edge (旧版)18IE
Firefox for Android60+iOS Safari13.3+Chrome for Android70+Android WebView70+Samsung InternetOpera Mobile

response 类型为 AuthenticatorResponse,只读

此属性包含认证器对客户端请求的响应,创建公钥凭证或生成身份验证断言。如果PublicKeyCredential 是响应create()而创建的, 则此属性的值将是AuthenticatorAttestationResponse, 否则, PublicKeyCredential 是响应get()而创建的, 并且此属性的值 将是AuthenticatorAssertionResponse

getClientExtensionResults()

此操作返回[[clientExtensionsResults]]的值, 该值是一个包含映射扩展标识符客户端扩展输出 条目的客户端扩展处理

[[type]]

PublicKeyCredential 接口对象[[type]] 内部槽的值是字符串 "public-key"。

注意:这通过type 继承自Credential的getter进行反映。

[[discovery]]

PublicKeyCredential 接口对象[[discovery]] 内部槽的值是 "remote"。

[[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

此参数是相关设置对象origin,由 调用create()实现决定。

options

此参数是一个 CredentialCreationOptions 对象,其 options.publicKey 成员包含一个 PublicKeyCredentialCreationOptions 对象,指定要创建的公钥凭证的期望属性。

sameOriginWithAncestors

此参数是一个布尔值,当且仅当调用者的环境设置对象与其祖先同源时为true。如果调用者是跨域的,则为false

注意:内部方法的调用表明它已被权限策略允许,评估于[CREDENTIAL-MANAGEMENT-1]级别。 详见 § 5.9 权限策略集成

注意: 此算法是同步的: Promise 的解决/拒绝由navigator.credentials.create()处理。

注意:此算法中使用的所有BufferSource 对象必须在算法开始时进行快照, 以避免潜在的同步问题。算法实现应获取缓冲源持有的字节的副本并在算法的相关部分中使用该副本。

当调用此方法时,用户代理必须执行以下算法:

  1. 断言: options.publicKey 是存在的。

  2. 如果sameOriginWithAncestorsfalse,则返回 "NotAllowedError" DOMException

    注意:此"sameOriginWithAncestors"限制旨在解决在问题 #1336中提出的跟踪问题。此规范的未来版本可能会对此进行修订。

  3. optionsoptions.publicKey 的值。

  4. 如果 timeout 成员options存在,检查其值是否在客户端定义的合理范围内,如果不在,则将其调整为该范围内的最接近值。将计时器lifetimeTimer设置为此调整后的值。如果timeout 成员options不存在,则将lifetimeTimer设置为客户端特定的默认值。

    对于timeout 成员options的推荐范围和默认值如下: 如果 options.authenticatorSelection.userVerification

    设置为discouraged

    推荐范围:30000 毫秒到 180000 毫秒。

    推荐默认值:120000 毫秒(2 分钟)。

    设置为requiredpreferred

    推荐范围:30000 毫秒到 600000 毫秒。

    推荐默认值:300000 毫秒(5 分钟)。

    注意:用户代理应在考虑具有特殊需求的用户的认知指南后再确定超时。

  5. 如果 options.user.id 的长度不在 1 到 64 字节(含)之间,则返回 TypeError

  6. callerOriginorigin。 如果callerOrigin不透明的origin,则返回一个DOMException 其名称为 "NotAllowedError", 并终止此算法。

  7. effectiveDomaincallerOrigin有效域名。 如果有效域名不是有效域名,则返回一个DOMException 其名称为 "SecurityError", 并终止此算法。

    注意:一个有效域名可以解析为host,其表示形式多种多样, 如域名IPv4 地址IPv6 地址不透明的host空host。 此处仅允许域名格式的host。 这是为了简化,同时也 认识到使用直接IP地址识别与PKI-based安全结合使用的各种问题。

  8. 如果 options.rp.id

    存在

    如果 options.rp.id 不是注册域名后缀或不等于effectiveDomain, 返回一个DOMException 其名称为"SecurityError", 并终止此算法。

    不存在

    options.rp.id 设置为effectiveDomain

    注意: options.rp.id 代表调用者的RP IDRP ID默认情况下为调用者的origineffective domain,除非调用者在调用create()时显式设置了 options.rp.id

  9. credTypesAndPubKeyAlgs为一个新的列表,其PublicKeyCredentialType 和 一个COSEAlgorithmIdentifier

  10. 如果 options.pubKeyCredParams大小

    为零

    附加以下PublicKeyCredentialTypeCOSEAlgorithmIdentifier对到credTypesAndPubKeyAlgs

    非零

    对于每个currentoptions.pubKeyCredParams

    1. 如果 current.type 不包含此实现支持的PublicKeyCredentialType, 则继续

    2. algcurrent.alg

    3. 附加此对 current.typealgcredTypesAndPubKeyAlgs

    如果credTypesAndPubKeyAlgs为空,则返回DOMException 其名称为 "NotSupportedError", 并终止此算法。

  11. clientExtensions为一个新的映射,让authenticatorExtensions为一个新的映射

  12. 如果optionsextensions成员存在,则对于每个 extensionIdclientExtensionInputoptions.extensions

    1. 如果extensionId不被此客户端平台支持或不是注册扩展,则继续

    2. 设置 clientExtensions[extensionId] 为clientExtensionInput

    3. 如果extensionId不是认证器扩展,则继续

    4. authenticatorExtensionInput为运行extensionId客户端扩展处理算法时的(CBOR)结果 在clientExtensionInput上。如果算法返回错误,则继续

    5. 设置 authenticatorExtensions[extensionId] 为 authenticatorExtensionInputbase64url 编码

  13. collectedClientData为一个新的CollectedClientData实例,其字段为:

    type

    字符串 "webauthn.create"。

    challenge

    optionschallengebase64url 编码

    origin

    callerOrigin序列化

    crossOrigin

    传递给此内部方法sameOriginWithAncestors参数值的反转。

    tokenBinding

    客户端与callerOrigin之间令牌绑定的状态,及与callerOrigin相关联的令牌绑定ID,如果可用的话。

  14. clientDataJSON为从collectedClientData构造的客户端数据的JSON兼容序列化

  15. clientDataHash为由clientDataJSON表示的客户端数据序列化后的哈希值

  16. 如果 options.signal 存在,并且其中止标志设置为true,则返回DOMException 其名称为"AbortError", 并终止此算法。

  17. issuedRequests为一个新的有序集合

  18. authenticators表示一个值,该值在任何给定时刻都是一个集合,其中每个标识此客户端平台此时可用的认证器

    注意: 什么使认证器被视为"可用"是有意未指定的;这是为了表示如何通过各种机制认证器可以热插拔到(例如,通过USB)或被客户端发现(例如,通过NFC或蓝牙),或永久内置于客户端中。

  19. 启动lifetimeTimer

  20. lifetimeTimer未过期时,依据lifetimeTimer、 状态和响应对于每个 authenticatorauthenticators 中执行以下操作:

    如果lifetimeTimer过期,

    对于每个authenticatorissuedRequests 中调用authenticatorCancel操作,并移除authenticatorissuedRequests中。

    如果用户行使用户代理用户界面选项来取消该过程,

    对于每个authenticatorissuedRequests中调用authenticatorCancel操作,并移除authenticatorissuedRequests中。返回一个DOMException 其名称为 "NotAllowedError"。

    如果 options.signal 存在并且其中止标志设置为true

    对于每个authenticatorissuedRequests中调用authenticatorCancel操作,并移除authenticatorissuedRequests中。然后返回一个DOMException 其名称为"AbortError", 并终止此算法。

    如果authenticator在此客户端设备上变得可用,

    注意:这包括lifetimeTimer启动时authenticator已经可用的情况。

    1. authenticator现在是候选认证器

    2. 如果 options.authenticatorSelection 存在:

      1. 如果 options.authenticatorSelection.authenticatorAttachment 存在且其值不等于authenticator认证器连接方式继续

      2. 如果 options.authenticatorSelection.residentKey

        存在并设置为required

        如果authenticator无法存储客户端可发现的公钥凭证源继续

        存在并设置为preferreddiscouraged

        无效。

        不存在

        如果 options.authenticatorSelection.requireResidentKey 设置为true,且authenticator无法存储客户端可发现的公钥凭证源继续

      3. 如果 options.authenticatorSelection.userVerification 设置为requiredauthenticator无法执行用户验证,则继续

    3. requireResidentKey成为有效的凭证创建的常驻密钥要求,作为一个布尔值,规则如下:

      如果 options.authenticatorSelection.residentKey

      存在并设置为required

      requireResidentKeytrue

      存在并设置为preferred

      如果authenticator

      能够执行客户端凭证存储方式

      requireResidentKeytrue

      无法执行客户端凭证存储方式,或客户端无法确定认证器能力,

      requireResidentKeyfalse

      存在并设置为discouraged

      requireResidentKeyfalse

      不存在

      requireResidentKey为以下值: options.authenticatorSelection.requireResidentKey

    4. userVerification成为有效的凭证创建的用户验证要求,作为一个布尔值,规则如下: 如果 options.authenticatorSelection.userVerification

      设置为required

      userVerificationtrue

      设置为preferred

      如果authenticator

      能够执行用户验证

      userVerificationtrue

      无法执行用户验证

      userVerificationfalse

      设置为discouraged

      userVerificationfalse

    5. enterpriseAttestationPossible成为一个布尔值,规则如下。 如果 options.attestation

      设置为enterprise

      enterpriseAttestationPossibletrue,如果用户代理希望支持企业证明对于 options.rp.id (参见步骤8,在上文中)。 否则设为false

      否则

      enterpriseAttestationPossiblefalse

    6. excludeCredentialDescriptorList为一个新的列表

    7. 对于每个凭证描述符Coptions.excludeCredentials中:

      1. 如果 C.transports 非空,并且 authenticator连接的传输方式不在C.transports中提到,客户端可继续

        注意:如果客户端选择继续,这可能会导致意外注册多个凭证绑定到同一个认证器,如果 C.transports中的传输提示不准确。 例如,存储的传输提示可能会因为软件升级添加了新的连接选项而变得不准确。

      2. 否则,附加CexcludeCredentialDescriptorList中。

      3. authenticator上调用authenticatorMakeCredential操作,并使用clientDataHashoptions.rpoptions.userrequireResidentKeyuserVerificationcredTypesAndPubKeyAlgsexcludeCredentialDescriptorListenterpriseAttestationPossible, 以及authenticatorExtensions作为参数。

    8. 附加authenticatorissuedRequests

    如果authenticator在此客户端设备上不再可用,

    移除authenticatorissuedRequests中。

    如果任何authenticator返回状态指示用户取消了操作,
    1. 移除authenticatorissuedRequests中。

    2. 对于每个剩余的authenticatorissuedRequests中调用authenticatorCancel操作,并移除它从issuedRequests中。

      注意:认证器可能会返回“用户取消了整个操作”的指示。 用户代理如何将此状态显示给用户是未指定的。

    如果任何authenticator返回的错误状态等同于"InvalidStateError",
    1. 移除authenticatorissuedRequests中。

    2. 对于每个剩余的authenticatorissuedRequests中调用authenticatorCancel操作,并移除它从issuedRequests中。

    3. 返回一个DOMException 其名称为"InvalidStateError", 并终止此算法。

    注意:此错误状态单独处理,因为authenticator仅在 excludeCredentialDescriptorList标识了一个凭证绑定authenticator,且用户已同意该操作时才会返回。 鉴于这种明确的同意,允许Relying Party识别此情况是可以接受的。

    如果任何authenticator返回的错误状态不等同于"InvalidStateError",

    移除authenticatorissuedRequests中。

    注意:此情况并不意味着对该操作的用户同意, 因此错误的详细信息对Relying Party隐藏,以防止泄露可能识别用户的信息。 参见§ 14.5.1 注册仪式隐私以了解详细信息。

    如果任何authenticator指示成功,
    1. 移除authenticatorissuedRequests中。此认证器现在是已选认证器

    2. credentialCreationData为一个结构体, 其中的为:

      attestationObjectResult

      其值为从成功的authenticatorMakeCredential 操作返回的字节。

      注意:此值为 attObj,如在§ 6.5.4 生成证明对象中定义。

      clientDataJSONResult

      其值为clientDataJSON的字节。

      attestationConveyancePreferenceOption

      其值为optionsattestation的值。

      clientExtensionResults

      其值为一个AuthenticationExtensionsClientOutputs 对象,包含扩展标识符客户端扩展输出 条目。条目是通过运行每个扩展的客户端扩展处理算法来创建客户端扩展输出,对于 optionsextensions中的每个客户端扩展

    3. constructCredentialAlg成为一个算法,该算法接受一个全局对象global, 其步骤为:

      1. 如果 credentialCreationDataattestationConveyancePreferenceOption的值为

        "none"

        用非识别版本替换可能唯一识别的信息:

        1. 如果AAGUID证明的凭证数据中为16个零字节, credentialCreationData.attestationObjectResult.fmt 为"packed",且"x5c"不存在于 credentialCreationData.attestationObjectResult 中,则正在使用自我证明且无需进一步操作。

        2. 否则

          1. AAGUID证明的凭证数据中替换为16个零字节。

          2. credentialCreationDataattestationObjectResult.fmt 设置为"none",并将 credentialCreationDataattestationObjectResult.attStmt 设置为空的CBOR 映射。 (参见§ 8.7 无证明声明格式§ 6.5.4 生成证明对象)。

        "indirect"

        客户端可选择用更隐私友好和/或更易验证的版本替换AAGUID证明声明 (例如,通过使用匿名化CA)。

        "direct"或"enterprise"

        认证器AAGUID证明声明未修改地传递给Relying Party

      2. attestationObject为一个新的ArrayBuffer, 使用global%ArrayBuffer%创建, 包含 credentialCreationDataattestationObjectResult的值的字节。

      3. idattestationObject.authData.attestedCredentialData.credentialId

      4. pubKeyCred为一个新的PublicKeyCredential 对象,与global相关联,其字段为:

        [[identifier]]

        id

        response

        一个新的AuthenticatorAttestationResponse 对象,与global相关联,其字段为:

        clientDataJSON

        一个新的ArrayBuffer, 使用global%ArrayBuffer%创建, 包含 credentialCreationDataclientDataJSONResult的字节。

        attestationObject

        attestationObject

        [[transports]]

        一个或多个唯一的DOMString的序列, 按字典序排列,authenticator被认为支持这些值。 值应该是AuthenticatorTransport的成员, 但客户端平台必须忽略未知的值。

        如果用户代理不希望透露此信息,则可以用设计用来保护隐私的任意序列代替。此序列仍必须有效,即按字典顺序排列且不重复。例如,它可以使用空序列。无论哪种方式,在这种情况下,用户代理需要承担Relying Party行为可能不理想的风险。

        如果用户代理没有任何传输信息,它应将此字段设置为空序列。

        注意:用户代理如何发现给定authenticator支持的传输方式超出了本规范的范围,但可能包括来自证明证书的信息(例如[FIDO-Transports-Ext]), 通过authenticator协议(如CTAP2)通信的元数据,或关于平台认证器的特例知识。

        [[clientExtensionsResults]]

        一个新的ArrayBuffer, 使用global%ArrayBuffer%创建, 包含 credentialCreationDataclientExtensionResults的字节。

      5. 返回pubKeyCred

    4. 对于每个剩余的authenticatorissuedRequests中调用authenticatorCancel操作,并移除它从issuedRequests中。

    5. 返回constructCredentialAlg并终止此算法。

  21. 返回一个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) 方法

这个 内部方法接受三个参数:

origin

这个参数是相关设置对象origin,由调用的get() 实现决定,即CredentialsContainer请求Credential抽象操作。

options

这个参数是一个 CredentialRequestOptions 对象,其中 options.publicKey 成员包含一个 PublicKeyCredentialRequestOptions 对象,指定要发现的 公钥凭证的期望属性。

sameOriginWithAncestors

这个参数是一个布尔值,当且仅当调用者的环境设置对象与其祖先同源时,它为true。如果调用者是跨源的,则它为false

注意: 调用这个 内部方法 表明它已被权限策略允许,该策略在 [CREDENTIAL-MANAGEMENT-1] 级别进行评估。 参见§ 5.9 权限策略集成

注意: 该算法是同步的: Promise 的解决/拒绝由navigator.credentials.get() 处理。

注意: 在此算法中使用的所有 BufferSource 对象必须在算法开始时进行快照,以避免潜在的同步问题。算法实现应获取缓冲区源所持有的字节的副本并在算法的相关部分使用该副本。

调用此方法时,用户代理必须执行以下算法:

  1. 断言: options.publicKey 已存在。

  2. optionsoptions.publicKey 的值。

  3. 如果 timeout 成员出现在 options 中,检查其值是否在由 客户端定义的合理范围内,如果不在该范围内,将其校正为位于该范围内的最接近值。 将计时器 lifetimeTimer 设置为此调整后的值。如果 timeout 成员未出现在 options 中,则将 lifetimeTimer 设置为 客户端特定的默认值。

    timeout 成员的推荐范围和默认值如下。 如果 options.userVerification

    设置为discouraged

    推荐范围:30000 毫秒到 180000 毫秒。

    推荐默认值:120000 毫秒(2 分钟)。

    设置为 requiredpreferred

    推荐范围:30000 毫秒到 600000 毫秒。

    推荐默认值:300000 毫秒(5 分钟)。

    注意: 用户代理应考虑认知指南,针对有特殊需求的用户设置超时时间。

  4. callerOriginorigin。 如果 callerOrigin 是一个不透明的 origin,则返回 DOMException, 其名称为 "NotAllowedError", 并终止此算法。

  5. effectiveDomaincallerOrigin有效域。 如果 有效域 不是一个有效域,则返回 DOMException ,其名称为 "SecurityError" 并终止此算法。

    注意: 有效域可能解析为一个host,它可以通过各种方式表示,如 ipv4 地址ipv6 地址不透明的 host、 或空的 host。 这里只允许 格式的 host。 这是为了简化操作,并且也认识到使用基于 PKI 的安全性与直接 IP 地址识别的各种问题。

  6. 如果 options.rpId 未出现,则将 rpId 设置为 effectiveDomain

    否则:

    1. 如果 options.rpId 不是 effectiveDomain 的可注册域后缀或与其相等,则返回 DOMException, 其名称为 "SecurityError", 并终止此算法。

    2. rpId 设置为 options.rpId 的值。

      注意: rpId 表示调用者的 RP IDRP ID 默认是调用者的 origin有效域,除非调用者在调用get()时显式设置了 options.rpId

  7. clientExtensions 为一个新的 映射,并且 令 authenticatorExtensions 为一个新的 映射

  8. 如果 extensions 成员出现在 options 中,则为每个 extensionIdclientExtensionInputoptions.extensions

    1. 如果 extensionId 不受此客户端平台支持或不是认证扩展,则继续

    2. 设置 clientExtensions[extensionId] 为 clientExtensionInput

    3. 如果 extensionId 不是认证器扩展,则继续

    4. authenticatorExtensionInput 为执行 extensionId客户端扩展处理 算法 在 clientExtensionInput 上的结果(CBOR)。如果算法返回了错误,继续

    5. 设置 authenticatorExtensions[extensionId] 为 base64url 编码authenticatorExtensionInput

  9. collectedClientData 为一个新的 CollectedClientData 实例,其字段如下:

    type

    字符串 "webauthn.get"。

    challenge

    base64url 编码options.challenge

    origin

    origin 的序列化 的值 callerOrigin

    crossOrigin

    与传递给此 内部方法 的参数sameOriginWithAncestors 的值相反。

    tokenBinding

    客户端与 callerOrigin 之间的 Token Binding 的状态,以及与 callerOrigin 关联的 Token Binding ID,如果存在的话。

  10. clientDataJSON客户端数据的 JSON 兼容序列化的表示形式 collectedClientData

  11. clientDataHash序列化客户端数据的哈希值 clientDataJSON

  12. 如果 options.signal 出现并且其aborted 标志被设置为true, 则返回 DOMException, 其名称为 "AbortError", 并终止此算法。

  13. issuedRequests 为一个新的有序集合

  14. savedCredentialIds 为一个新的 映射

  15. authenticators 表示一个值,该值在任何给定时间内都是一个集合,其中每个 客户端平台 特定句柄 在该时间点识别出当前可用的一个认证器

    注意: 什么资格可以让一个 认证器 被认为是“可用的”并没有具体说明;这旨在表示认证器可以通过各种机制热插拔(例如,通过 USB) 或被客户端发现(例如,通过 NFC 或 Bluetooth),或者永久内置于客户端中。

  16. 启动 lifetimeTimer

  17. lifetimeTimer 未过期时, 执行 以下操作,取决于 lifetimeTimer, 以及状态和响应 每个 authenticatorauthenticators 中:

    如果 lifetimeTimer 过期,

    对每个 authenticatorissuedRequests 中调用 authenticatorCancel 操作并且移除 authenticatorissuedRequests 中。

    如果用户执行用户代理用户界面选项以取消过程,

    对每个 authenticatorissuedRequests 中调用 authenticatorCancel 操作并且移除 authenticatorissuedRequests 中。返回 DOMException ,其名称为 "NotAllowedError"。

    如果 signal 成员存在并且 aborted 标志 设置为 true

    对每个 authenticatorissuedRequests 中调用 authenticatorCancel 操作并且移除 authenticatorissuedRequests 中。然后 返回 DOMException, 其名称为 "AbortError", 并终止此算法。

    如果 issuedRequests 为空, options.allowCredentials 不为空,并且没有 authenticator 会变得可用用于其中的任何 公钥凭证

    向用户表明没有找到符合条件的凭证。当用户确认对话框后,返回 DOMException, 其名称为 "NotAllowedError"。

    注意: 一个客户端平台可以确定没有 authenticator 会变得可用的一种方法是检查当前的 transports 成员 的 PublicKeyCredentialDescriptor options.allowCredentials, 如果有的话。例如,如果所有 PublicKeyCredentialDescriptor 仅列出 internal, 但是所有平台 authenticator 都已经尝试过,那么就没有可能满足请求。或者, 所有 PublicKeyCredentialDescriptor 可能列出 transports, 而客户端平台不支持这些 transports。

    如果 authenticator 变得在此客户端设备上可用,

    注意: 这包括 authenticatorlifetimeTimer 启动时已可用的情况。

    1. 如果 options.userVerification 设置为required 并且 authenticator 无法执行 用户验证继续

    2. userVerification有效用户验证要求,一个布尔值,如下所示。如果 options.userVerification

      设置为 required

      userVerificationtrue

      设置为 preferred

      如果 authenticator

      能够执行 用户验证

      userVerificationtrue

      无法执行 用户验证

      userVerificationfalse

      设置为 discouraged

      userVerificationfalse

    3. 如果 options.allowCredentials

      不为空
      1. allowCredentialDescriptorList 为一个新的 列表

      2. 执行一个客户端平台特定 过程,确定是否存在匹配 rpIdoptions.allowCredentialsoptions.idoptions.type的 公钥凭证。 将 allowCredentialDescriptorList 设置为此过滤后的列表。

      3. 如果 allowCredentialDescriptorList 为空继续

      4. distinctTransports 为一个新的 有序集合

      5. 如果 allowCredentialDescriptorList 只有一个值,将 savedCredentialIds[authenticator] 设置为 allowCredentialDescriptorList[0].id 的值(参见 此处§ 6.3.3 认证器获取断言操作 了解更多信息)。

      6. 对于每个 凭证描述符 CallowCredentialDescriptorList 中,附加 每个值(如果有) 到 distinctTransports

        注意: 这将聚合 distinctTransports 中仅限的 transports 值 (对于此 认证器)由于有序集合的属性。

      7. 如果 distinctTransports

        不为空

        客户端从 distinctTransports 中选择一个 transport 值,可能会结合本地 配置知识以选择适合于与 authenticator 配合使用的 传输。

        然后,使用 transport,调用 authenticatorGetAssertion 操作在 authenticator 上,带有 rpIdclientDataHashallowCredentialDescriptorListuserVerificationauthenticatorExtensions 作为参数。

        为空

        使用本地配置知识以选择适合于与 authenticator 配合使用的 传输,调用 authenticatorGetAssertion 操作在 authenticator 上带有 rpIdclientDataHashallowCredentialDescriptorListuserVerificationauthenticatorExtensions 作为参数。

      为空

      使用本地配置知识选择适合于与 authenticator 配合使用的传输,调用 authenticatorGetAssertion 操作在 authenticator 上,带有 rpIdclientDataHashuserVerificationauthenticatorExtensions 作为参数。

      注意: 在这种情况下,依赖方 未提供可接受的凭证描述符列表。因此,认证器被要求行使任何 凭证它可能 拥有 在 rpId 下标识的依赖方范围内。

    4. 附加 authenticatorissuedRequests

    如果 authenticator 不再在此客户端设备上可用,

    移除 authenticatorissuedRequests 中。

    如果任何 authenticator 返回一个状态,表示用户取消了操作,
    1. 移除 authenticatorissuedRequests 中。

    2. 对每个 剩余 authenticatorissuedRequests 中调用 authenticatorCancel 操作 并且 移除它从 issuedRequests 中。

      注意: 认证器 可能 返回表示“用户取消了整个操作”的状态。 用户代理如何将此状态表现给用户未做具体说明。

    如果任何 authenticator 返回错误状态,

    移除 authenticatorissuedRequests 中。

    如果任何 authenticator 指示成功,
    1. 移除 authenticatorissuedRequests 中。

    2. 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

    3. constructAssertionAlg 为一个算法,它接收一个全局对象 global,其步骤如下:

      1. 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 的字节数。

      2. 返回 pubKeyCred

    4. 对每个 剩余 authenticatorissuedRequests 中调用 authenticatorCancel 操作 并且 移除它从 issuedRequests 中。

    5. 返回 constructAssertionAlg 并终止此算法。

  18. 返回 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

当调用此方法时,用户代理必须执行以下算法:

  1. 返回一个 DOMException, 其名称为 "NotSupportedError", 并终止此算法

5.1.6. 防止静默访问现有凭证 - PublicKeyCredential 的 [[preventSilentAccess]](credential, sameOriginWithAncestors) 方法

调用 [[preventSilentAccess]](credential, sameOriginWithAncestors) 方法对需要 授权手势的认证器没有影响,但设置该标志可能会排除那些可以在没有用户干预的情况下操作的认证器。

这个内部方法不接受任何参数。

5.1.7. 用户验证平台认证器的可用性 - PublicKeyCredential 的 isUserVerifyingPlatformAuthenticatorAvailable() 方法

WebAuthn 依赖方使用此方法来确定他们是否可以使用用户验证平台认证器创建新凭证。 调用后,客户端使用 客户端平台特定过程发现可用的用户验证平台认证器。 如果发现任何认证器,promise 的值将解析为 true。 否则,promise 的值将解析为 false。 基于结果,依赖方可以采取进一步行动引导用户创建凭证。

此方法不接受任何参数,并返回一个布尔值。

PublicKeyCredential/isUserVerifyingPlatformAuthenticatorAvailable

在所有当前引擎中可用。

Firefox60+Safari13+Chrome67+
OperaEdge79+
Edge (旧版)18IE
Firefox for Android60+iOS Safari13.3+Chrome for Android70+Android WebView70+Samsung InternetOpera Mobile
partial interface PublicKeyCredential {
    static Promise<boolean> isUserVerifyingPlatformAuthenticatorAvailable();
};

注意: 从一个 浏览上下文 中调用此方法,而该上下文中的 Web 身份验证 API 根据 允许使用 算法被“禁用”,即通过权限策略,将导致 promise 被拒绝,并抛出 DOMException, 其名称为 "NotAllowedError"。 另见 § 5.9 权限策略集成

5.2. 认证器响应 (接口 AuthenticatorResponse)

AuthenticatorResponse

在所有当前引擎中可用。

Firefox60+Safari13+Chrome67+
OperaEdge79+
Edge (旧版)18IE
Firefox for Android60+iOS Safari13.3+Chrome for Android70+Android WebView70+Samsung InternetOpera Mobile

认证器通过返回一个从 AuthenticatorResponse 接口派生的对象来响应 依赖方 的请求:

[SecureContext, Exposed=Window]
interface AuthenticatorResponse {
    [SameObject] readonly attribute ArrayBuffer      clientDataJSON;
};

AuthenticatorResponse/clientDataJSON

在所有当前引擎中可用。

Firefox60+Safari13+Chrome67+
OperaEdge79+
Edge (旧版)18IE
Firefox for Android60+iOS Safari13.3+Chrome for Android70+Android WebView70+Samsung InternetOpera Mobile

clientDataJSON, 类型为 ArrayBuffer, 只读

该属性包含 与 JSON 兼容的序列化客户端数据,其 散列值 是由客户端在调用 create()get() 时传递给认证器的(即,客户端数据本身不会发送给认证器)。

5.2.1. 公钥凭证信息 (接口 AuthenticatorAttestationResponse)

AuthenticatorAttestationResponse

在所有当前引擎中可用。

Firefox60+Safari13+Chrome67+
OperaEdge79+
Edge (旧版)18IE
Firefox for Android60+iOS Safari13.3+Chrome for Android70+Android WebView70+Samsung Internet10.0+Opera Mobile

AuthenticatorAttestationResponse 接口表示 认证器 对客户端请求创建新 公钥凭证 的响应。它包含有关新凭证的信息,可用于 以后识别它,以及 WebAuthn 依赖方 在注册过程中用来评估凭证特征的元数据。

AuthenticatorAttestationResponse/getTransports

在无当前引擎中可用。

FirefoxSafariChrome
OperaEdge
Edge (旧版)IE
Firefox for AndroidiOS SafariChrome for AndroidAndroid WebViewSamsung InternetOpera 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 内, 位于 认证器数据 内, 位于 认证对象 内,由 AuthenticatorAttestationResponseattestationObject 传递。 希望使用 认证依赖方 必须解析 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

在所有当前的引擎中。

Firefox60+Safari13+Chrome67+
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 MobileNone

authenticatorData, 类型为 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 MobileNone

signature, 类型为 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 MobileNone

userHandle, 类型为 ArrayBuffer,只读,可为空

该属性包含由认证器返回的 用户句柄,如果认证器未返回 用户句柄,则为 null。参见 § 6.3.3 认证器获取断言操作

5.3. 凭证生成参数 (字典 PublicKeyCredentialParameters)

dictionary PublicKeyCredentialParameters {
    required DOMString                    type;
    required COSEAlgorithmIdentifier      alg;
};
此字典用于在创建新凭证时提供额外的参数。
type, 类型为 DOMString

该成员指定要创建的凭证类型。值应为 PublicKeyCredentialType 的成员,但 客户端平台必须忽略未知的值,忽略任何具有未知 PublicKeyCredentialParameterstype

alg, 类型为 COSEAlgorithmIdentifier

该成员指定新生成凭证将使用的加密签名算法,因此也指定了要生成的非对称密钥对的类型,例如 RSA 或椭圆曲线。

注意: 我们使用“alg”作为后一个成员名称,而不是拼出“algorithm”,因为它将被序列化为发给认证器的消息,这可能通过低带宽链接发送。

5.4. 凭证创建选项(字典 PublicKeyCredentialCreationOptions

PublicKeyCredentialCreationOptions

在所有当前引擎中。

Firefox60+Safari13+Chrome67+
Opera54+Edge79+
Edge (旧版)IE
Android 版 FirefoxiOS 版 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 版 FirefoxiOS Safari13.3+Android 版 Chrome67+Android WebView三星 InternetOpera 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 版 FirefoxiOS Safari13.3+Android 版 Chrome67+Android WebView三星 InternetOpera Mobile48+

user, 类型 为 PublicKeyCredentialUserEntity

此成员包含有关 依赖方 请求 的用户帐户的 数据。

其值的 namedisplayNameid 成员是必需的。有关详细信息,请参阅 § 5.4.1 公钥实体描述(字典 PublicKeyCredentialEntity)§ 5.4.3 用户帐户凭证生成参数(字典 PublicKeyCredentialUserEntity)

PublicKeyCredentialCreationOptions/challenge

在所有当前引擎中。

Firefox60+Safari13+Chrome67+
Opera54+Edge79+
Edge (旧版)IE
Android 版 FirefoxiOS Safari13.3+Android 版 Chrome67+Android WebView三星 InternetOpera Mobile48+

challenge, 类型为 BufferSource

此成员包含用于生成新创建的凭证的 证明对象 的挑战。有关安全性注意事项,请参阅 § 13.4.3 加密挑战

PublicKeyCredentialCreationOptions/pubKeyCredParams

在所有当前引擎中。

Firefox60+Safari13+Chrome67+
Opera54+Edge79+
Edge (旧版)IE
Android 版 FirefoxiOS Safari13.3+Android 版 Chrome67+Android WebView三星 InternetOpera Mobile48+

pubKeyCredParams, 类型为 sequence<PublicKeyCredentialParameters>

此成员包含有关要创建的凭证所需属性的信息。序列按优先顺序排列,从最优先到最不优先。客户端 会尽力创建它所能创建的最优先凭证。

PublicKeyCredentialCreationOptions/timeout

在所有当前引擎中。

Firefox60+Safari13+Chrome67+
Opera54+Edge79+
Edge (旧版)IE
Android 版 FirefoxiOS Safari13.3+Android 版 Chrome67+Android WebView三星 InternetOpera Mobile48+

timeout, 类型为 unsigned long

此成员指定调用者愿意等待调用完成的时间,以毫秒为单位。这被视为提示,可能会被 客户端 覆盖。

PublicKeyCredentialCreationOptions/excludeCredentials

在所有当前引擎中。

Firefox60+Safari13+Chrome67+
Opera54+Edge79+
Edge (旧版)IE
Android 版 FirefoxiOS Safari13.3+Android 版 Chrome67+Android WebView三星 InternetOpera Mobile48+

excludeCredentials, 类型为 sequence<PublicKeyCredentialDescriptor>,默认为 []

此成员供希望限制在单个验证器上为同一帐户创建多个凭证的 依赖方 使用。如果新凭证将在已包含此参数中列出的凭证之一的验证器上创建,客户端 被请求返回错误。

PublicKeyCredentialCreationOptions/authenticatorSelection

在所有当前引擎中。

Firefox60+Safari13+Chrome67+
Opera54+Edge79+
Edge (旧版)IE
Android 版 FirefoxiOS Safari13.3+Android 版 Chrome67+Android WebView三星 InternetOpera Mobile48+

authenticatorSelection, 类型为 AuthenticatorSelectionCriteria

此成员供希望选择适当验证器参与 create() 操作的 依赖方 使用。

PublicKeyCredentialCreationOptions/attestation

在所有当前引擎中。

Firefox60+Safari13+Chrome67+
Opera54+Edge79+
Edge (旧版)IE
Android 版 FirefoxiOS Safari13.3+Android 版 Chrome67+Android WebView三星 InternetOpera 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;
};
id, 类型为 DOMString

用于设置 RP ID依赖方 实体的唯一标识符。

5.4.3. 用户帐户凭证生成参数 (字典 PublicKeyCredentialUserEntity)

字典 PublicKeyCredentialUserEntity 用于在创建新凭证时提供额外的用户帐户属性。

dictionary PublicKeyCredentialUserEntity : PublicKeyCredentialEntity {
    required BufferSource   id;
    required DOMString      displayName;
};
id, 类型为 BufferSource

用户帐户实体的 用户句柄用户句柄 是一个不透明的 字节序列,最大长度为 64 字节,不应向用户显示。

为了确保安全操作,认证和授权决策必须基于该 id 成员,而不是基于 displayNamename 成员。参见 [RFC8266] 的第 6.1 节。

用户句柄不得包含有关用户的个人身份信息,例如用户名或电子邮件地址;详见 § 14.6.1 用户句柄内容。用户句柄不得为空,尽管它可以为 null。

注意:用户句柄 不应 在不同帐户之间是常量值,即使对于 不可发现的凭证 也是如此,因为某些验证器始终创建 可发现的凭证。因此,常量用户句柄将阻止用户在同一 依赖方 上使用这样的验证器与多个帐户。

displayName, 类型为 DOMString

用户帐户的 易理解 名称,仅用于显示。例如,“Alex Müller” 或 “田中倫”。依赖方 应允许用户选择此名称,并且不应限制选择超过必要范围。

客户端客户端平台,或 验证器 显示 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 的成员,但 客户端平台 必须忽略未知值,并将未知值视为该 成员不存在。如果未给出值,则当 requireResidentKeytrue 时,其有效值为 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 类型

platform

此值表示平台附件

cross-platform

此值表示跨平台附件

注意: 认证器附件模式选择选项仅在 [[Create]](origin, options, sameOriginWithAncestors) 操作中可用。依赖方可以使用它,例如,确保用户有一个 漫游凭证用于在其他 客户端设备上进行身份验证;或专门注册一个 平台凭证,以便在特定 客户端设备上更轻松地重新验证。[[DiscoverFromExternalSource]](origin, options, sameOriginWithAncestors)操作没有认证器附件模式选择选项,因此依赖方应该接受用户注册的任何凭证客户端和用户将使用当时可用且方便的凭证。

5.4.6. 常驻密钥要求枚举 (枚举 ResidentKeyRequirement)

enum ResidentKeyRequirement {
    "discouraged",
    "preferred",
    "required"
};

注意: ResidentKeyRequirement 枚举被故意忽略引用,请参见 § 2.1.1 枚举作为 DOMString 类型

此枚举的值描述了依赖方对于客户端可发现的凭证(以前称为常驻凭证常驻密钥)的要求:

discouraged

此值表示依赖方更倾向于创建服务器端凭证,但会接受客户端可发现的凭证

注意: 依赖方不能要求创建的凭证必须是服务器端凭证,而凭证属性扩展可能不会返回rk属性的值。因此,依赖方可能无法知道凭证是否为服务器端凭证,也无法知道是否创建了具有相同用户句柄的第二个凭证会将第一个凭证移除。

preferred

此值表示依赖方强烈倾向于创建客户端可发现的凭证,但会接受服务器端凭证。例如,如果需要创建客户端可发现的凭证,用户代理应引导用户设置用户验证。在这种情况下,这优先于userVerification的设置。

required

此值表示依赖方要求创建一个客户端可发现的凭证,并且如果无法创建客户端可发现的凭证,则会接受错误。

注意: 依赖方可以通过检查凭证属性扩展的返回值,结合提供的值 options.authenticatorSelection.residentKey,了解认证器是否创建了客户端可发现的凭证。当discouragedpreferred用于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提供此类证明。

如果允许,用户代理应在调用时向认证器发出请求企业证明的信号,并将结果中的AAGUID证明声明未更改地传达给依赖方

5.5. 断言生成选项 (字典 PublicKeyCredentialRequestOptions)

PublicKeyCredentialRequestOptions

在所有当前引擎中。

Firefox60+Safari13+Chrome67+
Opera54+Edge79+
Edge (旧版)IE
Firefox for Android?iOS Safari13.3+Chrome for Android67+Android WebView67+三星 InternetOpera 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+三星 InternetOpera 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+三星 InternetOpera Mobile48+

timeout, 类型 unsigned long

此可选成员指定调用完成所愿等待的时间(以毫秒为单位)。该值被视为提示,且可能会被客户端覆盖。

PublicKeyCredentialRequestOptions/rpId

在所有当前引擎中。

Firefox60+Safari13+Chrome67+
Opera54+Edge79+
Edge (旧版)IE
Firefox for Android?iOS Safari13.3+Chrome for Android67+Android WebView67+三星 InternetOpera Mobile48+

rpId, 类型 USVString

此可选成员指定调用方声称的依赖方标识符。如果省略,其值将为CredentialsContainer 对象的相关设置对象来源有效域

PublicKeyCredentialRequestOptions/allowCredentials

在所有当前引擎中。

Firefox60+Safari13+Chrome67+
Opera54+Edge79+
Edge (旧版)IE
Firefox for Android?iOS Safari13.3+Chrome for Android67+Android WebView67+三星 InternetOpera 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+三星 InternetOpera 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+三星 InternetOpera Mobile48+

PublicKeyCredentialRequestOptions/extensions

在所有当前引擎中。

Firefox60+Safari13+Chrome67+
Opera54+Edge79+
Edge (旧版)IE
Firefox for Android?iOS Safari13.3+Chrome for Android67+Android WebView67+三星 InternetOpera 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)。

注意:下面定义的类型——AuthenticationExtensionsClientInputsAuthenticationExtensionsClientOutputs—— 适用于 注册扩展认证扩展。 其名称中的“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, 类型 DOMString

此成员包含请求者的完全限定的来源,由客户端提供给认证器,格式为[RFC6454]定义的语法。

crossOrigin, 类型 boolean

此成员包含传递给内部方法sameOriginWithAncestors参数值的反值。

tokenBinding, 类型 TokenBinding

此可选成员包含关于与依赖方通信时使用的令牌绑定协议[TokenBinding]状态的信息。它的缺失表示客户端不支持令牌绑定。

status, 类型 DOMString

此成员应该是TokenBindingStatus的成员,但客户端平台必须忽略未知的值,将未知的值视为tokenBinding 成员不存在。已知时,此成员是以下之一:

supported

表示客户端支持令牌绑定,但在与依赖方通信时未协商使用。

present

表示在与依赖方通信时使用了令牌绑定。在这种情况下,必须存在id成员。

注意: TokenBindingStatus枚举故意不被引用,见§ 2.1.1 枚举作为 DOMString 类型

id, 类型 DOMString

如果statuspresent,则此成员必须存在,并且必须是使用与依赖方通信时使用的令牌绑定 IDbase64url 编码

注意:获取令牌绑定 ID客户端平台的特定操作。

客户端使用CollectedClientData结构来计算以下数量:

客户端数据的 JSON 兼容序列化

这是对CollectedClientData字典执行JSON 兼容序列化算法的结果。

序列化客户端数据的哈希值

这是客户端构造的客户端数据 JSON 兼容序列化的哈希值(使用 SHA-256 计算)。

5.8.1.1. 序列化

CollectedClientData的序列化是JSON 序列化为字节算法的一个子集。也就是说,它生成了CollectedClientData的有效 JSON 编码,但也提供了额外的结构,验证器可以利用这些结构来避免集成完整的 JSON 解析器。虽然建议验证器执行标准的 JSON 解析,但在完整 JSON 解析器体积过大的情况下,它们可以在上下文中使用以下更有限的算法。此验证算法只需要base64url 编码、字节串的追加(可以通过在固定模板中写入实现)以及三个条件检查(假设输入已知不需要转义)。

序列化算法通过将连续的字节串追加到最初为空的部分结果中,直到获得完整的结果。

  1. result为空字节串。

  2. 将0x7b2274797065223a({"type":)追加到result

  3. CCDToString(type)追加到result

  4. 将0x2c226368616c6c656e6765223a(,"challenge":)追加到result

  5. CCDToString(challenge)追加到result

  6. 将0x2c226f726967696e223a(,"origin":)追加到result

  7. CCDToString(origin)追加到result

  8. 将0x2c2263726f73734f726967696e223a(,"crossOrigin":)追加到result

  9. 如果crossOrigin不存在或为false

    1. 将0x66616c7365(false)追加到result

  10. 否则:

    1. 将0x74727565(true)追加到result

  11. 创建CollectedClientData的临时副本,并删除字段typechallengeorigincrossOrigin(如果存在)。

  12. 如果临时副本中没有剩余字段:

    1. 将0x7d(})追加到result

  13. 否则:

    1. 调用将 JSON 序列化为字节,在临时副本上产生字节串remainder

    2. 将0x2c(,)追加到result

    3. 移除remainder的前导字节。

    4. remainder追加到result

  14. 序列化的结果是result的值。

在上述算法中使用的函数CCDToString定义如下:

  1. encoded为空字节串。

  2. 将0x22(")追加到encoded

  3. 调用ToString将给定对象转换为字符串。

  4. 对于结果字符串中的每个代码点,如果代码点:

    属于集合 {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的数字。

  5. 将0x22(")追加到encoded

  6. 该函数的结果是encoded的值。

5.8.1.2. 有限验证算法

如果验证器无法支持完整的 JSON 解析器,可以使用以下算法来验证编码的CollectedClientData

  1. 该算法的输入包括:

    1. 一个字节串clientDataJSON,其中包含clientDataJSON——要验证的序列化的CollectedClientData

    2. 一个字符串type,其中包含预期的type

    3. 一个字节串challenge,其中包含在PublicKeyCredentialRequestOptionsPublicKeyCredentialCreationOptions中提供的挑战字节串。

    4. 一个字符串origin,其中包含向用户代理发出请求的预期origin

    5. 一个布尔值crossOrigin,当且仅当请求应在跨源iframe内执行时,该值为true。

  2. expected为空字节串。

  3. 将0x7b2274797065223a({"type":)追加到expected

  4. CCDToString(type)追加到expected

  5. 将0x2c226368616c6c656e6765223a(,"challenge":)追加到expected

  6. challenge执行base64url 编码,生成字符串challengeBase64

  7. CCDToString(challengeBase64)追加到expected

  8. 将0x2c226f726967696e223a(,"origin":)追加到expected

  9. CCDToString(origin)追加到expected

  10. 将0x2c2263726f73734f726967696e223a(,"crossOrigin":)追加到expected

  11. 如果crossOrigin为true:

    1. 将0x74727565(true)追加到expected

  12. 否则,即crossOrigin为false:

    1. 将0x66616c7365(false)追加到expected

  13. 如果expected不是clientDataJSON的前缀,则验证失败。

  14. 如果clientDataJSON长度不比expected长至少一个字节,则验证失败。

  15. 如果clientDataJSON在与expected长度相等的偏移处的字节:

    是0x7d

    验证成功。

    是0x2c

    验证成功。

    否则

    验证失败。

5.8.1.3. 未来开发

为了与有限验证算法保持兼容,未来版本的规范不得删除typechallengeorigincrossOrigin字段从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 枚举的成员,但 客户端平台 必须忽略具有未知 typePublicKeyCredentialDescriptor

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 类型的枚举

认证器 可能实现各种 传输客户端进行通信。此枚举定义了客户端可能如何与特定认证器通信以获取特定凭证的断言的提示。请注意,这些提示表示 WebAuthn 依赖方 对认证器可能的联系方式的最佳猜测。依赖方 通常会通过 getTransports() 获知公钥凭证的支持传输方式。
usb

表示相应的认证器可以通过可移除的 USB 联系。

nfc

表示相应的认证器可以通过近场通信 (NFC) 联系。

ble

表示相应的认证器可以通过蓝牙智能(蓝牙低能耗/BLE)联系。

internal

表示相应的认证器通过客户端设备特定传输方式联系,即它是平台认证器。这些认证器无法从客户端设备中移除。

5.8.5. 加密算法标识符 (typedef COSEAlgorithmIdentifier)

typedef long COSEAlgorithmIdentifier;
COSEAlgorithmIdentifier的 值是一个用于标识加密算法的数字。 算法标识符应为 IANA COSE 算法注册表中注册的值 [IANA-COSE-ALGS-REG], 例如,"ES256" 对应的代码为-7,"RS256" 对应的代码为 -257

COSE 算法注册表允许在 COSE 密钥中由其他参数指定的自由度。为了促进互操作性,本规范对凭证公钥做出以下额外保证:

  1. 使用算法 ES256 (-7) 的密钥必须将 P-256 (1) 指定为 crv 参数,且不得使用压缩点形式。

  2. 使用算法 ES384 (-35) 的密钥必须将 P-384 (2) 指定为 crv 参数,且不得使用压缩点形式。

  3. 使用算法 ES512 (-36) 的密钥必须将 P-521 (3) 指定为 crv 参数,且不得使用压缩点形式。

  4. 使用算法 EdDSA (-8) 的密钥必须将 Ed25519 (6) 指定为 crv 参数。(这些在 COSE 中总是使用压缩形式。)

注意: 使用这些算法正确实现签名验证需要进行许多检查。其中之一是,在处理未压缩的椭圆曲线点时,实施应检查点是否实际上在曲线上。特别强调此检查,因为它被认为是最有可能在加密库与其他代码之间被忽略的地方。

5.8.6. 用户验证要求枚举 (枚举 UserVerificationRequirement)

enum UserVerificationRequirement {
    "required",
    "preferred",
    "discouraged"
};

WebAuthn 依赖方 可能会要求在某些操作中进行用户验证,而在其他操作中则不需要,并且可以使用此类型来表达其需求。

注意: 枚举UserVerificationRequirement 故意不被引用,请参见 § 2.1.1 作为 DOMString 类型的枚举

required

此值表示依赖方要求在操作中进行用户验证,如果响应中未设置UV 标志,则操作将失败。

preferred

此值表示依赖方更喜欢在操作中进行用户验证,但如果响应中未设置UV 标志,操作也不会失败。

discouraged

此值表示依赖方不希望在操作中使用用户验证(例如,为了尽量减少对用户交互流程的干扰)。

5.9. 权限策略集成

Headers/Feature-Policy/publickey-credentials-get

仅在一个当前引擎中可用。

FirefoxSafariChrome84+
OperaEdge84+
Edge (旧版)IE
Firefox for AndroidiOS SafariChrome for Android84+Android WebView84+Samsung InternetOpera 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 签名。这些数据在签名请求从服务器传递到认证器的过程中,在堆栈的不同级别上被观察并添加。在验证签名时,服务器会将这些绑定与预期值进行检查。这些上下文绑定分为两部分:一部分由依赖方或客户端添加,称为客户端数据;另一部分由认证器添加,称为认证器数据。认证器对客户端数据进行签名,但除此之外对其内容不感兴趣。为了节省认证器的带宽和处理要求,客户端对客户端数据进行哈希,并仅将结果发送给认证器。认证器对客户端数据序列化后的哈希值与其自身的认证器数据的组合进行签名。

该设计的目标可以总结如下。

认证器生成的加密签名有两个不同的目的:

  1. 当通过 authenticatorMakeCredential 操作创建新的 公钥凭据 时,会生成一个认证签名认证签名认证器和凭据的某些属性提供加密证明。例如,认证签名声明了认证器类型(如其 AAGUID 所表示)和凭据公钥认证签名认证私钥签名,该私钥根据所需的认证类型选择。有关认证的更多详细信息,请参阅§ 6.5 认证

  2. 当调用 authenticatorGetAssertion 方法时,会生成一个声明签名。它表示认证器对用户同意特定事务(如登录或完成购买)的声明。因此,声明签名表示持有特定凭据私钥认证器已经尽其所能确认请求此事务的用户与创建该特定公钥凭据同意的用户是同一人。它还断言了额外的信息,即称为客户端数据,这对调用者可能有用,例如用户同意的方式,以及认证器向用户显示的提示。声明签名的格式如图 4所示。

WebAuthn 签名一词指的是认证签名声明签名。这些签名的格式以及生成它们的过程将在下文中指定。

6.1. 认证器数据

认证器数据结构编码了由认证器生成的上下文绑定。这些绑定由认证器本身控制,并从WebAuthn 依赖方对认证器安全属性的评估中获得信任。在一种极端情况下,认证器可能嵌入在客户端中,其绑定的可信度可能不会超过客户端数据。在另一种极端情况下,认证器可能是具有高安全硬件和软件的独立实体,通过安全通道连接到客户端。在这两种情况下,依赖方以相同的格式接收认证器数据,并根据对认证器的了解做出信任决策。

认证器数据具有紧凑但可扩展的编码。这是期望的,因为认证器可能是具有有限能力和低功耗需求的设备,其软件栈远比客户端平台简单得多。

认证器数据结构是一个37字节或更多的字节数组,如所示。

名称 长度(字节) 描述
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完全匹配来验证它。

认证器执行以下步骤以生成认证器数据结构

展示了认证器数据结构的视觉表示。

认证器数据布局。
注意: 认证器数据描述了它自己的长度:如果AT和ED 标志未设置,则它的长度总是37字节。 认证凭证数据(仅在AT 标志设置时存在)描述了它自己的长度。如果ED 标志设置了,那么总长度为37字节加上认证凭证数据的长度(如果设置了AT 标志),再加上扩展输出的长度(一个CBOR映射)紧随其后。

确定认证凭证数据的长度是可变的,涉及确定凭证公钥的起始位置,取决于前面的凭证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. 认证器分类

许多使用案例取决于所使用的认证器的功能。 本节定义了这些功能的一些术语、它们的重要组合及其启用的使用案例。

例如:

以上示例说明了主要的认证器类型特征:

这些特征是独立的,理论上可以以任何方式组合,但列出了特别感兴趣的一些认证器类型并命名了它们。

认证器类型 认证器附着模式 凭证存储模式 身份验证因素能力
第二因素平台认证器 平台 任意 单因素能力
用户验证平台认证器 平台 任意 多因素能力
第二因素漫游认证器 跨平台 服务器端存储 单因素能力
第一因素漫游认证器 跨平台 客户端存储 多因素能力
一些认证器类型名称的定义。

一个第二因素平台认证器在同一客户端设备上重新进行身份验证时使用方便,并且可以在启动新会话和恢复现有会话时增加一层额外的安全性。一个第二因素漫游认证器更有可能在特定的客户端设备上首次进行身份验证,或者在多个用户共享的客户端设备上使用。

用户验证平台认证器第一因素漫游认证器支持无密码多因素身份验证。除了证明凭证私钥的持有之外,这些认证器还支持作为第二身份验证因素用户验证,通常是PIN码或生物识别。认证器因此可以作为两种身份验证因素,从而实现多因素身份验证,同时无需与依赖方共享密码。

中未命名的四种组合的使用案例较少:

以下小节更深入地定义了认证器附着模式凭证存储模式身份验证因素能力的各个方面。

6.2.1. 认证器附着模式

客户端可以通过多种机制与认证器通信。例如,客户端可以使用客户端设备特定的API与物理绑定到客户端设备认证器通信。另一方面,客户端可以使用各种标准化的跨平台传输协议(例如蓝牙,参见§ 5.8.4 认证器传输枚举 (enum AuthenticatorTransport))来发现和通信与跨平台附着认证器。我们将作为客户端设备一部分的认证器称为平台认证器,而那些通过跨平台传输协议可访问的则称为漫游认证器

某些平台认证器在某些情况下也可以作为漫游认证器。例如,集成到移动设备中的平台认证器可以通过蓝牙作为漫游认证器提供服务。在这种情况下,运行在移动设备上的客户端将识别该认证器为平台认证器,而通过蓝牙与同一认证器通信的不同客户端设备上运行的客户端则会将其识别为漫游认证器

平台认证器的主要使用场景是将特定的客户端设备注册为“受信任设备”,使得该客户端设备本身作为未来您拥有的某物 身份验证因素进行身份验证。这使得用户无需在未来的身份验证仪式中使用漫游认证器,例如,用户不必在口袋里翻找钥匙扣或手机。

漫游认证器的使用场景包括:首次在新客户端设备上进行身份验证,在很少使用的客户端设备上进行身份验证,在多个用户共享的客户端设备上进行身份验证,或者在不包含平台认证器客户端设备上进行身份验证;以及当策略或偏好要求认证器与其使用的客户端设备分离时使用。漫游认证器还可以用来持有备份的凭证,以防另一个认证器丢失。

6.2.2. 凭证存储模式

认证器可以通过以下两种方式之一存储公钥凭证源

  1. 在嵌入认证器客户端客户端设备中的持久性存储中,例如在安全元素中。这是客户端可发现的公钥凭证源的技术要求。

  2. 通过加密(即封装)凭证私钥,使得只有这个认证器能够解密(即解封装)它,并让生成的密文成为凭证ID,用于公钥凭证源凭证ID依赖方存储,并通过allowCredentials选项在get()操作中返回给认证器,允许认证器解密并使用凭证私钥

    这使得认证器能够拥有无限的凭证私钥存储容量,因为加密的凭证私钥依赖方而非认证器存储——但这意味着以这种方式存储的凭证必须先从依赖方检索回来,认证器才能使用它。

这些存储策略中的哪一种由认证器支持,定义了该认证器凭证存储模式,具体如下:

请注意,具有可发现凭证能力认证器可以同时支持这两种存储策略。在这种情况下,认证器可以自行决定对不同的凭证使用不同的存储策略,但必须遵守residentKeyrequireResidentKey选项的要求。

6.2.3. 认证因子能力

认证过程中,用于证明身份的认证因子主要有三大类:所持物所知物,和所是物。例如,分别对应物理钥匙、密码和指纹。

所有WebAuthn 认证器都属于所持物类,但如果一个认证器支持用户验证,它也可以作为一种或两种额外的认证因子。例如,如果认证器可以验证 PIN 码,则 PIN 码属于所知物,而生物识别认证器可以验证所是物。因此,一个支持用户验证认证器被称为多因子能力。反之,一个不具备多因子能力认证器被称为单因子能力。请注意,单个多因子能力认证器可能支持多种用户验证模式,这意味着它可以作为所有三种认证因子

虽然用户验证是在认证器上本地执行的,而不是由依赖方执行的,但认证器通过在返回给依赖方的签名响应中设置UV 标志来指示是否进行了用户验证。因此,依赖方可以使用UV标志来验证在注册认证过程中是否使用了额外的认证因子UV 标志的真实性可以通过检查认证器认证声明来评估。

6.3. 认证器操作

一个WebAuthn 客户端必须连接到认证器,才能调用该认证器的任何操作。此连接定义为认证器会话。认证器必须在会话之间保持隔离。它可以通过仅允许一个会话在任何特定时间存在,或者通过提供更复杂的会话管理来实现这一点。

客户端可以在认证器会话中调用以下操作。

6.3.1. 通过凭据 ID 查找凭据源算法

认证器 authenticator查找凭据 ID credentialId的结果是以下算法的结果:

  1. 如果authenticator可以将credentialId解密为公钥凭据源 credSource

    1. credSource.id设置为credentialId

    2. 返回credSource

  2. 对于每个 公钥凭据源 credSource,在authenticator凭据映射中:

    1. 如果credSource.idcredentialId,则返回credSource

  3. 返回null

6.3.2. The authenticatorMakeCredential 操作

此操作接受以下输入参数:

hash

由客户端提供的序列化客户端数据的哈希

rpEntity

依赖方PublicKeyCredentialRpEntity

userEntity

用户账户的PublicKeyCredentialUserEntity, 包含用户句柄,由依赖方提供。

requireResidentKey

凭据创建的有效常驻密钥要求,由客户端确定的布尔值。

requireUserPresence

布尔常量值true。 它作为伪参数包含在此处,以简化将此抽象认证器模型应用于可能希望使用户存在测试可选的实现,尽管 WebAuthn 并不要求这样做。

requireUserVerification

凭据创建的有效用户验证要求,由客户端确定的布尔值。

credTypesAndPubKeyAlgs

依赖方请求的PublicKeyCredentialType和公钥算法(COSEAlgorithmIdentifier)对的序列。此序列按从最优先到最不优先的顺序排列。认证器尽最大努力创建其可以支持的最优先的凭据。

excludeCredentialDescriptorList

依赖方提供的PublicKeyCredentialDescriptor对象的可选列表,意图是如果认证器已知其中的任何一个,则不应创建新凭据。excludeCredentialDescriptorList包含已知凭据的列表。

enterpriseAttestationPossible

一个布尔值,指示认证器可能返回单独标识的认证。

extensions

客户端基于依赖方(如果有)请求的扩展创建的从扩展标识符到其认证器扩展输入CBOR map

注意:在执行此操作之前,必须通过运行认证器取消操作,终止在认证器会话中进行的所有其他操作。

当调用此操作时,认证器必须执行以下过程:

  1. 检查所有提供的参数是否在语法上格式正确且长度正确。如果不正确,返回等效于"UnknownError"的错误代码并终止操作。

  2. 检查credTypesAndPubKeyAlgs中指定的至少一个PublicKeyCredentialType和密码参数组合是否受支持。如果不支持,返回等效于"NotSupportedError"的错误代码并终止操作。

  3. 对于每个descriptorexcludeCredentialDescriptorList中:

    1. 如果查找 descriptor.id在此认证器中返回非空,并且返回的RP ID类型分别与rpEntity.idexcludeCredentialDescriptorList.类型匹配, 然后收集一个确认创建新凭据的授权手势授权手势必须包括用户存在测试。如果用户

      确认同意创建新凭据

      返回等效于"InvalidStateError"的错误代码并终止操作。

      不同意创建新凭据

      返回等效于"NotAllowedError"的错误代码并终止操作。

      注意:授权手势的目的是为了隐私原因授权披露 descriptor.id绑定到此认证器的事实,而不是继续创建凭据。如果用户同意,客户端依赖方可以检测到这一点,并指导用户使用不同的认证器。如果用户不同意,认证器不会披露 descriptor.id绑定到它,并表现得像用户只是拒绝同意创建凭据一样。

  4. 如果requireResidentKeytrue且认证器无法存储客户端可发现的公钥凭据源, 返回等效于"ConstraintError"的错误代码并终止操作。

  5. 如果requireUserVerificationtrue且认证器无法执行用户验证,返回等效于"ConstraintError"的错误代码并终止操作。

  6. 一旦授权手势完成并获得用户同意,生成一个新的凭据对象:

    1. 令(publicKey, privateKey)为一对新的加密密钥,使用PublicKeyCredentialType和由此认证器支持的credTypesAndPubKeyAlgs中的第一个项目表示的加密参数组合生成。

    2. userHandle成为userEntity.id

    3. credentialSource成为新的公钥凭据源,其字段如下:

      类型

      public-key

      私钥

      privateKey

      RP ID

      rpEntity.id

      用户句柄

      userHandle

      其他用户界面信息

      认证器选择包含的任何其他信息。

    4. 如果requireResidentKeytrue或认证器选择创建客户端可发现的公钥凭据源

      1. credentialId成为新的凭据 ID

      2. credentialSource.ID设置为credentialId

      3. credentials成为此认证器的凭据映射

      4. 设置credentials[(rpEntity.iduserHandle)]到credentialSource

    5. 否则:

      1. credentialId成为序列化并加密的credentialSource,以便只有此认证器可以解密它。

  7. 如果在创建新凭据对象时发生任何错误,返回等效于"UnknownError"的错误代码并终止操作。

  8. processedExtensions成为结果,认证器扩展处理的结果,对于每个支持的扩展标识符认证器扩展输入extensions中。

  9. 如果认证器

    是 U2F 设备

    让新凭据的签名计数器值为零。 (U2F 设备可能支持签名计数器,但在创建凭据时不会返回计数器。参见[FIDO-U2F-Message-Formats]。)

    支持全局签名计数器

    在生成认证器数据时,使用全局签名计数器的实际值。

    支持每个凭据签名计数器

    分配计数器,将其与新凭据关联,并将计数器值初始化为零。

    不支持签名计数器

    让新凭据的签名计数器值恒定为零。

  10. attestedCredentialData成为包括credentialIdpublicKey认证凭据数据字节数组。

  11. authenticatorData成为字节数组,如§ 6.1 认证器数据中所述,包括attestedCredentialData作为attestedCredentialDataprocessedExtensions(如果有的话)作为扩展

  12. 为新凭据创建认证对象,使用§ 6.5.4 生成认证对象中规定的程序,使用由认证器选择的认证声明格式authenticatorDatahash,并考虑到enterpriseAttestationPossible的值。有关认证的更多详细信息,请参见§ 6.5 认证

成功完成此操作后,认证器将认证对象返回给客户端。

6.3.3. authenticatorGetAssertion 操作

它接受以下输入参数:

rpId

调用者的RP ID,由用户代理和客户端确定

hash

客户端提供的序列化客户端数据的哈希值

allowCredentialDescriptorList

一个可选的列表,包含描述Relying Party可接受的凭据的PublicKeyCredentialDescriptor对象(可能由客户端过滤),如果有的话。

requireUserPresence

常量布尔值true。 这里将其作为伪参数包含在内,以简化将此抽象认证器模型应用于可能希望使用户在场测试可选的实现,尽管 WebAuthn 不允许这样做。

requireUserVerification

用于断言的有效用户验证要求,由客户端提供的布尔值。

extensions

由客户端基于Relying Party请求的扩展(如果有)创建的CBOR 映射,从扩展标识符到其认证器扩展输入

注意: 在执行此操作之前,必须通过运行authenticatorCancel操作终止认证器会话中的所有其他正在进行的操作。

当调用此方法时,认证器必须执行以下步骤:

  1. 检查所有提供的参数是否在语法上正确且长度正确。如果不正确,返回等效于"UnknownError"的错误代码并终止操作。

  2. credentialOptions成为一个新的空集合,用于存储公钥凭据源

  3. 如果提供了allowCredentialDescriptorList,则对每个allowCredentialDescriptorList中的descriptor执行以下操作:

    1. credSource成为此认证器中查找descriptor.id的结果。

    2. 如果credSource不为null,则将其附加credentialOptions

  4. 否则(未提供allowCredentialDescriptorList),对每个此认证器的凭据映射中的keycredSource执行操作,并credSource附加到credentialOptions

  5. credentialOptions中删除rpId不等于指定rpId的所有项。

  6. 如果credentialOptions现在为空,则返回等效于"NotAllowedError"的错误代码并终止操作。

  7. 提示用户从credentialOptions中选择一个公钥凭据源 selectedCredential。 收集一个授权手势,确认用户同意使用selectedCredential。 如果认证器具有自己的输出能力,则授权手势提示可以由认证器显示,否则由用户代理显示。

    如果requireUserVerificationtrue,则授权手势必须包括用户验证

    如果requireUserPresencetrue,则授权手势必须包括用户在场测试

    如果用户不同意,返回等效于"NotAllowedError"的错误代码并终止操作。

  8. processedExtensions成为认证器扩展处理的结果,对每个extensions中的支持的扩展标识符认证器扩展输入

  9. 增加与凭据相关的签名计数器或全局签名计数器值,具体取决于认证器实现的方式,通过某个正值。如果认证器不实现签名计数器,则让签名计数器的值保持为零。

  10. authenticatorData成为字节数组,如§ 6.1 认证器数据中所述,包括processedExtensions(如果有的话)作为扩展,并排除认证的凭据数据

  11. signature成为使用selectedCredentialprivateKeyauthenticatorData || hash串联生成的断言签名。此处可以安全地使用简单的未分隔串联,因为认证器数据描述了自己的长度。序列化客户端数据的哈希(可能具有可变长度)始终是最后一个元素。

    生成断言签名
  12. 如果在生成断言签名时发生任何错误,返回等效于"UnknownError"的错误代码并终止操作。

  13. 返回给用户代理:
    • selectedCredential.id,如果客户端提供了长度为2或更长的凭据列表(即allowCredentialDescriptorList)或未提供此类列表。

      注意: 如果客户端在allowCredentialDescriptorList中仅提供了一个凭据,并且成功使用了该凭据,则不会返回其凭据 ID,因为客户端已经知道它。这可以节省在可能是常见情况下通过可能受限连接传输这些字节的资源。

    • authenticatorData

    • signature

    • selectedCredential.userHandle

      注意: 返回的userHandle值可能为null,请参见:userHandleResult

如果认证器找不到与指定Relying Party匹配的任何符合指定条件的凭据,则它会终止操作并返回错误。

6.3.4. authenticatorCancel 操作

此操作不接受任何输入参数,也不返回任何结果。

当客户端在认证器会话中调用此操作时,它会终止该认证器会话中当前正在进行的任何authenticatorMakeCredentialauthenticatorGetAssertion操作。认证器停止提示或接受与已取消操作相关的任何用户输入。客户端忽略认证器对已取消操作的任何进一步响应。

如果在没有正在进行的authenticatorMakeCredentialauthenticatorGetAssertion操作的认证器会话中调用此操作,则此操作会被忽略。

6.4. 字符串处理

认证器可能需要存储由Relying Party选择的任意字符串,例如在namedisplayName字段中的PublicKeyCredentialUserEntity对象。本节讨论了处理可能呈现给人类的任意字符串的一些实际影响。

6.4.1. 字符串截断

API中的每个任意字符串都会考虑到认证器可能可用的有限资源。如果选择字符串值截断作为适应措施,则认证器可以截断字符串以使其适合等于或大于指定的最小支持长度的长度。此类截断还应尊重UTF-8序列边界或字素簇边界[UTR29]。这定义了允许的最大截断,认证器不得进一步截断。

例如,在中,字符串长度为65字节。如果截断到64字节,则必须出于空间原因删除最后的0x88字节。由于这留下了部分UTF-8序列,因此该序列的剩余部分也可能会被删除。由于这留下了部分字素簇,认证器可以删除该簇的其余部分。

UTF-8编码字符串的末尾,显示不同截断边界的位置。

符合标准的用户代理负责确保Relying Party观察到的认证器行为在字符串处理方面符合此规范。例如,如果已知认证器在被要求存储大字符串时表现不正确,用户代理应为其执行截断以保持从Relying Party视角来看的一致性。执行此操作的用户代理应在字素簇边界处截断。

基于UTF-8序列的截断可能会导致字素簇被截断。这可能导致字素簇呈现为不同的字形,潜在地改变字符串的含义,而不是完全删除字形。

此外,仅在字节边界上截断会导致一个已知问题,用户代理应该意识到这一点:如果认证器使用[FIDO-CTAP],那么来自认证器的未来消息可能包含无效的CBOR,因为该值被类型化为CBOR字符串,因此需要有效的UTF-8。用户代理的任务是处理此问题,以避免让认证器理解字符编码和Unicode字符属性的负担。因此,当与认证器交互时,用户代理应:

  1. 确保发送给认证器的任何字符串都是有效编码的。

  2. 处理字符串截断导致的无效编码情况。例如,可以删除或用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值,具体取决于语言是否被编码。(由于方向明确,此示例中不需要方向性标记。)

可能带有语言和方向编码的字符串的消费者应该意识到,截断可能会将语言标签截断为不同但仍然有效的语言。最终的方向性标记或取消标签代码点提供了截断的明确指示。

6.5. 认证

认证器还应该在可能的情况下提供某种形式的证明。如果认证器提供证明,基本要求是认证器能够为每个凭证公钥生成一个证明声明,可由WebAuthn 依赖方验证。通常,这个证明声明包含由一个证明私钥对已认证的凭证公钥和挑战进行的签名,以及提供证明公钥来源信息的证书或类似数据,使依赖方能够做出信任决策。然而,如果证明密钥对不可用,则认证器可以执行凭证公钥和相应的凭证私钥的自我证明,或者执行无证明。所有这些信息都由认证器在生成新公钥凭证时返回,总体形式为证明对象。证明对象与认证数据(包含已认证的凭证数据)和证明声明的关系在下面的图中说明。

如果认证器使用了自我证明不进行证明,则不会提供供依赖方做出信任决策的来源信息。在这些情况下,认证器不对其操作向依赖方提供任何保证。

证明对象布局,展示了所包含的认证器数据(包含已证明的凭证数据)和证明声明
该图仅说明了packed 认证声明格式。在§ 8定义的认证声明格式中定义了几种其他认证声明格式

认证对象的一个重要组成部分是认证声明。这是一个特定类型的签名数据对象,包含有关公钥凭证本身和创建它的认证器的声明。它包含使用认证机构的密钥生成的认证签名(除非是自认证的情况,此时使用的是凭证私钥)。为了正确解释认证声明依赖方需要理解认证的以下两个方面:

  1. 认证声明格式是签名的表示方式,以及各种上下文绑定是如何被认证器合并到认证声明中的。换句话说,这定义了声明的语法。各种现有的组件和操作系统平台(如TPM和Android OS)已经定义了认证声明格式。本规范以可扩展的方式支持多种格式,如§ 6.5.2 认证声明格式中定义的那样。格式本身由字符串标识,如§ 8.1认证声明格式标识符中所述。

  2. 认证类型定义了认证声明及其底层信任模型的语义。具体而言,它定义了依赖方在验证认证声明的加密有效性后,如何建立对特定认证声明的信任。本规范支持多种认证类型,如§ 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 type
  3:  -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 type
  3: -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 type
  3:-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. 证明声明格式

如上所述,证明声明格式是指由验证器对一组上下文绑定进行加密签名的数据格式。每个证明声明格式必须使用以下模板定义:

指定的证明声明格式的初始列表在 § 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 动态生成每个凭证证明证书,以确保向信赖方展示的证明声明不会提供可能用于跟踪的唯一可识别信息。

注意: 传递证明类型AttCAAnonCA证明声明使用与类型类型基本的证明声明相同的数据结构,因此这三种证明类型通常只能通过外部提供的有关证明证书内容的知识来区分。

无证明声明 ()

在这种情况下,不提供证明信息。另见§ 8.7 无证明声明格式

6.5.4. 生成证明对象

要生成一个证明对象(参见:图 6),需要给定以下内容:

attestationFormat

一个证明声明格式

authData

包含验证器数据的字节数组。

hash

序列化客户端数据的哈希值

验证器必须:

  1. attStmt成为运行attestationFormat签名过程的结果,给定authDatahash

  2. fmt成为attestationFormat证明声明格式标识符

  3. 返回证明对象,作为包含以下语法的 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 证明和声明签名的签名格式

建议任何新定义的证明格式不要使用 ASN.1 编码,而是使用与 [RFC8152][RFC8230] 中定义的 COSE 签名使用的表示方法相同的固定长度字节数组来表示签名,无需内部结构。

以下签名格式定义满足此要求,并作为派生其他未明确提及的签名算法的示例:

7. WebAuthn 证明对象 操作

一个注册认证仪式开始于WebAuthn 证明对象 创建一个PublicKeyCredentialCreationOptionsPublicKeyCredentialRequestOptions对象,这些对象分别编码了仪式的参数。证明对象 应该注意在这个阶段不要泄露敏感信息;详细信息见§ 14.6.2 用户名枚举

在成功执行create()get()后, 证明对象的脚本会接收到一个PublicKeyCredential,其中包含一个AuthenticatorAttestationResponseAuthenticatorAssertionResponse 结构,这些结构分别来自客户端。然后,它必须使用本规范之外的方法将这些结构的内容传送到证明对象服务器。这一节描述了证明对象在接收到这些结构后必须执行的操作。

7.1. 注册一个新的凭证

为了执行注册仪式证明对象 必须按如下步骤进行:

  1. options成为一个新的PublicKeyCredentialCreationOptions 结构,并根据证明对象的需求进行配置。

  2. 调用navigator.credentials.create() 并将options作为publicKey选项传递。让credential成为成功解决的promise的结果。如果promise被拒绝,则使用用户可见的错误中止仪式,或根据拒绝的promise中的可用上下文引导用户体验。例如,如果promise因错误代码等同于InvalidStateError而被拒绝,用户可能会被指示使用不同的认证器。有关不同错误上下文及导致它们的情况的信息,请参见§ 6.3.2 认证器创建凭证操作

  3. response成为credential.response。如果response不是AuthenticatorAttestationResponse的实例,则使用用户可见的错误中止仪式。

  4. clientExtensionResults成为调用credential.getClientExtensionResults()的结果。

  5. JSONtext成为通过UTF-8解码response.clientDataJSON值的结果。

    注意: 使用任何UTF-8解码的实现是可以接受的,只要它产生的结果与UTF-8解码算法产生的结果相同。特别是,必须去除任何前导字节顺序标记(BOM)。

  6. C,即在凭证创建期间收集的客户端数据,成为在JSONtext上运行实现特定的JSON解析器的结果。

    注意: C可以是任何实现特定的数据结构表示,只要C的组件可以被引用,如本算法所要求的那样。

  7. 验证C.type的值是否为webauthn.create

  8. 验证C.challenge的值是否等于options.challenge的base64url编码。

  9. 验证C.origin的值是否与证明对象匹配。

  10. 验证C.tokenBinding.status的值是否与获取令牌绑定的TLS连接的状态相匹配。如果在该TLS连接上使用了令牌绑定,还应验证C.tokenBinding.id的值是否与连接的base64url编码令牌绑定ID匹配。

  11. hash成为使用SHA-256对response.clientDataJSON值进行哈希计算的结果。

  12. attestationObject字段中的AuthenticatorAttestationResponse结构执行CBOR解码,以获取证明对象格式fmt认证器数据authData以及证明对象attStmt

  13. 验证authData中的rpIdHash是否是RP ID所期望的SHA-256哈希值。

  14. 验证authData中的标志用户存在位是否已设置。

  15. 如果此注册要求用户验证,请验证authData中的标志用户验证位是否已设置。

  16. 验证authData中的凭证公钥中的"alg"参数是否与alg属性匹配,options.pubKeyCredParams

  17. 验证clientExtensionResults中的客户端扩展输出authData中的认证器扩展输出是否符合预期,考虑给出的客户端扩展输入options.扩展,以及证明对象关于未经请求的扩展的特定政策,即那些未作为options.扩展的一部分指定的扩展。一般情况下,"符合预期"的含义取决于证明对象以及所使用的扩展。

    注意: 客户端平台可能会实施本地策略,该策略会设置额外的认证器扩展客户端扩展,从而导致在authData中的认证器扩展输出clientExtensionResults中的客户端扩展输出中出现原本未在options.扩展部分指定的值。证明对象必须做好处理此类情况的准备,无论是忽略这些未经请求的扩展还是拒绝认证。证明对象可以根据本地政策和所使用的扩展做出此决定。

    注意: 由于所有扩展对客户端认证器都是可选的,证明对象还必须准备处理未处理所有请求的扩展的情况。

  18. 通过在fmt与支持的WebAuthn证明对象格式标识符值集合之间执行USASCII区分大小写匹配来确定证明对象格式。WebAuthn证明对象格式标识符值的最新注册列表由IANA "WebAuthn Attestation Statement Format Identifiers"注册表[IANA-WebAuthn-Registries]维护,该注册表由[RFC8809]建立。

  19. 验证attStmt是否为正确的证明对象,传递一个有效的证明签名,通过使用fmt验证过程,给定attStmtauthDatahash

    注意: 每个证明对象格式都指定了其自己的验证过程。参见§ 8 定义的证明对象格式以获取最初定义的格式,[IANA-WebAuthn-Registries]以获取最新列表。

  20. 如果验证成功,请从可信来源或政策中获取该证明类型和证明对象格式fmt的可接受信任锚(即证明根证书)列表。例如,FIDO Metadata Service [FIDOMetadataService]提供了一种获取此类信息的方法,使用authData中的aaguid

  21. 使用步骤19中验证过程的输出评估证明的可信度,如下所示:

    • 如果没有提供证明,验证None证明在证明对象政策下是否可接受。

    • 如果使用了自我证明,验证自我证明是否在证明对象政策下可接受。

    • 否则,使用作为验证过程的证明信任路径返回的X.509证书,验证证明公钥是否正确地链到可接受的根证书,或其本身是否为可接受的证书(即,它与步骤20中获取的根证书可能是相同的)。

  22. 检查credentialId是否尚未注册到任何其他用户。如果请求为已注册到其他用户的凭证注册,证明对象应当失败此注册仪式,或可能决定接受注册,例如删除旧注册。

  23. 如果证明对象attStmt成功验证且被视为可信,则将新凭证注册到在options.user中指定的帐户中:

    建议还要:

  24. 如果证明对象attStmt成功验证但在步骤21中未被视为可信,证明对象应当失败此注册仪式。

    注意: 但是,如果政策允许,证明对象可能会注册credential ID和凭证公钥,但将凭证视为具有自我证明的凭证(参见§ 6.5.3 证明类型)。如果这样做,证明对象正在断言,没有公钥凭证是由特定认证器型号生成的密码学证明。参见[FIDOSecRef][UAFProtocol]以获取更详细的讨论。

证明对象的验证需要证明对象在上面的步骤20中有一种可信的方法来确定可接受的信任锚。此外,如果使用了证书,证明对象必须访问中间CA证书的证书状态信息。如果客户端在证明信息中未提供此链,证明对象还必须能够构建证明证书链。

7.2. 验证认证声明

为了执行认证仪式证明对象必须按如下步骤进行:

  1. options设为一个新的PublicKeyCredentialRequestOptions结构,配置为证明对象所需的仪式。

    如果options.allowCredentials存在,transports成员的每个应设置为注册相应凭据时通过调用credential.response.getTransports()返回的值。

  2. 调用navigator.credentials.get()并将options作为publicKey选项传递。让credential成为成功解决的承诺的结果。如果承诺被拒绝,则以用户可见的错误终止仪式,或以其他方式根据拒绝的承诺中可用的上下文引导用户体验。有关不同错误上下文及其导致情况的信息,请参见§ 6.3.3 认证器获取声明操作

  3. response设为credential.response。如果response不是AuthenticatorAssertionResponse的实例,则以用户可见的错误终止仪式。

  4. clientExtensionResults设为调用credential.getClientExtensionResults()的结果。

  5. 如果options.allowCredentials非空,验证credential.id是否标识options.allowCredentials中列出的公钥凭证之一。

  6. 识别正在进行身份验证的用户并验证该用户是否为credentialSource标识的公钥凭证源的所有者:

    如果在启动认证仪式之前已识别用户,例如通过用户名或cookie,

    验证识别的用户是否为credentialSource的所有者。如果response.userHandle存在,则将userHandle设为其值。验证userHandle是否也映射到同一用户。

    如果在启动认证仪式之前未识别用户,

    验证response.userHandle是否存在,并且该值标识的用户是否为credentialSource的所有者。

  7. 使用credential.id(或credential.rawId,如果不适合使用base64url编码的情况),查找相应的凭证公钥,将credentialPublicKey设为该凭证公钥

  8. cDataauthDatasig分别表示为responseclientDataJSONauthenticatorDatasignature的值。

  9. JSONtext设为对cData的值运行UTF-8解码的结果。

    注意: 使用任何UTF-8解码实现都是可接受的,只要它产生的结果与UTF-8解码算法产生的结果相同。特别是,必须去除任何前导字节顺序标记(BOM)。

  10. C(签名时声称使用的客户端数据)设为对JSONtext运行实现特定的JSON解析器的结果。

    注意: C可以是任何实现特定的数据结构表示,只要C的组件可以根据该算法的要求进行引用。

  11. 验证C.type的值是否为字符串webauthn.get

  12. 验证C.challenge的值是否等于options.challenge的base64url编码。

  13. 验证C.origin的值是否与证明对象来源匹配。

  14. 验证C.tokenBinding.status的值是否与获取证明的TLS连接的令牌绑定状态匹配。如果在该TLS连接上使用了令牌绑定,还验证C.tokenBinding.id是否与该连接的base64url编码令牌绑定ID匹配。

  15. 验证rpIdHashauthData中的值是否为证明对象期望的RP ID的SHA-256哈希值。

    注意: 如果使用了appid扩展,这一步需要一些特殊逻辑。详见§ 10.1 FIDO AppID扩展(appid)

  16. 验证flagsauthData用户在场位是否已设置。

  17. 如果此声明需要用户验证,验证flagsauthData用户已验证位是否已设置。

  18. 根据clientExtensionResults中的客户端扩展输出authData中的认证器扩展输出验证值是否如预期,考虑options.扩展中给出的客户端扩展输入值以及证明对象关于未请求的扩展(即那些未作为options.扩展的一部分指定的)政策。

    注意: 客户端平台可以制定本地政策,设置额外的认证器扩展客户端扩展,从而导致在认证器扩展输出客户端扩展输出中出现未在options.扩展中指定的值。证明对象必须准备处理这些情况,无论是忽略未请求的扩展还是拒绝声明,证明对象可以基于本地政策和所使用的扩展作出决定。

    注意: 由于扩展对于客户端认证器都是可选的,因此证明对象也必须准备处理没有执行任何或所有请求扩展的情况。

  19. hash设为对cData使用SHA-256计算的哈希结果。

  20. 使用credentialPublicKey验证sig是否为authDatahash二进制连接的有效签名。

    注意: 此验证步骤与FIDO U2F认证器生成的签名兼容。参见§ 6.1.2 FIDO U2F签名格式兼容性

  21. storedSignCount设为与credential.id关联的存储签名计数器值。如果authData.signCount为非零或storedSignCount为非零,则运行以下子步骤:

    • 如果 authData.signCount

      大于 storedSignCount:
      storedSignCount 更新为 authData.signCount 的值。
      小于或等于 storedSignCount:
      这表明认证器可能已被克隆,即至少存在两个 凭证私钥 副本,并行使用。证明对象应将此信息纳入其风险评分中。在这种情况下,证明对象是否更新 storedSignCount,或者是否让 认证仪式失败,是 证明对象 自行决定的。
  22. 如果以上所有步骤均成功,则根据需要继续进行认证仪式。否则,认证仪式失败。

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

支持的证明类型

基本自我AttCA

语法

打包证明声明的语法定义如下的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格式编码。

签名过程

此证明声明格式的签名过程类似于生成断言签名的过程

  1. authenticatorData表示证明的验证器数据, 令clientDataHash表示序列化客户端数据的哈希值

  2. 如果使用基本AttCA 证明, 验证器通过连接authenticatorDataclientDataHash来生成sig,并使用通过验证器特定机制选择的证明私钥对结果进行签名。它将x5c设置为attestnCert,后面跟随相关的 证书链(如果有)。它将alg设置为 证明私钥的算法。

  3. 如果使用自我证明,验证器通过连接authenticatorDataclientDataHash来生成sig, 并使用凭证私钥对结果进行签名。它将alg设置为 凭证私钥的算法,并省略其他字段。

验证过程

给定验证过程的输入 attStmt, authenticatorDataclientDataHash验证过程 如下:

  1. 验证attStmt是否为符合上述语法定义的有效CBOR,并对其执行CBOR解码以提取 包含的字段。

  2. 如果x5c存在:

    • 验证sig是否是使用 alg中指定的算法,通过attestnCert中的证明公钥对 authenticatorDataclientDataHash的连接进行签名的有效签名。

    • 验证attestnCert是否符合§ 8.2.1 打包证明声明 证书要求中的要求。

    • 如果attestnCert包含OID为 1.3.6.1.4.1.45724.1.1.4 (id-fido-gen-ce-aaguid)的扩展,验证 该 扩展的值是否与 aaguid 中的值一致authenticatorData

    • 可选地,检查x5c并咨询外部提供的知识以 确定attStmt是否传达了基本AttCA证明。

    • 如果成功,返回表示证明类型 基本AttCA或不确定性以及 证明信任路径 x5c的实现特定值。

  3. 如果x5c不存在,则使用自我证明

    • 验证alg是否与authenticatorData中的 credentialPublicKey 的算法匹配。

    • 验证sig是否是使用alg的算法,通过凭证公钥对 authenticatorDataclientDataHash的连接进行签名的有效签名。

    • 如果成功,返回表示证明类型 自我的实现特定值和一个空的 证明信任路径

8.2.1. 打包证明声明证书要求

证明证书必须具有以下字段/扩展:

8.3. TPM证明声明格式

此证明声明格式通常由使用可信平台模块(TPM)作为其加密 引擎的验证器使用。

证明声明格式标识符

tpm

支持的证明类型

AttCA

语法

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表示序列化客户端数据的哈希值

authenticatorDataclientDataHash连接 形成 attToBeSigned

使用[TPMv2-Part3]第18.2节中规定的过程生成签名, 使用证明私钥 并将extraData参数设置为使用"alg"签名算法的哈希算法生成的attToBeSigned摘要。 (对于"RS256"算法,这将是SHA-256摘要。)

pubArea字段设置为凭证公钥的公共区域,将 certInfo字段设置为相同名称的 输出参数,并将sig字段设置为从上述过程获得的签名。

验证过程

给定验证过程的输入 attStmt, authenticatorDataclientDataHash验证过程如下:

验证attStmt是否为符合上述语法定义的有效CBOR,并对其执行 CBOR解码以提取 包含的字段。

验证由parametersunique字段指定的 公钥是否与 credentialPublicKey 中的公钥一致 attestedCredentialDataauthenticatorData中。

authenticatorDataclientDataHash连接形成 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节中, 即 qualifiedSignerclockInfofirmwareVersion被忽略。 这些字段可以用作风险引擎的输入。

  • 验证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),验证该扩展的值是否与 aaguidauthenticatorData的一致。

  • 如果成功,返回表示证明类型 AttCA证明信任路径x5c的实现特定值。

8.3.1. TPM证明声明证书要求

TPM 证明证书 必须包含以下字段/扩展:

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设置为返回值。

认证器通过连接authenticatorDataclientDataHash生成sig,并使用凭据私钥对结果进行签名。它将alg设置为签名格式的算法。

验证过程

给定验证过程输入attStmtauthenticatorDataclientDataHash验证过程如下:

  • 验证attStmt是符合上述语法定义的有效CBOR,并对其进行CBOR解码以提取包含的字段。

  • 验证sig是对连接authenticatorDataclientDataHash的结果使用x5c中第一个证书中的公钥及alg指定的算法进行的有效签名。

  • 验证x5c中第一个证书中的公钥与authenticatorData中的凭据公钥一致。

  • 验证证明证书扩展数据中的attestationChallenge字段与clientDataHash一致。

  • 使用证明证书扩展数据中的授权列表验证以下内容:

    • AuthorizationList.allApplications字段不应出现在任何一个授权列表中(softwareEnforcedteeEnforced),因为PublicKeyCredential必须与RP ID相关联。

    • 如果RP只接受来自可信执行环境的密钥,则仅使用teeEnforced授权列表,否则使用teeEnforcedsoftwareEnforced的并集。

      • 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表示序列化客户端数据的哈希值

连接authenticatorDataclientDataHash,对连接后的字符串进行SHA-256哈希,并将哈希结果作为attToBeSigned

请求SafetyNet证明,并将attToBeSigned作为nonce值提供。将response设置为结果,将ver设置为认证器中运行的Google Play服务的版本。

验证过程

给定验证过程输入attStmtauthenticatorDataclientDataHash验证过程如下:

  • 验证attStmt是符合上述语法定义的有效CBOR,并对其进行CBOR解码以提取包含的字段。

  • 通过遵循SafetyNet在线文档中指定的步骤,验证response是否为版本ver的有效SafetyNet响应。截止撰写本文时,SafetyNet响应只有一种格式,ver保留供将来使用。

  • 验证response的有效负载中的nonce属性是否与authenticatorDataclientDataHash连接后的SHA-256哈希值的Base64编码值相同。

  • 通过遵循SafetyNet在线文档中的步骤,验证SafetyNet响应确实来自SafetyNet服务。

  • 如果成功,返回表示证明类型基础和证明信任路径x5c的实现特定值。

8.6. FIDO U2F 证明声明格式

该证明声明格式用于使用[FIDO-U2F-Message-Formats]中定义的格式的FIDO U2F认证器。

证明声明格式标识符

fido-u2f

支持的证明类型

基础, AttCA

语法

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

验证过程

给定验证过程输入attStmtauthenticatorDataclientDataHash验证过程如下:

  1. 验证attStmt是符合上述语法定义的有效CBOR,并对其进行CBOR解码以提取包含的字段。

  2. 检查x5c是否只有一个元素,并将该元素作为attCert。将certificate public key设为attCert中传达的公钥。如果certificate public key不是P-256曲线上的椭圆曲线(EC)公钥,终止此算法并返回相应的错误。

  3. authenticatorData中提取声明的rpIdHash,并从authenticatorData.attestedCredentialData中提取声明的credentialIdcredentialPublicKey

  4. 将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密钥格式。

  5. verificationData设为(0x00 || rpIdHash || clientDataHash || credentialId || publicKeyU2F)的连接(参见[FIDO-U2F-Message-Formats]第4.3节)。

  6. 按照[SEC1]第4.1.4节的要求,使用SHA-256作为第二步中的哈希函数,使用certificate public keyverificationData进行sig验证。

  7. 可选地,检查x5c并咨询外部提供的知识,以确定attStmt是否传达了基础AttCA证明。

  8. 如果成功,返回表示证明类型基础AttCA或不确定性,及证明信任路径x5c的实现特定值。

8.7. 无证明声明格式

无证明声明格式用于替换任何认证器提供的证明声明,当WebAuthn依赖方表示不希望接收证明信息时,参见§ 5.4.7 证明传递偏好枚举(enum AttestationConveyancePreference)

如果认证器不支持证明认证器也可以直接生成这种格式的证明声明。

证明声明格式标识符

none

支持的证明类型

语法

无证明声明的语法定义如下:

    $$attStmtType //= (
                          fmt: "none",
                          attStmt: emptyMap
                      )

    emptyMap = {}
签名过程

返回上面定义的固定证明声明。

验证过程

返回表示证明类型和空的证明信任路径的实现特定值。

8.8. 苹果匿名证明声明格式

此证明声明格式专为支持WebAuthn的某些类型的苹果设备使用。

证明声明格式标识符

apple

支持的证明类型

匿名CA

语法

苹果证明声明的语法定义如下:

    $$attStmtType //= (
                          fmt: "apple",
                          attStmt: appleStmtFormat
                      )

    appleStmtFormat = {
                          x5c: [ credCert: bytes, * (caCert: bytes) ]
                      }

上述字段的语义如下:

x5c

credCert后跟其证书链,每个都以X.509格式编码。

credCert

用于证明的凭证公钥证书,编码为X.509格式。

签名过程
  1. authenticatorData设为证明的认证器数据,并将clientDataHash设为序列化客户端数据的哈希

  2. 连接authenticatorDataclientDataHash以形成nonceToHash

  3. nonceToHash执行SHA-256哈希以生成nonce

  4. 让苹果匿名证明CA生成一个用于凭证公钥的X.509证书,并将nonce作为OID为1.2.840.113635.100.8.2的证书扩展名包含在内。credCert表示此证书。credCert因此作为证明的证明,并且包含的nonce证明证明是实时的。此外,nonce还保护了authenticatorData客户端数据的完整性。

  5. x5c设置为credCert及其证书链。

验证过程

给定验证过程输入attStmtauthenticatorDataclientDataHash,验证过程如下:

  1. 验证attStmt是符合上述语法定义的有效CBOR,并对其进行CBOR解码以提取包含的字段。

  2. 连接authenticatorDataclientDataHash以形成nonceToHash

  3. nonceToHash执行SHA-256哈希以生成nonce

  4. 验证nonce等于credCert中OID为1.2.840.113635.100.8.2的扩展名的值。

  5. 验证凭证公钥等于credCert的主题公钥。

  6. 如果成功,返回表示证明类型匿名CA和证明信任路径x5c的实现特定值。

9. WebAuthn扩展

生成公钥凭证以及请求和生成认证声明的机制,如§ 5 Web身份验证API中定义的,可以根据特定的用例进行扩展。每种情况都通过定义注册扩展和/或认证扩展来处理。

每个扩展都是一个客户端扩展,意味着该扩展涉及与客户端的通信和处理。客户端扩展定义了以下步骤和数据:

在创建公钥凭证或请求认证声明时,WebAuthn依赖方可以请求使用一组扩展。这些扩展将在请求的操作期间被调用,如果它们被客户端和/或WebAuthn认证器支持。依赖方get()调用中(用于认证扩展)或create()调用中(用于注册扩展)向客户端发送每个扩展的客户端扩展输入客户端为每个客户端平台支持的扩展执行客户端扩展处理,并按照每个扩展的规定通过包含扩展标识符客户端扩展输出值来扩展客户端数据

扩展还可以是一个认证器扩展,这意味着扩展涉及与认证器的通信和处理。认证器扩展定义了以下步骤和数据:

对于认证器扩展,作为客户端扩展处理的一部分,客户端还为每个扩展创建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()调用发送的客户端扩展输入参数,客户端扩展处理规则以及一个客户端扩展输出值。如果扩展与认证器通信(即它是一个认证器扩展),它还必须指定通过authenticatorGetAssertionauthenticatorMakeCredential调用发送的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. 认证器扩展处理

每个处理的认证器扩展认证器扩展输入值都包含在authenticatorMakeCredentialauthenticatorGetAssertion操作的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凭据进行身份验证

  1. allowCredentials 选项中列出所需的U2F凭据 在get() 方法中:

    • type 成员设置为public-key

    • id 成员设置为所需凭据的相应U2F密钥句柄。注意,U2F密钥句柄通常使用base64url编码,但在id中使用时必须解码为其二进制形式。

    allowCredentials 可以包含WebAuthn凭据ID和U2F密钥句柄的混合; 通过此扩展声明appid 并不妨碍用户使用注册到rpId中声明的RP ID的WebAuthn凭据。

  2. 验证声明时,期望rpIdHash可能是AppID的哈希值,而不是RP ID的哈希值。

此扩展不允许创建与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;
};
客户端扩展处理
  1. facetId成为将调用者的来源传递到 FIDO算法中以确定调用应用程序的FacetID的结果。

  2. appId成为扩展输入。

  3. facetIdappId传递给FIDO算法以确定调用者的FacetID是否获得AppID的授权。 如果该算法拒绝appId,则返回“SecurityErrorDOMException

  4. 构建allowCredentialDescriptorList时, 如果U2F认证器指示凭据不适用(即返回SW_WRONG_DATA),则客户端必须重试,将U2F应用参数设置为appId的SHA-256哈希。 如果这导致了一个适用的凭据,客户端必须将该凭据包含在allowCredentialDescriptorList中。 然后appId的值替换authenticatorGetAssertionrpId参数。

  5. output设置为布尔值false

  6. 创建assertionCreationData时, 如果声明由U2F认证器创建,并且U2F应用参数设置为appId的SHA-256哈希而不是RP ID的SHA-256哈希,则将output设置为true

注意: 实际上,几个实现没有执行算法的步骤四及以后的步骤确定调用者的FacetID是否获得AppID的授权。 相反,在步骤三中,主机上的比较放宽以接受同一站点上的主机。

客户端扩展输出

返回output的值。如果为true,则使用了AppID,因此,在验证声明时,依赖方必须期望rpIdHashAppID的哈希值,而不是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;
};
客户端扩展处理

创建新凭据时:

  1. 建立 RP ID后立即执行以下步骤:

    1. facetId成为将调用者的来源传递给 FIDO 算法以确定调用应用程序的 FacetID 的结果。

    2. appId成为扩展输入的值appidExclude

    3. facetIdappId传递给 FIDO 算法,以确定调用者的 FacetID 是否获得 AppID 授权。如果后一个算法拒绝appId,则 返回 "SecurityError" DOMException 并终止创建新凭据算法以及这些步骤。

      注意: 实际上,几个实现没有执行算法的步骤四及以后的步骤确定调用者的 FacetID 是否获得 AppID 授权。相反,在第三步中,主机上的比较放宽为接受同一站点上的主机。

    4. 否则,继续正常处理。

  2. 调用 authenticatorMakeCredential之前执行以下步骤:

    1. 如果authenticator支持 U2F 协议[FIDO-U2F-Message-Formats],则针对每个 凭据描述符 CexcludeCredentialDescriptorList 中:

      1. 通过向authenticator发送一个U2F_AUTHENTICATE消息来检查C是否是使用authenticator上的 U2F 创建的,该消息的“5个部分”设置为以下值:

        控制字节

        0x07 ("check-only")

        挑战参数

        32 个随机字节

        应用参数

        appId 的 SHA-256 哈希

        密钥句柄长度

        C.id 的长度(以字节为单位)

        密钥句柄

        C.id 的值,即凭据 ID

      2. 如果authenticator响应message:error:test-of-user-presence-required(即成功),则停止对该authenticator的正常处理,并以平台特定的方式指示认证器不适用。例如,这可以以 UI 的形式显示,或可以涉及从authenticator请求用户同意,并在收到后,将其视为认证器已返回InvalidStateError。请求用户同意可以通过再次向authenticator发送U2F_AUTHENTICATE消息来实现,除了将控制字节设置为0x03 ("enforce-user-presence-and-sign") 并忽略响应。

    2. 继续正常处理。

客户端扩展输出

返回值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["credProps"]["rk"] 为在 调用authenticatorMakeCredential 操作中使用的 requireResidentKey 参数的值。

dictionary CredentialPropertiesOutput {
    boolean rk;
};

partial dictionary AuthenticationExtensionsClientOutputs {
    CredentialPropertiesOutput credProps;
};
rk, 类型 boolean

此可选属性,抽象地称为驻留密钥凭据属性(即客户端可发现的凭据属性), 是一个布尔值,指示是否注册仪式的结果是 PublicKeyCredential客户端可发现的凭据。 如果rktrue,则凭据是可发现的凭据。 如果rkfalse,则凭据是服务器端凭据。 如果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, 类型 boolean

一个布尔值,指示依赖方希望获取与断言的凭据关联的先前写入的数据块。仅在身份验证期间有效。

write, 类型 BufferSource

一个依赖方希望与现有凭据一起存储的不透明字节串。仅在身份验证期间有效。

客户端扩展处理 (注册)
  1. 如果readwrite存在:

    1. 返回一个DOMException,其名称为“NotSupportedError”。

  2. 如果support存在且值为required

    1. supported设置为true

      注意:这是为了预期能够存储大数据块的认证器可用的情况。它发生在[[Create]]()的步骤 11 中的扩展处理期间。如果没有可用的满意认证器,AuthenticationExtensionsLargeBlobOutputs将被放弃。

    2. 如果在步骤 19 中有一个候选认证器变得可用,继续(即忽略候选认证器),如果该候选认证器不支持存储大数据块。

  3. 否则(即support不存在或其值为preferred):

    1. 如果认证器被选中并且选中的认证器支持大数据块,将supported设置为true,否则为false

客户端扩展处理 (身份验证)
  1. 如果support存在:

    1. 返回一个DOMException,其名称为“NotSupportedError”。

  2. 如果readwrite都存在:

    1. 返回一个DOMException,其名称为“NotSupportedError”。

  3. 如果read存在且值为true

    1. 初始化客户端扩展输出largeBlob

    2. 如果任何认证器指示成功(在[[DiscoverFromExternalSource]]()),尝试读取与断言的凭据关联的任何largeBlob数据。

    3. 如果成功,将blob设置为结果。

      注意:如果读取不成功,largeBlob将在AuthenticationExtensionsClientOutputs中存在,但blob成员将不存在。

  4. 如果write存在:

    1. 如果allowCredentials不包含完全一项:

      1. 返回一个DOMException,其名称为“NotSupportedError”。

    2. 如果断言操作成功,尝试将write的内容存储在认证器上,与指定的凭据关联。

    3. 如果成功,将written设置为true,否则设置为false

客户端扩展输出
partial dictionary AuthenticationExtensionsClientOutputs {
    AuthenticationExtensionsLargeBlobOutputs largeBlob;
};

dictionary AuthenticationExtensionsLargeBlobOutputs {
    boolean supported;
    ArrayBuffer blob;
    boolean written;
};
supported, 类型 boolean

如果且仅当创建的凭据支持存储大数据块时,true。仅在注册输出中存在。

blob, 类型 ArrayBuffer

rawId标识的凭据关联的不透明字节串。仅当readtrue时有效。

written, 类型 boolean

指示write的内容是否已成功存储在与指定凭据关联的认证器上的布尔值。

认证器扩展处理

此扩展指示用户代理将大数据块存储在认证器上或从认证器中检索,因此它不会为依赖方指定任何直接的认证器交互。

11. 用户代理自动化

为了用户代理自动化和web应用程序测试,本文件定义了一些[WebDriver] 扩展命令

11.1. WebAuthn WebDriver 扩展功能

为了宣传下面定义的扩展命令的可用性,定义了一个新的扩展功能

功能 值类型 描述
虚拟认证器支持 "webauthn:virtualAuthenticators" boolean 指示端点节点是否支持所有虚拟认证器命令。

验证功能时,验证"webauthn:virtualAuthenticators"value的特定扩展步骤如下:

  1. 如果value不是boolean,返回WebDriver错误,并附带WebDriver错误代码 无效参数

  2. 否则,将deserialized设置为value

匹配功能时,匹配"webauthn:virtualAuthenticators"value的特定扩展步骤如下:

  1. 如果valuetrue,且端点节点不支持任何虚拟认证器命令,则匹配不成功。

  2. 否则,匹配成功。

11.1.1. 认证器扩展功能

此外,为本规范中定义的每个认证器扩展(即那些定义了认证器扩展处理的扩展)定义了扩展功能:

功能 值类型 描述
用户验证方法扩展支持 "webauthn:extension:uvm" boolean 指示端点节点 WebAuthn WebDriver实现是否支持用户验证方法扩展。
大数据存储扩展支持 "webauthn:extension:largeBlob" boolean 指示端点节点 WebAuthn WebDriver实现是否支持largeBlob 扩展。

验证功能时,验证认证器扩展功能keyvalue的特定扩展步骤如下:

  1. 如果value不是boolean,返回WebDriver错误,并附带WebDriver错误代码 无效参数

  2. 否则,将deserialized设置为value

匹配 功能时,匹配认证器扩展功能keyvalue的特定扩展步骤如下:

  1. 如果valuetrue,且端点节点 WebAuthn WebDriver实现不支持key标识的认证器扩展,则匹配不成功。

  2. 否则,匹配成功。

实现定义的认证器扩展的用户代理应实现相应的认证器扩展功能

11.2. 虚拟验证器

这些WebDriver 扩展命令 用来创建和交互 虚拟验证器验证器模型 的软件实现。虚拟验证器 存储在 虚拟验证器数据库 中。 每个存储的虚拟验证器 具有以下属性:

验证器ID

使用 [RFC3986] 附录A中定义的最多48个字符组成的非空字符串,用于唯一标识虚拟验证器

protocol

虚拟验证器 支持的协议之一:"ctap1/u2f", "ctap2""ctap2_1" [FIDO-CTAP]

transport

模拟的 验证器传输。如果 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个 用户验证方法 条目 空数组

远程端步骤 如下:

  1. 如果 parameters 不是 JSON 对象,返回一个 WebDriver 错误,错误代码为 WebDriver 错误代码 无效参数

    注意: parameters 是一个 验证器配置 对象。

  2. authenticator 为新的 虚拟验证器

  3. 对于 parameters 中的每个可枚举 自有属性

    1. key 为属性名称。

    2. value获取属性 parameters 中名为 key 的属性的结果。

    3. 如果 parameters 中没有与 key 匹配的 key,返回 WebDriver 错误,错误代码为 WebDriver 错误代码 无效参数

    4. 如果 value 不是该 key有效值 之一,返回 WebDriver 错误,错误代码为 WebDriver 错误代码 无效参数

    5. 设置属性 keyauthenticator 上的 value

  4. 对于 验证器配置 中定义了默认值的每个属性:

    1. 如果 authenticator 没有定义的 key 属性,设置属性 keyauthenticator 上的 default

  5. 对于 验证器配置 中的每个属性:

    1. 如果 authenticator 没有定义的 key 属性,返回 WebDriver 错误,错误代码为 WebDriver 错误代码 无效参数

  6. 对于 authenticator.extensions 中的每个 extension

    1. 如果 extension 不是由 扩展标识符 支持的 端点节点 WebAuthn WebDriver 实现,返回 WebDriver 错误,错误代码为 WebDriver 错误代码 不支持的操作

  7. 生成有效唯一的 authenticatorId

  8. 设置属性 authenticatorIdauthenticator 上的 authenticatorId

  9. authenticator 存储在 虚拟验证器数据库 中。

  10. 返回 成功,数据为 authenticatorId

11.4. 移除虚拟验证器

移除虚拟验证器 WebDriver 扩展命令 移除先前创建的 虚拟验证器。 定义如下:

HTTP 方法 URI 模板
DELETE /session/{session id}/webauthn/authenticator/{authenticatorId}

远程端步骤如下:

  1. 如果 authenticatorId 不匹配存储在 虚拟验证器中的任何记录, 返回 WebDriver 错误,并附带 WebDriver 错误代码 无效参数

  2. 虚拟验证器数据库中移除由 authenticatorId标识的虚拟验证器条目。

  3. 返回 成功

11.5. 添加凭证

添加凭证 WebDriver 扩展命令公钥凭证来源 注入到现有的 虚拟验证器中。定义如下:

HTTP 方法 URI 模板
POST /session/{session id}/webauthn/authenticator/{authenticatorId}/credential

凭证参数 是一个 JSON 对象,作为 parameters 传递给 远程端步骤。它包含以下 keyvalue 对:

描述 值类型
credentialId 使用 凭证 ID编码,采用 Base64url 编码字符串
isResidentCredential 如果设置为 true,则创建 客户端可发现凭证。 如果设置为 false,则创建 服务器端凭证布尔值
rpId 凭证范围内的 依赖方 ID字符串
privateKey 一个包含单个 私钥的非对称密钥包,符合 [RFC5958],使用 Base64url 编码字符串
userHandle 与凭证关联的 userHandle,使用 Base64url 编码。 此属性可能未定义。 字符串
signCount 签名计数器 关联的初始值,用于 公钥凭证来源数字
largeBlob 每个凭证的大块 blob 关联,采用 Base64url 编码。 此属性可能未定义。 字符串

远程端步骤如下:

  1. 如果 parameters 不是 JSON 对象, 返回 WebDriver 错误, 并附带 WebDriver 错误代码 无效参数

    注意: parameters 是一个 凭证参数 对象。

  2. credentialId 成为使用 Base64url 编码parameterscredentialId 属性进行解码的结果。

  3. 如果 credentialId 解码失败,返回 WebDriver 错误, 并附带 WebDriver 错误代码 无效参数

  4. isResidentCredential 成为 parametersisResidentCredential 属性。

  5. 如果 isResidentCredential 未定义,返回 WebDriver 错误, 并附带 WebDriver 错误代码 无效参数

  6. rpId 成为 parametersrpId 属性。

  7. 如果 rpId 不是有效的 RP ID, 返回 WebDriver 错误, 并附带 WebDriver 错误代码 无效参数

  8. privateKey 成为使用 Base64url 编码parametersprivateKey 属性进行解码的结果。

  9. 如果 privateKey 解码失败,返回 WebDriver 错误, 并附带 WebDriver 错误代码 无效参数

  10. 如果 privateKey 不是包含单个 ECDSA 私钥的有效编码的非对称密钥包,符合 [RFC5958] 的 P-256 曲线标准, 返回 WebDriver 错误, 并附带 WebDriver 错误代码 无效参数

  11. 如果 parametersuserHandle 属性已定义:

    1. userHandle 成为使用 Base64url 编码parametersuserHandle 属性进行解码的结果。

    2. 如果 userHandle 解码失败,返回 WebDriver 错误, 并附带 WebDriver 错误代码 无效参数

  12. 否则:

    1. 如果 isResidentCredentialtrue,返回 WebDriver 错误, 并附带 WebDriver 错误代码 无效参数

    2. userHandlenull

  13. 如果 authenticatorId 不匹配存储在 虚拟验证器中的任何记录, 返回 WebDriver 错误, 并附带 WebDriver 错误代码 无效参数

  14. authenticator 成为与 authenticatorId 匹配的 虚拟验证器

  15. 如果 isResidentCredentialtrue,且 authenticatorhasResidentKey 属性为 false, 返回 WebDriver 错误, 并附带 WebDriver 错误代码 无效参数

  16. 如果 authenticator 支持 largeBlob 扩展,并且 parameterslargeBlob 特性已定义:

    1. largeBlob 成为使用 Base64url 编码parameterslargeBlob 属性进行解码的结果。

    2. 如果 largeBlob 解码失败,返回 WebDriver 错误, 并附带 WebDriver 错误代码 无效参数

  17. 否则:

    1. largeBlobnull

  18. credential 成为一个新的 客户端可发现的公钥凭证来源, 如果 isResidentCredentialtrue,否则让其成为 服务器端公钥凭证来源, 其项包括:

    类型

    public-key

    id

    credentialId

    privateKey

    privateKey

    rpId

    rpId

    userHandle

    userHandle

  19. 将一个与 credential 关联的 签名计数器 counter, 其初始值等于 parameterssignCount, 如果 signCountnull,则默认为 0

  20. 如果 largeBlob 不为 null, 将与 credential 关联的 大块 blob 设置为 largeBlob

  21. credentialcounter 存储在 authenticator 的数据库中。

  22. 返回 成功

11.6. 获取凭证

获取凭证 WebDriver 扩展命令 返回每个存储在虚拟验证器中的凭证参数对象,无论它们是通过添加凭证还是通过navigator.credentials.create()存储的。 定义如下:

HTTP 方法 URI 模板
GET /session/{session id}/webauthn/authenticator/{authenticatorId}/credentials

远程端步骤如下:

  1. 如果 authenticatorId 不匹配存储在 虚拟验证器中的任何记录, 返回 WebDriver 错误, 并附带 WebDriver 错误代码 无效参数

  2. credentialsArray 成为空数组。

  3. 对于由 authenticatorId 标识的验证器管理的每个 公钥凭证来源 credential, 构造一个对应的凭证参数 对象并将其添加到 credentialsArray 中。

  4. 返回包含 credentialsArray 的数据的成功

11.7. 移除凭证

移除凭证 WebDriver 扩展命令 移除存储在 虚拟验证器上的公钥凭证来源。定义如下:

HTTP 方法 URI 模板
DELETE /session/{session id}/webauthn/authenticator/{authenticatorId}/credentials/{credentialId}

远程端步骤如下:

  1. 如果 authenticatorId 不匹配存储在 虚拟验证器中的任何记录, 返回 WebDriver 错误, 并附带 WebDriver 错误代码 无效参数

  2. authenticator 成为由 authenticatorId 标识的 虚拟验证器

  3. 如果 credentialId 不匹配 authenticator 管理的任何公钥凭证来源, 返回 WebDriver 错误, 并附带 WebDriver 错误代码 无效参数

  4. 移除由 credentialId 标识并由 authenticator 管理的公钥凭证来源

  5. 返回 成功

11.8. 移除所有凭证

移除所有凭证 WebDriver 扩展命令 移除存储在 虚拟验证器上的所有公钥凭证来源。定义如下:

HTTP 方法 URI 模板
DELETE /session/{session id}/webauthn/authenticator/{authenticatorId}/credentials

远程端步骤如下:

  1. 如果 authenticatorId 不匹配存储在 虚拟验证器中的任何记录, 返回 WebDriver 错误, 并附带 WebDriver 错误代码 无效参数

  2. 移除由 authenticatorId 标识的 虚拟验证器管理的所有公钥凭证来源

  3. 返回 成功

11.9. 设置用户已验证

设置用户已验证 扩展命令 设置虚拟验证器上的 isUserVerified 属性。定义如下:

HTTP 方法 URI 模板
POST /session/{session id}/webauthn/authenticator/{authenticatorId}/uv

远程端步骤如下:

  1. 如果 parameters 不是 JSON 对象,返回 WebDriver 错误 并附带 WebDriver 错误代码 无效参数

  2. 如果 authenticatorId 不匹配存储在 虚拟验证器中的任何记录, 返回 WebDriver 错误, 并附带 WebDriver 错误代码 无效参数

  3. 如果 parameters 中没有定义 isUserVerified 属性,返回 WebDriver 错误, 并附带 WebDriver 错误代码 无效参数

  4. authenticator 成为由 authenticatorId 标识的 虚拟验证器

  5. authenticatorisUserVerified 属性设置为 parameters 中的 isUserVerified 属性。

  6. 返回 成功

12. IANA 考虑

12.1. WebAuthn Attestation 声明格式标识符注册更新

本节更新了在 IANA "WebAuthn Attestation 声明格式标识符" 注册表中定义的以下列举的声明格式(详见§ 8 定义的声明格式),并指向此规范。此注册表由 [RFC8809] 创建,最初注册于 [WebAuthn-1]

12.2. WebAuthn Attestation 声明格式标识符注册

本节在 IANA "WebAuthn Attestation 声明格式标识符" 注册表中注册以下列举的声明格式,这些格式在 § 8 定义的声明格式 中新定义,由 [RFC8809] 创建。

12.3. WebAuthn 扩展标识符注册更新

本节更新了 IANA "WebAuthn 扩展标识符" 注册表中定义的以下列举的 扩展标识符 值(详见 § 10 定义的扩展), 该注册表由 [RFC8809] 创建,最初注册于 [WebAuthn-1],并指向本规范。

12.4. WebAuthn 扩展标识符注册

本节在 IANA "WebAuthn 扩展标识符" 注册表中注册以下列举的 扩展标识符 值,这些值在 § 10 定义的扩展 中新定义,由 [RFC8809] 创建。

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依赖方提供的主要优势包括:

  1. 用户和账户可以通过广泛兼容、易于使用的多因素身份验证来保护。

  2. 依赖方不需要向其用户提供验证器硬件。相反,每个用户可以独立获取任何符合要求的验证器,并将该验证器与任意数量的依赖方一起使用。依赖方可以选择通过检查由验证器返回的证明书声明,强制执行对验证器安全特性的要求。

  3. 身份验证流程中间人攻击具有抵抗力。关于注册流程,请参见下面的§ 13.4.4 证明书限制

  4. 依赖方可以自动支持多种用户验证方法,例如PIN码、生物识别和/或未来的方法,且几乎无需修改代码,并可以通过用户选择的验证器让每个用户决定他们更愿意使用哪种方法。

  5. 依赖方不需要存储额外的秘密信息即可获得上述优势。

一致性部分所述,依赖方必须按照§ 7 WebAuthn依赖方操作中描述的方式行事,以获得上述所有安全性优势。然而,下面描述的一个显著用例略有不同,见§ 13.4.4 证明书限制

13.4.2. 嵌入式使用的可见性考虑

在嵌入式环境中简化使用WebAuthn(例如,在iframe中使用,参见§ 5.10 在iframe元素中使用Web身份验证)可能使用户容易受到UI重定向攻击,也称为“点击劫持”。这是指攻击者在依赖方的预期UI之上覆盖他们自己的UI,并试图诱使用户在依赖方执行非预期操作。例如,使用这些技术,攻击者可能能够诱使用户购买商品、转账等。

尽管WebAuthn特定的UI通常由客户端平台处理,因此不容易受到UI重定向的影响,但对于嵌入WebAuthn内容的依赖方来说,确保其内容的UI对用户可见可能非常重要。一种新兴的方法是观察实验性交叉观察者v2isVisible属性的状态。例如,嵌入式环境中运行的依赖方脚本可以在检测到isVisble被设置为false时预先加载自己到弹出窗口中,从而绕过其内容的遮挡。

13.4.3. 加密挑战

作为一种加密协议,Web身份验证依赖随机挑战来避免重放攻击。因此,PublicKeyCredentialCreationOptions.challengePublicKeyCredentialRequestOptions.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允许为同一用户注册多个凭证。例如,用户可以在经常使用的客户端设备上注册平台凭证,并为备份和使用新设备或不常使用的设备注册一个或多个漫游凭证

建议依赖方允许并鼓励用户为同一账户注册多个凭证依赖方应使用excludeCredentialsuser.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》不使用或提供任何形式的全球身份标识,但使用了以下几种可能相关的标识符:

上述部分信息是必然会与依赖方共享的。以下章节描述了为防止恶意依赖方利用这些信息来发现用户的个人身份而采取的措施。

14.2. 匿名的、作用域限定的、不可关联的公钥凭证

本节不具备规范性。

尽管凭证ID凭证公钥为了实现强身份验证,必须与WebAuthn依赖方共享,但它们被设计为最小化识别性,且不会在依赖方之间共享。

此外,客户端可发现的公钥凭证源可以选择性地包括由依赖方指定的用户句柄凭证然后可以用于同时标识和验证用户。这意味着隐私意识强的依赖方可以允许用户在没有传统用户名的情况下创建账户,从而进一步提高依赖方之间的不可关联性。

14.3. 认证器本地的生物识别

生物识别认证器认证器内部执行生物识别——但对于平台认证器,生物识别数据可能也对客户端可见,具体取决于实现方式。生物识别数据不会泄露给WebAuthn依赖方;它仅在本地用于执行用户验证,授权创建和注册或使用认证公钥凭证。因此,恶意的依赖方无法通过生物识别数据发现用户的个人身份,并且在依赖方发生的安全漏洞也不会暴露生物识别数据,供攻击者用于伪造其他依赖方的登录。

如果依赖方要求生物识别,此操作将由执行用户验证生物识别认证器在本地执行,然后通过在签名的断言响应中设置UV标志来传递结果,而不是将生物识别数据本身泄露给依赖方

14.4. 认证器的隐私考虑

14.4.1. 证明隐私

证明证书证明密钥对可用于跟踪用户或将同一用户的不同在线身份关联在一起。对此可以通过几种方式进行缓解,包括:

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”在此依赖方有账户的可能敏感信息。

以下是依赖方可以实施的非规范性、非详尽的措施清单,以减轻或防止此类攻击引起的信息泄漏:

14.6.3. 通过凭证ID的隐私泄漏

本节不是规范性内容。

本隐私注意事项适用于支持认证仪式且第一个认证步骤使用非allowCredentials参数的依赖方。例如,如果使用服务器端凭证作为第一个认证步骤。

在这种情况下,allowCredentials参数存在泄露个人识别信息的风险,因为它将用户的凭证ID暴露给未认证的调用者。凭证ID旨在无法在依赖方之间进行关联,但凭证ID的长度可能暗示创建它的认证器类型。用户很可能会为多个依赖方使用相同的用户名和一组认证器,因此凭证ID的数量和长度可能成为一个全局关联标识,以去匿名化用户。了解用户的凭证ID还可以使得在仅瞬间接触到用户的一个认证器的情况下确认用户身份的猜测。

为了防止此类信息泄漏,依赖方可以例如:

如果上述预防措施不可用,即如果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 团队联系人所做的贡献。

索引

本规范定义的术语

引用定义的术语

参考文献

规范性引用

[BCP47]
A. Phillips; M. Davis. 用于识别语言的标签。 2009年9月。IETF最佳现行实践。URL: https://tools.ietf.org/html/bcp47
[CREDENTIAL-MANAGEMENT-1]
Mike West. 凭据管理第1级。2019年1月17日。 WD。URL: https://www.w3.org/TR/credential-management-1/
[DOM4]
Anne van Kesteren. DOM标准。现行标准。URL: https://dom.spec.whatwg.org/
[ECMAScript]
ECMAScript语言规范。URL: https://tc39.es/ecma262/
[ENCODING]
Anne van Kesteren. 编码标准。现行标准。URL: https://encoding.spec.whatwg.org/
[FETCH]
Anne van Kesteren. Fetch标准。现行标准。URL: https://fetch.spec.whatwg.org/
[FIDO-APPID]
D. Balfanz; et al. FIDO AppID和Facet规范。2018年2月27日。FIDO联盟实施草案。URL: https://fidoalliance.org/specs/fido-v2.0-id-20180227/fido-appid-and-facets-v2.0-id-20180227.html
[FIDO-CTAP]
M. Antoine; et al. 客户端到认证器协议。 2018年2月27日。FIDO联盟实施草案。URL: https://fidoalliance.org/specs/fido-v2.0-ps-20190130/fido-client-to-authenticator-protocol-v2.0-ps-20190130.html
[FIDO-Privacy-Principles]
FIDO联盟。FIDO 隐私原则。FIDO联盟白皮书。URL: https://fidoalliance.org/wp-content/uploads/2014/12/FIDO_Alliance_Whitepaper_Privacy_Principles.pdf
[FIDO-Registry]
R. Lindemann; D. Baghdasaryan; B. Hill. FIDO 预定义值的注册表。2018年2月27日。FIDO联盟实施草案。URL: https://fidoalliance.org/specs/fido-v2.0-id-20180227/fido-registry-v2.0-id-20180227.html
[FIDO-U2F-Message-Formats]
D. Balfanz; J. Ehrensvard; J. Lang. FIDO U2F原始消息格式。FIDO联盟实施草案。URL: https://fidoalliance.org/specs/fido-u2f-v1.1-id-20160915/fido-u2f-raw-message-formats-v1.1-id-20160915.html
[FileAPI]
Marijn Kruisselbrink; Arun Ranganathan. 文件API。 2019年9月11日。WD。URL: https://www.w3.org/TR/FileAPI/
[HTML]
Anne van Kesteren; et al. HTML标准。现行标准。URL: https://html.spec.whatwg.org/multipage/
[IANA-COSE-ALGS-REG]
IANA CBOR对象签名和加密(COSE)算法注册表。URL: https://www.iana.org/assignments/cose/cose.xhtml#algorithms
[IANA-WebAuthn-Registries]
IANA。Web认证(WebAuthn)注册表。 URL: https://www.iana.org/assignments/webauthn/
[INFRA]
Anne van Kesteren; Domenic Denicola. Infra标准。现行标准。URL: https://infra.spec.whatwg.org/
[PAGE-VISIBILITY]
Jatinder Mann; Arvind Jain. 页面可见性(第二版)。 2013年10月29日。REC。URL: https://www.w3.org/TR/page-visibility/
[Permissions-Policy]
Ian Clelland. 权限政策。2020年7月16日。 WD。URL: https://www.w3.org/TR/permissions-policy-1/
[RFC2119]
S. Bradner. 在RFC中用于指示需求等级的关键字。 1997年3月。最佳现行实践。URL: https://tools.ietf.org/html/rfc2119
[RFC3986]
T. Berners-Lee; R. Fielding; L. Masinter. 统一资源标识符(URI):通用语法。2005年1月。互联网标准。URL: https://tools.ietf.org/html/rfc3986
[RFC4648]
S. Josefsson. Base16,Base32和Base64数据编码。 2006年10月。建议标准。URL: https://tools.ietf.org/html/rfc4648
[RFC4949]
R. Shirey. 互联网安全术语表,第2版。 2007年8月。信息性。URL: https://tools.ietf.org/html/rfc4949
[RFC5234]
D. Crocker, Ed.; P. Overell. 增强型BNF用于语法规范:ABNF。 2008年1月。互联网标准。URL: https://tools.ietf.org/html/rfc5234
[RFC5280]
D. Cooper; et al. 互联网X.509公钥基础设施证书和证书撤销列表(CRL)规范。 2008年5月。建议标准。URL: https://tools.ietf.org/html/rfc5280
[RFC5890]
J. Klensin. 应用程序的国际化域名(IDNA):定义和文档框架。 2010年8月。建议标准。URL: https://tools.ietf.org/html/rfc5890
[RFC6454]
A. Barth. Web起源概念。 2011年12月。建议标准。URL: https://tools.ietf.org/html/rfc6454
[RFC7515]
M. Jones; J. Bradley; N. Sakimura. JSON Web签名(JWS)。 2015年5月。建议标准。URL: https://tools.ietf.org/html/rfc7515
[RFC8152]
J. Schaad. CBOR对象签名和加密(COSE)。 2017年7月。建议标准。URL: https://tools.ietf.org/html/rfc8152
[RFC8230]
M. Jones. 使用RSA算法与CBOR对象签名和加密(COSE)消息。 2017年9月。建议标准。URL: https://tools.ietf.org/html/rfc8230
[RFC8264]
P. Saint-Andre; M. Blanchet. PRECIS框架:在应用协议中准备,实施和比较国际化字符串。 2017年10月。建议标准。URL: https://tools.ietf.org/html/rfc8264
[RFC8265]
P. Saint-Andre; A. Melnikov. 准备,实施和比较表示用户名和密码的国际化字符串。 2017年10月。建议标准。URL: https://tools.ietf.org/html/rfc8265
[RFC8266]
P. Saint-Andre. 准备,实施和比较表示昵称的国际化字符串。 2017年10月。建议标准。URL: https://tools.ietf.org/html/rfc8266
[RFC8610]
H. Birkholz; C. Vigano; C. Bormann. 简明数据定义语言(CDDL):表示简明二进制对象表示法(CBOR)和JSON数据结构的符号约定。 2019年6月。IETF建议标准。URL: https://tools.ietf.org/html/rfc8610
[RFC8809]
Jeff Hodges; Giridhar Mandyam; Michael B. Jones. Web认证(WebAuthn)的注册表。 2020年8月。IETF建议标准。URL: https://www.rfc-editor.org/rfc/rfc8809
[RFC8949]
C. Bormann; P. Hoffman. 简明二进制对象表示法(CBOR)。 2020年12月。互联网标准。URL: https://tools.ietf.org/html/rfc8949
[SEC1]
SEC1:椭圆曲线密码学,版本2.0。URL: http://www.secg.org/sec1-v2.pdf
[SECURE-CONTEXTS]
Mike West. 安全上下文。2016年9月15日。 CR。URL: https://www.w3.org/TR/secure-contexts/
[SP800-800-63r3]
Paul A. Grassi; Michael E. Garcia; James L. Fenton. NIST特别出版物800-63:数字身份指南。 2017年6月。URL: https://pages.nist.gov/800-63-3/sp800-63-3.html
[TCG-CMCProfile-AIKCertEnroll]
Scott Kelly; et al. TCG 基础设施工作组:AIK证书注册的CMC配置文件。2011年3月24日。 已发布。URL: https://trustedcomputinggroup.org/wp-content/uploads/IWG_CMC_Profile_Cert_Enrollment_v1_r7.pdf
[TokenBinding]
A. Popov; et al. Token绑定协议版本1.0。 2018年10月。IETF建议标准。URL: https://tools.ietf.org/html/rfc8471
[TPMv2-EK-Profile]
TPM 家族2.0的TCG EK凭据配置文件。URL: https://www.trustedcomputinggroup.org/wp-content/uploads/Credential_Profile_EK_V2.0_R14_published.pdf
[TPMv2-Part1]
可信平台模块库,第1部分:架构。 URL: https://www.trustedcomputinggroup.org/wp-content/uploads/TPM-Rev-2.0-Part-1-Architecture-01.38.pdf
[TPMv2-Part2]
可信平台模块库,第2部分:结构。URL: https://www.trustedcomputinggroup.org/wp-content/uploads/TPM-Rev-2.0-Part-2-Structures-01.38.pdf
[TPMv2-Part3]
可信平台模块库,第3部分:命令。URL: https://www.trustedcomputinggroup.org/wp-content/uploads/TPM-Rev-2.0-Part-3-Commands-01.38.pdf
[URL]
Anne van Kesteren. URL标准。现行标准。URL: https://url.spec.whatwg.org/
[UTR29]
UNICODE文本分割。URL: http://www.unicode.org/reports/tr29/
[WCAG21]
Andrew Kirkpatrick; et al. Web内容可访问性指南(WCAG)2.1。 2018年6月5日。REC。URL: https://www.w3.org/TR/WCAG21/
[WebDriver]
Simon Stewart; David Burns. WebDriver。 2018年6月5日。REC。URL: https://www.w3.org/TR/webdriver1/
[WebIDL]
Boris Zbarsky. Web IDL。2016年12月15日。 ED。URL: https://heycam.github.io/webidl/

参考文献

[Ceremony]
Carl Ellison. 仪式设计与分析。2007年。URL: https://eprint.iacr.org/2007/399.pdf
[CSS-OVERFLOW-3]
David Baron; Elika Etemad; Florian Rivoal. CSS 溢出模块 第3级。2020年6月3日。WD。URL: https://www.w3.org/TR/css-overflow-3/
[EduPersonObjectClassSpec]
EduPerson。正在进行中。URL: https://refeds.org/eduperson
[FIDO-Transports-Ext]
FIDO 联盟。FIDO U2F 认证器传输扩展。FIDO 联盟建议标准。URL: https://fidoalliance.org/specs/fido-u2f-v1.2-ps-20170411/fido-u2f-authenticator-transports-extension-v1.2-ps-20170411.html
[FIDO-UAF-AUTHNR-CMDS]
R. Lindemann; J. Kemp. FIDO UAF 认证器命令。FIDO 联盟实施草案。URL: https://fidoalliance.org/specs/fido-uaf-v1.1-id-20170202/fido-uaf-authnr-cmds-v1.1-id-20170202.html
[FIDOAuthnrSecReqs]
D. Biggs; 等。FIDO 认证器安全要求。FIDO 联盟最终文件。URL: https://fidoalliance.org/specs/fido-security-requirements-v1.0-fd-20170524/
[FIDOMetadataService]
R. Lindemann; B. Hill; D. Baghdasaryan. FIDO 元数据服务。2018年2月27日。FIDO 联盟实施草案。URL: https://fidoalliance.org/specs/fido-v2.0-id-20180227/fido-metadata-service-v2.0-id-20180227.html
[FIDOSecRef]
R. Lindemann; 等。FIDO 安全参考。2018年2月27日。FIDO 联盟实施草案。URL: https://fidoalliance.org/specs/fido-v2.0-id-20180227/fido-security-ref-v2.0-id-20180227.html
[FIDOU2FJavaScriptAPI]
D. Balfanz; A. Birgisson; J. Lang. FIDO U2F JavaScript API。FIDO 联盟建议标准。URL: https://fidoalliance.org/specs/fido-u2f-v1.2-ps-20170411/fido-u2f-javascript-api-v1.2-ps-20170411.html
[ISOBiometricVocabulary]
ISO/IEC JTC1/SC37. 信息技术 — 词汇 — 生物识别技术。2012年12月15日。国际标准:ISO/IEC 2382-37:2012(E) 第一版。URL: http://standards.iso.org/ittf/PubliclyAvailableStandards/c055194_ISOIEC_2382-37_2012.zip
[RFC3279]
L. Bassham; W. Polk; R. Housley. 互联网X.509公钥基础设施证书和证书撤销列表(CRL)配置文件的算法和标识符。2002年4月。建议标准。URL: https://tools.ietf.org/html/rfc3279
[RFC5958]
S. Turner. 非对称密钥包。2010年8月。建议标准。URL: https://tools.ietf.org/html/rfc5958
[RFC6265]
A. Barth. HTTP 状态管理机制。2011年4月。建议标准。URL: https://httpwg.org/specs/rfc6265.html
[RFC8017]
K. Moriarty, Ed.; 等。PKCS #1:RSA密码规范版本2.2。2016年11月。信息性。URL: https://tools.ietf.org/html/rfc8017
[UAFProtocol]
R. Lindemann; 等。FIDO UAF 协议规范 v1.0。FIDO 联盟建议标准。URL: https://fidoalliance.org/specs/fido-uaf-v1.0-ps-20141208/fido-uaf-protocol-v1.0-ps-20141208.html
[WebAuthn-1]
Dirk Balfanz; 等。Web 认证:访问公共密钥凭证的API,第1级。2019年3月4日。REC。URL: https://www.w3.org/TR/webauthn-1/
[WebAuthnAPIGuide]
Web 认证 API 指南。实验性。URL: https://developer.mozilla.org/en-US/docs/Web/API/Web_Authentication_API

IDL 索引

[SecureContext, Exposed=Window]
interface PublicKeyCredential : Credential {
    [SameObject] readonly attribute ArrayBuffer              rawId;
    [SameObject] readonly attribute AuthenticatorResponse    response;
    AuthenticationExtensionsClientOutputs getClientExtensionResults();
};

partial dictionary CredentialCreationOptions {
    PublicKeyCredentialCreationOptions      publicKey;
};

partial dictionary CredentialRequestOptions {
    PublicKeyCredentialRequestOptions      publicKey;
};

partial interface PublicKeyCredential {
    static Promise<boolean> isUserVerifyingPlatformAuthenticatorAvailable();
};

[SecureContext, Exposed=Window]
interface AuthenticatorResponse {
    [SameObject] readonly attribute ArrayBuffer      clientDataJSON;
};

[SecureContext, Exposed=Window]
interface AuthenticatorAttestationResponse : AuthenticatorResponse {
    [SameObject] readonly attribute ArrayBuffer      attestationObject;
    sequence<DOMString>                              getTransports();
    ArrayBuffer                                      getAuthenticatorData();
    ArrayBuffer?                                     getPublicKey();
    COSEAlgorithmIdentifier                          getPublicKeyAlgorithm();
};

[SecureContext, Exposed=Window]
interface AuthenticatorAssertionResponse : AuthenticatorResponse {
    [SameObject] readonly attribute ArrayBuffer      authenticatorData;
    [SameObject] readonly attribute ArrayBuffer      signature;
    [SameObject] readonly attribute ArrayBuffer?     userHandle;
};

dictionary PublicKeyCredentialParameters {
    required DOMString                    type;
    required COSEAlgorithmIdentifier      alg;
};

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;
};

dictionary PublicKeyCredentialEntity {
    required DOMString    name;
};

dictionary PublicKeyCredentialRpEntity : PublicKeyCredentialEntity {
    DOMString      id;
};

dictionary PublicKeyCredentialUserEntity : PublicKeyCredentialEntity {
    required BufferSource   id;
    required DOMString      displayName;
};

dictionary AuthenticatorSelectionCriteria {
    DOMString                    authenticatorAttachment;
    DOMString                    residentKey;
    boolean                      requireResidentKey = false;
    DOMString                    userVerification = "preferred";
};

enum AuthenticatorAttachment {
    "platform",
    "cross-platform"
};

enum ResidentKeyRequirement {
    "discouraged",
    "preferred",
    "required"
};

enum AttestationConveyancePreference {
    "none",
    "indirect",
    "direct",
    "enterprise"
};

dictionary PublicKeyCredentialRequestOptions {
    required BufferSource                challenge;
    unsigned long                        timeout;
    USVString                            rpId;
    sequence<PublicKeyCredentialDescriptor> allowCredentials = [];
    DOMString                            userVerification = "preferred";
    AuthenticationExtensionsClientInputs extensions;
};

dictionary AuthenticationExtensionsClientInputs {
};

dictionary AuthenticationExtensionsClientOutputs {
};

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" };

enum PublicKeyCredentialType {
    "public-key"
};

dictionary PublicKeyCredentialDescriptor {
    required DOMString                    type;
    required BufferSource                 id;
    sequence<DOMString>                   transports;
};

enum AuthenticatorTransport {
    "usb",
    "nfc",
    "ble",
    "internal"
};

typedef long COSEAlgorithmIdentifier;

enum UserVerificationRequirement {
    "required",
    "preferred",
    "discouraged"
};

partial dictionary AuthenticationExtensionsClientInputs {
  USVString appid;
};

partial dictionary AuthenticationExtensionsClientOutputs {
  boolean appid;
};

partial dictionary AuthenticationExtensionsClientInputs {
  USVString appidExclude;
};

partial dictionary AuthenticationExtensionsClientOutputs {
  boolean appidExclude;
};

partial dictionary AuthenticationExtensionsClientInputs {
  boolean uvm;
};

typedef sequence<unsigned long> UvmEntry;
typedef sequence<UvmEntry> UvmEntries;

partial dictionary AuthenticationExtensionsClientOutputs {
  UvmEntries uvm;
};

partial dictionary AuthenticationExtensionsClientInputs {
    boolean credProps;
};

dictionary CredentialPropertiesOutput {
    boolean rk;
};

partial dictionary AuthenticationExtensionsClientOutputs {
    CredentialPropertiesOutput credProps;
};

partial dictionary AuthenticationExtensionsClientInputs {
    AuthenticationExtensionsLargeBlobInputs largeBlob;
};

enum LargeBlobSupport {
  "required",
  "preferred",
};

dictionary AuthenticationExtensionsLargeBlobInputs {
    DOMString support;
    boolean read;
    BufferSource write;
};

partial dictionary AuthenticationExtensionsClientOutputs {
    AuthenticationExtensionsLargeBlobOutputs largeBlob;
};

dictionary AuthenticationExtensionsLargeBlobOutputs {
    boolean supported;
    ArrayBuffer blob;
    boolean written;
};

问题索引

WHATWG HTML 工作组正在讨论是否在浏览上下文获得或失去焦点时提供一个钩子。如果提供钩子,上述段落将更新以包括该钩子。 有关更多详细信息,请参阅 WHATWG HTML 工作组问题 #2711