电子邮件验证 API

非官方提案草案,

此版本:
https://github.com/WICG/email-verification
问题跟踪:
GitHub
作者:
Sam Goto, Google, goto@google.com
Dick Hardt, Hellō, dick.hardt@gmail.com

摘要

本文档定义了电子邮件验证协议(EVP),该协议使 Web 应用程序无需发送验证电子邮件,即可验证 用户是否控制某个电子邮件地址。该协议采用三方模型, 由浏览器在验证者和颁发者之间充当中介,从而同时提供更好的用户体验 和隐私保护。

本文档的状态

本规范由 Web 平台孵化器 社区组发布。 它不是 W3C 标准,也不在 W3C 标准轨道上。 请注意,根据 W3C 社区贡献者许可协议 (CLA), 仅可在有限范围内选择退出,并且还适用其他条件。 详细了解 W3C 社区组和业务组

1. 简介

以往,在创建账户、登录或恢复账户期间验证电子邮件地址,一直依赖 手动的带外机制。典型流程是网站向用户的电子邮件地址发送一次性密码(OTP)或 “魔法链接”。随后,用户必须前往电子邮件收件箱,获取 密码或点击链接,然后返回网站以证明其所有权。

此过程会带来显著阻力,影响用户体验和转化率。此外,它 容易受到网络钓鱼攻击,恶意网站可能诱骗用户提供 OTP。

电子邮件验证协议(EVP)引入了一种由浏览器中介的机制,以通过密码学方式验证电子邮件所有权。 通过利用用户与其电子邮件提供商(颁发者)之间的活跃会话, 浏览器可以请求经过密码学签名的电子邮件验证令牌(EVT),并将其呈现给 网站(验证者)。

本规范定义了验证者用于请求 EVT 的 HTML 扩展,以及用于与颁发者协调 获取令牌的客户端浏览器行为。

1.1. 协议概述

该协议涉及三个主要参与方:

典型流程包括以下步骤:

  1. 登录:用户登录其电子邮件提供商。该提供商将浏览器的 登录状态更新为已登录(使用 登录状态 API)。

  2. 请求:验证者的网站包含一个具有 autocomplete="email-verification-token"nonce 属性的隐藏输入字段。

  3. 发现与验证:当用户选择电子邮件地址时(例如通过 自动填充),UA 通过 DNS 发现权威颁发者。UA 检查用户是否与该颁发者具有 活跃会话。

  4. 颁发:UA 从颁发者请求 EVT。

  5. 绑定与呈现:UA 将验证者的源和 nonce 绑定到 EVT, 创建密钥绑定 JWT(KB-JWT),并在表单 提交前将其填入验证者的输入字段。

  6. 验证:验证者验证 EVT 和 KB-JWT,以完成验证。

1.2. 示例

本节是非规范性的。

假设验证者网站 https://rp.example 希望在注册期间验证用户的电子邮件地址。

1.2.1. 验证者 HTML 表单

验证者包含一个标准电子邮件输入和一个用于电子邮件验证令牌(EVT)的隐藏输入,并具有 autocomplete="email-verification-token" 和唯一的 nonce

<form action="/signup" method="post">
  <label for="email">电子邮件地址:</label>
  <input type="email" id="email" name="email" autocomplete="email">

  <!-- EVP 隐藏输入 -->
  <input type="hidden" name="evt" 
         autocomplete="email-verification-token" 
         nonce="xyz123456789">

  <button type="submit">注册</button>
</form>

1.2.2. 浏览器交互

  1. 当用户聚焦 email 输入时,浏览器会建议可自动填充的电子邮件地址 (例如 user@email.example)。

  2. 用户选择 user@email.example

  3. 浏览器执行颁发者发现(查明 email.example 委托给 issuer.example),验证用户与颁发者的会话,并显示提示: 验证您的电子邮件? 您是否要与 rp.example 共享 user@email.example 的已验证令牌? [允许] [拒绝]

  4. 如果用户选择“允许”,浏览器将从 issuer.example 获取 EVT,并将其 绑定到 rp.example 和 nonce xyz123456789,然后存储绑定后的令牌。

1.2.3. 表单提交

当用户提交表单时,浏览器会自动将绑定后的令牌注入隐藏输入 字段。验证者接收以下 POST 载荷:

POST /signup HTTP/1.1
Host: rp.example
Content-Type: application/x-www-form-urlencoded

email=user%40email.example&evt=eyJhbGciOiJFZERTQSIsImtpZCI6IjIwMjQtMDgtMTkiLCJ0eXAiOiJldnQrand0In0...

随后,验证者解析并验证 evt 令牌(验证签名、源 rp.example、nonce xyz123456789,以及匹配的电子邮件 user@email.example),从而无需发送验证电子邮件即可完成注册。

2. HTML 扩展

本规范通过引入新的自动填充字段名称并扩展 nonce 属性的使用方式,对 HTML 标准 [HTML] 进行了扩展。

2.1. email-verification-token 自动填充值

email-verification-token 关键字被添加到 [HTML] 中定义的自动填充 字段名称列表(具体而言,是详细信息令牌)中。

<input> 元素的 autocomplete 属性设置为 email-verification-token 时,表示用户代理应当尝试在提交表单时使用 经过密码学绑定的电子邮件验证令牌(EVT)填充此字段,前提是用户已在 同一表单中选择并验证了电子邮件地址。

通常,此关键字用于 <input type="hidden"> 元素。

2.2. input 元素上的 nonce 属性

本规范将最初在 [HTML] 中为 <script><style> 元素定义(并在内容安全策略 [CSP] 中使用)的 nonce 属性扩展到 <input> 元素。

nonce 属性存在于具有 autocomplete="email-verification-token"<input> 元素上时,它包含一个由服务器端生成的、密码学强度足够的随机值(即 密码学 nonce)。

此 nonce 用于将生成的 EVT 绑定到特定的表单呈现,从而防止重放攻击。

nonce 属性的值对于每次页面渲染都必须是唯一的。

3. 浏览器处理模型

3.1. 处理自动填充选择

当用户从用户代理针对 <form> form 内的 <input> 元素 emailInput 所提供的自动填充建议中选择电子邮件地址 email 时:

  1. evtInputform 中第一个具有 autocomplete 属性且该属性值为 email-verification-token<input> 元素。

  2. 如果不存在这样的 evtInput,则终止这些步骤。

  3. nonceevtInputnonce 属性值。

  4. 如果 nonce 为空,则终止这些步骤。

  5. form 的 EVP 状态设置为:

    • emailemail

    • inputElementemailInput

    • token:null

  6. 在后台执行以下步骤:

    1. issuer 为对 email 执行 [EVP-Protocol] 中定义的颁发者 发现步骤所得的结果。

    2. 如果 issuer 为 null,则终止这些步骤。

    3. accountMatch 为使用 issueremail 执行账户验证所得的结果。

    4. 如果 accountMatch 为 false,则终止这些步骤。

    5. 显示用户提示,请求允许使用 issuer 验证电子邮件地址 email

    6. 如果用户拒绝授权,则终止这些步骤。

    7. evtResult 为从 issueremail 执行 EVT 颁发所得的结果。

    8. 如果 evtResult 为 null,则终止这些步骤。

    9. evtevtResult[0]。

    10. keyPairevtResult[1]。

    11. kbEvt 为使用 keyPair 的私钥组件,并结合 nonce 和文档的源,对 evt 执行 [EVP-Protocol] 中定义的密钥绑定 创建步骤所得的结果。

    12. stateform 的 EVP 状态。

    13. 如果 state 不为 null,且 stateemailemail 不区分大小写地相等:

      1. statetoken 设置为 kbEvt

3.2. 表单提交集成

当提交 <form> form 时:

  1. stateform 的 EVP 状态。

  2. 如果 state 为 null,或 statetoken 为 null,则继续执行标准 表单提交步骤。

  3. currentEmailstateinputElement 的值。

  4. 如果 currentEmailstateemail 不区分大小写地相等:

    1. evtInputform 中第一个 具有 autocomplete 属性且该属性值为 email-verification-token<input> 元素。

    2. 如果 evtInput 存在:

      1. evtInput 的值设置为 statetoken

  5. 继续执行 [HTML] 中定义的标准表单提交步骤。

3.3. 账户验证

给定电子邮件地址 email 和颁发者域 issuer,用户代理必须执行 以下步骤来验证账户:

  1. 使用登录状态 API [login-status] 检查 issuer 的登录状态。

  2. 如果状态为已退出登录, 则返回 false。

  3. wellKnown 为按照 [fedcm] 中的定义,为 issuer 获取well-known 文件所得的结果。

  4. 如果 wellKnown 为 null,则返回 false。

  5. accountsEndpointwellKnownaccounts_endpoint 成员的值。

  6. 如果 accountsEndpoint 不存在或不是有效的 URL,则返回 false。

  7. accounts 为针对 issueraccountsEndpoint 执行 [fedcm] 中定义的获取账户算法所得的结果。

  8. 如果 accounts 为 null 或为空,则返回 false。

  9. 对于 accounts 中的每个 account

    1. accountEmailaccountemail 成员的值。

    2. 如果 accountEmailemail 不区分大小写地相等,则返回 true。

  10. 返回 false。

3.4. EVT 颁发

给定电子邮件地址 email 和颁发者域 issuer,用户代理必须执行 以下步骤来获取 EVT:

  1. 生成临时非对称密钥对 keyPair(使用颁发者支持的算法, 如颁发者的元数据中所定义;如果未指定,则默认为 Ed25519)。

  2. 构造 JSON Web Token [JWT] requestToken

    1. 标头必须包含:

      • alg:签名算法(与 keyPair 的算法匹配)。

      • jwkkeyPair 的公钥组件。

    2. 载荷必须包含:

      • audissuer 的标识符(域)。

      • iat:当前时间。

      • emailemail 地址。

    3. 使用 keyPair 的私钥组件对 requestToken 进行签名。

  3. issuanceUrl 为颁发者的令牌颁发端点(从颁发者的 元数据中获取)。

  4. 构造发送至 issuanceUrl 的 HTTP POST 请求 request

    1. Content-Type 标头设置为 application/x-www-form-urlencoded

    2. Sec-Fetch-Dest 标头设置为 email-verification

    3. 包含 issuer 的第一方 Cookie。

    4. 将请求正文设置为以下内容的 URL 编码表示: request_token = requestToken(序列化为字符串)。

  5. 发送 request 并等待响应 callResponse

  6. 如果 callResponse 的状态码不是 200 OK,或其 Content-Type 不是 application/json,则返回 null。

  7. callResponse 的正文解析为 JSON,并令 json 为结果。

  8. 如果 json 不包含 issuance_token,则返回 null。

  9. evtjsonissuance_token

  10. 验证 evt

    1. 验证 evt 是由颁发者签名的有效 SD-JWT [SD-JWT]

    2. 验证 evt 中的 cnf 声明包含与 keyPair 的公钥匹配的公钥。

    3. 验证 evt 中的 email 声明与 email 匹配。

  11. 如果验证失败,则返回 null。

  12. 返回包含(evt, keyPair)的元组。

4. 验证者处理模型

当验证者收到包含电子邮件地址 email 和绑定令牌 boundToken(来自具有 autocomplete="email-verification-token" 的输入字段)的已提交表单时:

  1. 针对验证者的源和预期 nonce,对 boundToken 执行 [EVP-Protocol] 中定义的令牌 验证步骤。

  2. 如果验证失败,则判定验证失败。

  3. verifiedEmail 为从已验证令牌中提取的电子邮件地址。

  4. 如果 verifiedEmailemail 不区分大小写地不相等,则判定验证失败。

  5. 否则,验证成功。

5. 安全与隐私注意事项

5.1. 隐私

5.1.1. 对颁发者实施盲化

EVP 的一个关键隐私目标是防止颁发者得知用户正在与哪个验证者交互。

用户代理必须确保 Well-Known 获取和账户获取不会泄露验证者的 源。 颁发请求尽管携带凭据,但不得在请求标头中包含验证者的源 (例如,必须省略 RefererOrigin)。

5.1.2. 跟踪风险

由于颁发请求使用 Cookie,因此颁发者会得知用户处于活跃状态。但是,它只会在 用户主动选择其电子邮件进行验证时得知这一点,而这是一项由用户发起的操作。

5.2. 安全

5.2.1. 重放攻击

呈现令牌(EVT+KB)通过密钥绑定 JWT 绑定到特定的 nonceaudience(验证者 源)。 验证者必须验证:
  1. audience 与其源匹配。

  2. nonce 与其为表单呈现生成的 nonce 匹配。

  3. exp 声明尚未过期。

这可以防止攻击者截获 EVT+KB,并将其重放到另一个网站或不同的 上下文中。

5.2.2. DNS 安全

颁发者发现依赖 DNS TXT 记录。如果 DNS 遭到破坏,攻击者可能会将发现过程重定向到 恶意颁发者。 为缓解此风险,用户代理应当使用安全 DNS(DNS-over-HTTPS 或 DNS-over-TLS),并在可用时检查 DNSSEC 签名。 此外,颁发者必须与电子邮件域匹配(除非以明确且安全的方式进行了委托)。

一致性

文档 约定

一致性要求通过描述性断言 与 RFC 2119 术语的组合来表达。 本文档规范性部分中的关键词“MUST”“MUST NOT”“REQUIRED”“SHALL”“SHALL NOT”“SHOULD”“SHOULD NOT”“RECOMMENDED” “MAY”和“OPTIONAL” 应按照 RFC 2119 中的描述进行解释。 但是,为了提高可读性, 这些词在本规范中并非全部以大写字母形式出现。

除明确标记为非规范性的章节、示例和注释外, 本规范的所有文本均为规范性内容。[RFC2119]

本规范中的示例以“例如”一词引出, 或使用 class="example" 与规范性文本分隔, 如下所示:

这是一个资料性示例。

资料性注释以“注”一词开头, 并使用 class="note" 与规范性文本分隔, 如下所示:

注:这是一条资料性注释。

索引

本规范定义的 术语

参考文献

规范性参考文献

[EVP-Protocol]
Dick Hardt; Sam Goto. 电子邮件验证 协议(EVP)后端。互联网草案。URL:https://www.ietf.org/archive/id/draft-hardt-email-verification-00.html
[FEDCM]
Nicolas Pena Moreno. 联合凭据管理 API。URL:https://w3c-fedid.github.io/FedCM/
[LOGIN-STATUS]
登录状态 API。编辑草案。URL: https://w3c-fedid.github.io/login-status/
[RFC2119]
S. Bradner. 用于 RFC 中 指示要求级别的关键词。1997 年 3 月。当前最佳实践。URL:https://datatracker.ietf.org/doc/html/rfc2119

非规范性参考文献

[CSP]
Mike West; Antonio Sartori. 内容安全策略 第 3 级。URL:https://w3c.github.io/webappsec-csp/
[HTML]
Anne van Kesteren; et al. HTML 标准。 现行标准。URL:https://html.spec.whatwg.org/multipage/
[JWT]
M. Jones; J. Bradley; N. Sakimura. JSON Web Token (JWT)。2015 年 5 月。提议标准。URL:https://www.rfc-editor.org/rfc/rfc7519
[SD-JWT]
D. Fett; K. Yasuda; B. Campbell. JSON Web Token 的选择性披露(SD-JWT)。RFC。URL:https://www.rfc-editor.org/rfc/rfc9682.html