我一直在使用这个符合 RFC822 的正则表达式进行电子邮件验证。HackerOne 上的笔测试人员使用了以下满足正则表达式的可怕电子邮件地址:
'/**/OR/**/1=1/**/--/**/@a.a
a@a.a&a=////etc/passwd
a@a.com&&a=a
%00%2a@a.a
这些电子邮件地址有效吗?如何进行安全的电子邮件验证?
我一直在使用这个符合 RFC822 的正则表达式进行电子邮件验证。HackerOne 上的笔测试人员使用了以下满足正则表达式的可怕电子邮件地址:
'/**/OR/**/1=1/**/--/**/@a.a
a@a.a&a=////etc/passwd
a@a.com&&a=a
%00%2a@a.a
这些电子邮件地址有效吗?如何进行安全的电子邮件验证?
这些电子邮件地址有效吗?
有关电子邮件外观的很好解释,请参阅信息RFC3696。更多技术性的 RFC 也链接在那里。
电子邮件地址的本地部分可能存在攻击
如果没有引号,本地部分可以由
字母字符、数字或任何特殊字符的任意组合组成! # $ % & ' * + - / = ? ^ _ ` . { | } ~
句点(“.”)也可能出现,但不能用于开始或结束局部部分,也不能出现两个或多个连续句点。换句话说,除 at 符号 ("@")、反斜杠、双引号、逗号或方括号之外的任何 ASCII 图形(打印)字符都可以不带引号出现。如果要出现该排除字符列表中的任何一个,则必须引用它们。
所以规则或多或少:大多数字符都可以是本地部分的一部分,除了@\",[]
,那些必须介于两者之间"
(当然除了"
它本身,它必须在带引号的字符串中进行转义)。
还有关于何时何地引用以及如何处理评论的规则,但这与您的问题不太相关。
这里的重点是,许多攻击可能是电子邮件地址的本地部分的一部分,例如:
'/**/OR/**/1=1/**/--/**/@a.a
"<script>alert(1)</script>"@example.com
" onmouseover=alert(1) foo="@example.com
"../../../../../test%00"@example.com
电子邮件地址的域部分中可能存在的攻击
域部分的确切结构可以在RFC2822或RFC5322中看到:
addr-spec = local-part "@" domain local-part = dot-atom / quoted-string / obs-local-part domain = dot-atom / domain-literal / obs-domain domain-literal = [CFWS] "[" *([FWS] dcontent) [FWS] "]" [CFWS] dcontent = dtext / quoted-pair dtext = NO-WS-CTL / ; Non white space controls %d33-90 / ; The rest of the US-ASCII %d94-126 ; characters not including "[", ; "]", or "\"
在哪里:
dtext = %d33-90 / ; Printable US-ASCII %d94-126 / ; characters not including obs-dtext ; "[", "]", or "\"
您可以再次看到,大多数字符都是允许的(甚至是非 ascii 字符)。可能的攻击是:
a@a.a&a=////etc/passwd
foo@bar(<script>alert(1)</script>).com
foo@'/**/OR/**/1=1/**/--/**/
结论
您无法安全地验证电子邮件地址。
相反,您需要确保有适当的防御措施(XSS 的 HTML 编码、SQL 注入的准备语句等)。
作为深度防御,您可以禁止引用字符串和注释以获得一定程度的保护,因为这两件事允许最不寻常的字符和字符串。但是一些攻击仍然是可能的,并且您将排除少量用户。
如果您确实需要超出电子邮件格式限制的额外输入过滤,因为您不信任应用程序的其余部分,您应该仔细考虑您允许什么和不允许什么。例如+
,gmail 使用它来允许过滤传入的电子邮件,因此不允许它可能会导致用户不注册。其他提供者可能会使用其他字符来实现类似的功能。第一种方法可能是只允许 alphanum + ! # % * + - = ? ^ _ . | ~
。这将禁止< > ' " ` / $ { } &
,这是常见攻击中使用的字符。根据您的应用程序,您可能希望禁止更多字符。
正如你提到的RFC822:它有点过时(它是从 1982 年开始的),但即使它允许引用字符串和注释,所以仅仅说你只接受 RFC822 兼容的地址不仅不实用,而且也行不通。
另外,您是否在客户端检查您的电子邮件?JS 代码给人这样的印象。攻击者可以绕过客户端检查。
对此进行测试的最简单方法是尝试从仅发送地址(即来自 noreply-randomblue@example.com)向该地址发送电子邮件。如果不能送达,则无效。
使用正则表达式解析电子邮件可能最好在客户端完成,以便在他们注册之前提前让他们知道他们的电子邮件地址中可能有拼写错误。
您说您希望拥有安全的电子邮件地址。我认为这意味着这些已放入您的应用程序中,并且您期望一些可预测的输出。编写您的应用程序的开发人员在他们的集体头脑中都知道在电子邮件字段中会发生什么,您最好不要在那里允许任何其他内容。你的程序员没有想到的不是很安全(即使根据一些可怕的 RFC 是有效的)。
因此,如果您的开发人员不太喜欢与电子邮件相关的 RFC,我建议使用恰好存在于 HTML5 的 W3C 标准中的“故意违反 RFC 5322” ,并转换为非常简单的正则表达式:
^[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])?)+$
我认为 99.9% 的真实人物地址都符合这两种表达方式。
你可以花太多时间担心这类事情。为什么你真的那么在乎?
实际上并没有不安全的地址——重要的是你用它做什么/如何处理它。
如果您以不安全的方式处理地址,例如连接字符串以生成 sql 而不是使用参数,那么您就是在自找麻烦,不仅在电子邮件地址中,而且在您允许用户输入的每个字段中。
简单的说; 提供它有
[>= one char]
@
[>= one char]
.
[>= one char]
甚至只是:
[>= one char]
@
[>= one char]
你应该允许它。这些字符是什么并不重要。