我正在检查我的电子邮件标头(从 Gmail 发送)并且想知道哪些最适合验证电子邮件是从正确的域发送的并且电子邮件的内容没有被修改?
1 回答
我将使用从 Stack Overflow 收到的示例消息来说明如何手动验证消息。
SPF在交付后用处不大,因为它是验证消息来源的一个相对较小(但很重要)的步骤,但很高兴知道它在当时很好,并且标头会告诉您这一点。与传递相关的消息内容部分是接收者添加的标头,以及显示从何处接收Return-path
的最后一个标头:Received
Return-Path: <bounces+3553988-07ba-marcus=example.com@em.stackoverflow.email>
Received: from o1.em.stackoverflow.email (o1.em.stackoverflow.email [167.89.81.234])
(using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits))
(No client certificate requested)
在 DNS 中将此em.stackoverflow.email
域作为 TXT 记录查找给我们:
# dig txt +short em.stackoverflow.email
u3553988.wl239.sendgrid.net.
"v=spf1 ip4:167.89.81.234 ip4:167.89.85.72 ip4:168.245.32.199 -all"
我们可以看到167.89.81.234
出现在Received
标头中的 IP 在记录中明确列出,因此 SPF 进行了检查。其他域可能有更复杂的需求来验证 SPF,例如需要额外的 DNS 查找include
机制。值得注意的是,SPF 甚至不查看From
标头中使用的地址。它可以与返回路径域完全无关。
DKIM 是真正的行动所在。您可以使用DKIM-signature
标头中的信息来验证消息是否未被篡改。例如:
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
d=stackoverflow.email;
h=from:subject:to:reply-to:mime-version:content-type; s=s1;
bh=IgKJJZNcUhfjH6LDr4XaWr3pBwq6wwxwyrGmf+k3DVo=; b=rR4J7VyvF3i0N
20IX9bx0LGTKpSKj7XoHJurhBjcZLLTn/hXuZ8OMehfgMNFeXaMljlOz4tfoFwit
aJ8UtK1oMVCPiv9200hpQViCh/5VsyYbs6k3YN6R3cFxMbrb7nflodXX+4Rp4xBu
T+CloNFEDICtWJT4bVSrs/NRAUlJWY=
查看From
标头并检查它是否与d
DKIM 签名字段中显示的域匹配,它确实如此:
From: Stack Exchange <do-not-reply@stackoverflow.email>
DKIM 签名有 2 个签名部分:b
一个是消息体bh
的签名,一个是消息头的签名。这些的相互作用是相当棘手的。要生成签名,首先计算正文签名,然后计算包含正文签名的标头签名,以及元素中列出的规范化消息标头,但h
元素的实际值除外bh
,因为这将呈现鸡和蛋的问题。bh
签名仅包括列出的标头,因为邮件服务器可能会添加其他不应包含的标头,或者在发送时不知道的标头,例如Return-path
和Received
. 堆栈溢出的签名很不寻常,因为它不包含Date
标头,因此可以在不破坏 DKIM 签名的情况下更改消息上的日期。
要验证签名,您需要使用它签名的公钥,您可以使用s
提供选择器的字段从 DNS 获取该公钥,在这种情况下s1
:
# dig txt +short s1._domainkey.stackoverflow.email
s1.domainkey.u3553988.wl239.sendgrid.net.
"k=rsa; t=s; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCyJRzkL/aRo1F1+ChY+Crt2TARqqo7tGATw3fMfzW8MXFWaoW1rSvZsq4k1EIf2iW7gO/QZjU1Td7h1aZpS63/CmpKymmqNbHnnbTxZGvZziKPcL/R2PVL0g88MFcpAuSjIsGysYTeow0mnXQ5W03z5mtWqm5nxNM40A/TIlOegwIDAQAB"
此签名的一个问题是它仅使用 1024 位密钥。gmail 会忽略少于 2048 位的 DKIM 签名,因此如果 SO 与 gmail 存在可传递性问题,我不会感到惊讶。
实际上验证 DKIM 签名是一个复杂的过程,特别是如果它使用relaxed
规范化算法(这使得签名更有可能在电子邮件旅程中幸存下来)。我编写了一个 PHP DKIM 验证器,您可以使用它来验证您自己的消息。
最后一层是 DMARC,它将 SPF、DKIM 和From
地址标头联系在一起。回头Return-path
看,我们可以看到返回路径域是From
头部中使用的域的子域。这意味着它符合“宽松”而不是“严格”对齐的条件。我们可以看到 SO 的 DMARC 记录:
# dig txt +short _dmarc.stackoverflow.email
"v=DMARC1;p=reject;sp=reject;pct=100;rua=mailto:dmarc-aggregates@stackoverflow.com;ruf=mailto:dmarc-forensics@stackoverflow.com;fo=1"
这告诉我们 SO 希望接收者严格执行 SPF 和 DKIM 检查,并拒绝任何未签出的邮件,并且他们已设置地址来接收任何失败邮件的摘要和取证报告。
还有更多细节,但这并不是真正适合它的地方。这里有一篇很好的文章。