regex 使用正则表达式验证电子邮件地址会造成伤害吗?

nkkqxpd9  于 2023-03-24  发布在  其他
关注(0)|答案(8)|浏览(322)

我听说用正则表达式验证电子邮件地址是件坏事,而且它实际上会造成伤害。为什么呢?
我认为验证数据永远不会是一件坏事。也许没有必要,但只要正确执行验证,就永远不会是一件坏事。为什么这是正确的或错误的?如果它会造成伤害,请给予个例子。

5fjcxozz

5fjcxozz1#

一般来说,是的-使用正则表达式来验证电子邮件地址是有害的。这是因为正则表达式的作者错误的(不正确的)假设。
正如klutt所指出的,一个电子邮件地址有两个部分,local-partdomain。值得注意的是,这些部分的一些内容并不明显:

  • local-part可以包含转义字符,甚至可以包含额外的@字符。
  • local-part可以区分大小写,但是这取决于特定域中的邮件服务器如何区分大小写。
  • domain部分可以包含零个或多个由句点(.)分隔的标签,尽管实际上没有MX records对应于根(零个标签)或TLD(一个标签)本身。

因此,您可以进行一些检查,而不会拒绝与上述内容对应的有效电子邮件地址:

  • 地址至少包含一个@
  • local-part(最右侧@左侧的所有内容)非空
  • domain部分(最右边的@右边的所有内容)至少包含一个句点(同样,这不是严格正确的,但很实用)

就这样。正如其他人所指出的,最好的做法是测试该地址的可送达性。这将确定两件重要的事情:
1.电子邮件当前是否存在;以及
1.用户有权访问电子邮件地址(是合法用户或所有者)
如果您将电子邮件激活流程构建到业务流程中,则无需担心复杂的正则表达式会出现问题。
一些进一步的阅读以供参考:
RFC 5321: Simple Mail Transfer Protocol
OWASP: Input Validation Cheat Sheet

apeeds0o

apeeds0o2#

TL;DR

不要使用正则表达式来验证电子邮件,除非你有很好的理由不这样做。使用验证邮件代替。在大多数情况下,正则表达式只需检查字符串是否包含@就足够了。

短版

在大多数情况下,问题 “我如何用正则表达式验证电子邮件地址” 是一个XY-problem,因为它很可能不是解决您实际问题的方法。真实的的问题可能是 “我如何确保用户输入的电子邮件地址可以用于与用户通信?” 或如zsalya在评论中提到的 “您应该对用户应用什么清理-在将其存储到数据库之前输入电子邮件地址?"
构造用于验证电子邮件的正则表达式可能是一个很好很有趣的练习,但总的来说,你真的应该在生产代码中避免它。验证电子邮件地址的正确方法在大多数情况下是发送验证邮件。试图验证邮件地址是否与规范匹配是非常棘手的,即使你做对了,除非您知道它是一个您可以发送邮件的邮件地址,并且有人会阅读它,否则它通常仍然是无用的信息。
想一想,你有多经常使用存储一个错误的邮件地址?
如果你只是想确保用户不会混淆输入字段,检查邮件地址是否包含@字符,这就足够了。好吧,它不会抓住那些坚持在用户名或密码中使用该字符的人,但这是他们的头痛。)

长版本

在大多数情况下,你想使用这个,只是知道电子邮件地址是有效的并不意味着一件事。你真正想知道的是,如果它是正确的电子邮件地址。
原因可能各不相同。您可能希望发送新闻通讯,用于常规通信,密码恢复或其他目的。但无论是什么,重要的是它是正确的地址。知道地址是否符合复杂的标准并不重要。唯一重要的是知道它是否可以用于存储地址的目的。

验证的正确方法是发送包含验证链接的邮件。

如果你已经用验证链接验证了电子邮件地址,那么通常没有必要检查它是否是一个正确的电子邮件地址,因为你知道它的工作原理。然而,它可以用来检查用户是否在正确的字段中输入了电子邮件地址。在这种情况下,我的建议是要非常宽容。我会说,只要检查字段中的@就足够了。这是一个简单的检查,所有的电子邮件地址都包括一个@。如果你想让它更复杂,我建议只是警告用户地址可能有问题,但不禁止它。一个非常简单的正则表达式,将有极少数的假阴性(如果有的话)是

.+@.+\..+

这意味着在@之前有一个非空的字符串,后跟一个非空的域名,一个点和一个非空的顶级域名。但实际上,我只坚持使用@.+,这意味着右边的部分是非空的,我不知道任何dns服务器会接受一个空的服务器名称。

根据标准正确检查电子邮件实际上非常棘手

但一个更糟糕的担忧是,用于准确验证电子邮件地址的正则表达式实际上是一件非常复杂的事情,如果你试图自己创建正则表达式,几乎肯定会出错,这里值得一提的是,标准RFC 5322确实允许括号内的注解,更糟糕的是允许嵌套注解。标准正则表达式不能匹配嵌套模式。为此,您需要扩展正则表达式。虽然扩展正则表达式并不罕见,但它确实说明了一些复杂性。即使您正确地使用了它,当一个新的标准到来时,你会更新正则表达式吗?

邮件服务器可能支持非标准地址

还有一件事,即使你100%正确,这可能仍然不够。电子邮件地址的本地部分在@的左边,域部分在右边。本地部分的所有内容都是由服务器处理的。当然,RFC 5322非常详细地介绍了有效的本地部分是什么样子的,但是如果一个特定的电子邮件服务器接受的地址根据RFC 5322是无效的呢?你真的确定你不想允许一个特定的电子邮件地址,只是因为它不符合标准?你想失去客户为您的业务只是因为他们选择了一个模糊的电子邮件提供商?或者因为你犯了一个错误的正则表达式?(提示:使用语言特定的字符很容易出错)
如果你真的想在生产代码中检查地址是否正确,那么使用MailAddress类或类似的东西。但首先花一分钟考虑这是否真的是你想要的。问问自己,如果地址不是正确的地址,它是否有任何值。如果答案是否定的,那么你不需要。使用验证链接代替。

话虽如此,验证输入可能是一件好事。重要的是要知道你为什么要这样做。用正则表达式或(最好)类似Mailaddress类的东西来验证电子邮件可以给予一些针对恶意输入的保护,例如SQL注入等。但是如果这是保护你免受恶意输入的唯一方法,那么你做了一些非常错误的事情。

ccrfmcuu

ccrfmcuu3#

除了其他答案之外,我想指出的是,使用回溯的正则表达式引擎容易受到ReDoS- regex拒绝服务攻击。这种攻击是基于这样一个事实,即许多重要的正则表达式的输入可能需要大量的CPU周期才能产生不匹配。
精心制作这样的输入可能会导致网站的可用性问题,即使是小型僵尸网络。
问题缓解措施:

  • 通常可以重写正则表达式以避免灾难性的回溯;或:
  • 使用不支持回溯的正则表达式引擎-虽然大多数支持它,但没有这种支持的引擎确实存在-一个值得注意的例子是Go/Golang使用的RE 2正则表达式引擎。

如需了解更多信息:* ”Regular Expressions Denial of the Service (ReDoS) Attacks“*

gjmwrych

gjmwrych4#

如果你的正则表达式是错误的,那么你可能会拒绝有效的电子邮件地址。这适用于任何“电子邮件验证”规则。
我知道一个电子邮件地址,它经常被不包含任何电子邮件奇怪的形式拒绝;这真的会惹恼它的主人,因为@前面的部分是他们的法律的名称--显然是电子邮件地址的选择。
这是电子邮件验证不正确的潜在危害的一部分:通过拒绝有效的电子邮件地址进入系统来骚扰用户。

yptwkmov

yptwkmov5#

验证电子邮件地址本身并不坏。
使用正则表达式验证电子邮件地址本身并不坏……尽管有更好的方法来验证它们1。
真实的的问题是基于语法的电子邮件地址验证是无效的

  • 它不会告诉您地址是否对应于有效的工作邮箱。
  • 它不会告诉您它是否是正确用户(或代理)的地址。

由于用户经常意外地(或故意地)输入语法上有效但不正确的电子邮件地址,如果您需要知道该地址是否是所涉及的人的正确地址,则需要执行其他操作。例如,您可以向提供的地址发送某种“激活”或“确认”电子邮件。
因此,假设您要实现第二阶段的检查,则第一阶段的电子邮件地址语法检查相对不重要,甚至不是绝对必要的。
1 -创建一个正则表达式来正确地处理电子邮件语法中的所有边缘情况是不平凡的。然而,如果不给大量用户带来不必要的不便,禁止一些更深奥的边缘情况也是可以接受的。
2 -正则表达式验证对于过滤掉故意伪造的电子邮件地址几乎是无用的。

llycmphe

llycmphe6#

我听说用正则表达式验证电子邮件地址是件坏事,而且它实际上会造成伤害。为什么呢?
这是正确的。regex解决方案很有吸引力,因为电子邮件地址是一个结构化的字符串,而regex用于查找字符串中的结构。
这也是一个错误的解决方案,因为当您向用户询问电子邮件地址时,通常是为了与他们联系。
验证不正确,因为:

  • 地址可能是有效的,但不是用户可以访问的地址。我可以在任何表单中填写地址billgates@microsoft.com,它可能会被接受为有效的电子邮件地址(免责声明:我不是比尔·盖茨:)。
  • 电子邮件地址的语法很难正确理解(参见the examples here)-通过定义自己的正则表达式来验证电子邮件,您最终将拒绝有效地址,并接受无效地址。

我认为验证数据永远不会是一件坏事。
验证数据并不坏,但在本例中,您将在应用程序中提供一个设计上有缺陷的特性:
您的应用程序在开发人员看来就像是在验证输入,但验证是不必要的,可能是不完整的,并且在验证结束时,您不知道是否有允许您联系用户的地址。
也许是不必要的,但只要您正确地执行验证,这绝不是坏事。
它不是不必要的;这是必要的。只是正则表达式不是合适的工具。
在一天结束时,检查地址是否对用户有效的最佳方法是对该地址进行唯一令牌交换:

  • 向该地址发送一封电子邮件,其中包含一个唯一的随机令牌(存储带有用户数据的令牌)
  • 在电子邮件中要求用户“单击链接/按钮”,有效地将令牌发送回您。
  • 验证令牌。
kt06eoxx

kt06eoxx7#

Regex是无害的。
使用一个好的电子邮件正则表达式来过滤不耐烦的假用户。
如果你是卖给那个人,你可能想联系他们进行进一步的验证,虽然卖家不太关心电子邮件,只是验证信用卡对他们来说就足够了。
否则,唯一需要验证的其他地方是当有人想要访问您的论坛并与之互动时,并且出于某种原因,您希望通过将其电子邮件出售给大众广告商来获得报酬,即使您说您不会这样做。
HTML5规范中的一个通用电子邮件正则表达式如下-

^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$

http://www.w3.org/TR/html5/forms.html#valid-e-mail-address

^
 [a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+
 @
 [a-zA-Z0-9]
 (?:
      [a-zA-Z0-9-]{0,61}
      [a-zA-Z0-9]
 )?
 (?:
      \.
      [a-zA-Z0-9]
      (?:
           [a-zA-Z0-9-]{0,61}
           [a-zA-Z0-9]
      )?
 )*
 $
hm2xizp9

hm2xizp98#

正则表达式可能是验证电子邮件地址的最好方法;只要你使用的是正确的。一旦你用正则表达式检查了地址,就只有一些额外的要求需要检查了(地址不能太长,并且它是有效的UTF-8)。
这是因为定义电子邮件地址形式的ABNF语法是“正则”的,这意味着它可以被精确地描述为正则表达式;而没有回溯、递归或任何非规则特征。
这只是一个理解规范的问题;但是一旦你这样做了,结果是电子邮件地址的正则表达式实际上非常简单:* 如何使用正则表达式验证电子邮件地址?*

相关问题