The Copenhagen Book

邮件验证

如果应用程序要求用户的电子邮件地址唯一,邮件验证是必须的。它可以阻止用户输入随机的电子邮件地址,并允许用户在实施密码重置的情况下取回用其电子邮件地址创建的账户。您甚至可能希望在用户验证其电子邮件地址之前阻止他们访问应用程序的内容。

电子邮件地址不区分大小写。 我们建议将用户提供的电子邮件地址标准化为小写。

输入验证

电子邮件复杂,无法使用正则表达式充分验证。尝试使用正则表达式也可能引入正则表达式拒绝服务(ReDoS)漏洞。不要过度复杂化:

  • 必须包含至少一个@字符。
  • @前至少有一个字符。
  • 域部分至少有一个.,且在它之前至少有一个字符。
  • 不以空格开始或结束。
  • 最多255个字符。

子地址

一些电子邮件提供商(包括Google)允许用户指定一个邮件服务会忽略的标签。例如,user@example.com可以使用user+foo@example.comuser+bar@example.com。您可以阻止带+符号的电子邮件以防止用户使用相同电子邮件地址创建多个账户,但用户仍可以使用临时电子邮件地址或创建新邮箱。切勿默默地移除用户输入中的标签部分,因为带+的电子邮件地址可能是常规的有效电子邮件地址。

邮件验证代码

一种验证电子邮件的方法是向用户的邮箱发送服务器存储的秘密代码。

这种方法相比使用链接有一些优势:

  • 人们越来越不愿点击链接。
  • 一些过滤器可能会自动将带有链接的电子邮件归类为垃圾邮件或网络钓鱼。
  • 使用验证链接可能会增加摩擦,尤其是在用户想在无法访问验证消息或无法打开链接的设备上完成验证过程时。

如果代码为数字,验证代码至少应为8位;如果为字母数字,至少为6位。如果验证是安全过程的一部分(如创建新账户或更改联系方式),应使用更强的代码。避免使用大写和小写字母。您可能还希望删除容易混淆的数字和字母(0, O, 1, I等)。必须使用密码学安全的随机生成器生成。

每个验证代码应关联到单个用户和电子邮件。当允许用户在发送电子邮件后更改电子邮件地址时尤其重要。每个代码至少应有效15分钟(推荐1-24小时)。验证后,代码必须立即失效且只能使用一次。每次用户请求另一封邮件/代码时,应生成新验证码。

类似于常规登录表单,必须根据用户ID实施节流或速率限制。每小时约10次尝试是一个合理的限制。在正确实施限制的情况下,代码可有效长达24小时。如果用户提供的代码已过期,您应生成并重新发送新代码。

当用户的电子邮件验证后,所有会话都应失效。

邮件验证链接

另一种验证电子邮件的方法是使用包含长随机单次使用令牌的验证链接。

https://example.com/verify-email/<TOKEN>

每个令牌应关联到单个用户和电子邮件。当允许用户在发送电子邮件后更改电子邮件地址时尤其重要。令牌应为单次使用,且验证后立即从存储中删除。令牌至少应有效15分钟(推荐1-24小时)。当用户请求另一个验证电子邮件时,如果令牌还未过期,您可以重新发送以前的令牌,而不是生成新令牌。

确保为包含令牌的任何路径设置Referrer Policy标记为strict-origin(或等效),以保护令牌不被引用泄露。

电子邮件验证后,所有会话都应失效(并为当前用户创建新会话以保持登录状态)。

更改电子邮件

用户应被要求输入他们的密码,或者如果启用了多因素身份验证,则使用他们的第二因素之一进行身份验证。新电子邮件应与当前电子邮件分开存储,直到验证完成。例如,可以将新电子邮件与验证令牌/代码一起存储。

当用户更改其电子邮件时,应向之前的电子邮件地址发送通知。

速率限制

任何能发送电子邮件的端点都应实施严格的速率限制。