电子邮件防伪:SPF, DKIM与DMARC




English version: Anti Email Spoofing: SPF, DKIM and DMARC – Frank’s Weblog

背景

电子邮件伪造(Email spoofing)问题

如果你的雇主使用Knowbe4进行信息安全培训,你可能经常会在收件箱里收到类似这样的邮件:

当你点击链接之后

万幸的是这是一封来自Knowbe4的模拟钓鱼邮件,你和你的雇主的资料并不会被窃取。

以图中的域名biola.edu为例,有些钓鱼邮件比较低级,会使用和真实域名相近的域名,比如bio1a.edu,有些则更隐蔽,比如上图的邮件,发件人一栏确确实实显示的是来自biola.edu,那么为什么钓鱼邮件能够显示和真实邮件一样的地址,但是这封邮件却没有经过域名拥有者的授权?

这篇知乎回答已经解释得很清楚了:

普通邮件存在「信封」和「信笺」两个不同的概念:信封上的信息是给邮递员看的,包含了这封邮件是打哪儿来、向哪儿去的基本寻址信息;而信笺上的信息则是给收件人看的,里面标明了一些额外的信息。如果你熟悉英文信件格式的话,你可能已经注意到在写作正式的英文信件时,信笺的开头部分也是包含了发件人和收件人的具体信息的…

这里大家要记住的最重要的一点是:信笺上写的收发件人信息和信封上的收发件人信息可以完全没有关系,因为邮递员送信的时候不会看到信笺内的地址信息,而完全是根据信封上的信息决定如何投递邮件的…

电子邮件也有类似的「信封」和「信笺」的概念,而且最要命的是不像普通邮件,电子邮件的「信封」对于普通用户通常是不可见的,只对邮件中转过程中的各种服务器可见。普通用户看见的都只是邮件客户端展示的信笺上的收发件人地址。这个设计失误便是现今各种用电子邮件「钓鱼」诈骗用户信息的主要原因:恶意发送钓鱼邮件的人会把信笺内的发件人写成你熟悉/信任的机构或者个人,然后在邮件中放入恶意附件让你点击,从而使得不明真相的用户中招。

如何通俗地向大众解释什么是 DMARC 协议? – 知乎

为了解决这个问题,SPF,DKIM和DMARC三项互联网标准应运而生。如果你使用过AWS SES,Sendgrid等邮件托管服务,在将自己的域名添加到这些服务时,除了用于邮件解析的MX记录之外,这些服务还会要求添加SPF和DKIM等记录来确保发出的邮件能够成功送达。

SPF(Sender Policy Framework)

发件人策略框架(Sender Policy Framework, SPF)是一种用于防止电子邮件伪造的电子邮件验证系统。它允许邮件发送方域名管理员在DNS中发布一个SPF记录,在该记录中指定哪些邮件服务器被授权使用此域名发送邮件。接收邮件服务器会检查Return-Path(也称为信封发件人)中的域名的SPF记录,以验证发来的邮件是否从一个被授权的服务器发送。

Return-Path是一个特殊的头部字段,用来指定当邮件无法送达时,退信应该被发送到的邮箱地址。和From字段不同的是,Return-Path字段通常在邮件从发件人的邮件服务器发送到收件人的邮件服务器的过程中被添加,而不是由发件人直接指定。

SPF验证

SPF记录是一条TXT记录,我们dig一下本站域名,回应中的第二条就是SPF记录。

$ dig +short txt nyan.im
"google-site-verification=2wX_1AQnUlrh9IGcRpZ81X_bEFX3r1iJVdjbFZSFOD4"
"v=spf1 include:spf.messagingengine.com ?all"

SPF记录列出了允许使用该域名发送电子邮件的IP地址,收到电子邮件的邮件服务器可以对照SPF记录检查发件服务器是否位于记录中的IP段内,通过检查后再投递至收件人的收件箱。例如下面的spf记录允许了来自192.0.2.0/24发送的邮件。

"v=spf1 ip4:192.0.2.0/24 a -all"

当然现在个人和组织很少自己托管邮件服务器了,大多使用的是第三方的电子邮件服务,比如AWS SES。在使用这种服务时我们无法得知服务商使用的IP是多少。针对这种情况,可以使用include将SPF检查代理给服务商的域名。例如下面这条记录将SPF检查代理给了amazonses.com

"v=spf1 include:amazonses.com ~all"

amazonses.com也会存在一条SPF记录,我们可以通过dig txt amazonses.com得到amazonses.com的SPF记录如下:

amazonses.com.		345	IN	TXT	"v=spf1 ip4:199.255.192.0/22 ip4:199.127.232.0/22 ip4:54.240.0.0/18 ip4:69.169.224.0/20 ip4:23.249.208.0/20 ip4:23.251.224.0/19 ip4:76.223.176.0/20 ip4:52.82.172.0/22 ip4:54.240.64.0/19 ip4:54.240.96.0/19 ip4:76.223.128.0/19 ip4:216.221.160.0/19 -all"

收件方服务器将验证amazonses.com的SPF记录,如果amazonses.com的SPF检查通过,那么本次检查也随即通过。

DKIM(DomainKeys Identified Mail)

域名密钥识别邮件(DomainKeys Identified Mail, DKIM)是一套电子邮件认证机制,通过公钥加密的方式实现了数字签名与身份验证的功能,以检测发件人、标题、正文、附件等部分有否被伪冒或篡改。

DKIM是非对称加密的另一种应用。邮件发送方持有一个密钥对,私钥仅由发送方持有,公钥通过DNS记录供公开查询。每次发送邮件时,将邮件正文和特定头字段使用私钥签名,并将签名附在邮件头中发送。收件方通过使用公钥验证签名,来确保邮件是来自真实的发送者,且邮件没有被篡改过。

DKIM头

每一封邮件的header中包含该邮件的DKIM签名。将邮件导出为EML格式并用文本编辑器打开即可查看,这是一个DKIM签名的示例。

DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=nyan.im; h=cc
	:content-type:content-type:date:date:from:from:in-reply-to
	:message-id:mime-version:reply-to:subject:subject:to:to; s=fm3;
	 t=1705722369; x=1705808769; bh=ULqA9++UbPZqGI33Fvdg+Ogy/g+TdMiA
	er5LoQ8Dh8Y=; b=f/C5iY9E+ooeU6kRwLNh+h3U1/TJPv6UObQIc2CE3gduXnEX
	nX0MjHnpkMB1BdVnTwPeAPmixCXEqJ56//WgyM39JOkgMMy4E1csAIlDL0SZ+TjM
	0fHHPUIIZh1s/5GNFqbFxBK1qf6JQ7oJ489awlRPZ5rjm6swFLmWzDXUWE4La15D
	i+3w8BECGCTwHuiO3bgDjP32z6COCglPoj7ApwAOahwpMqOga52/HW9udQxYCB5k
	WiM1TGTbP6c6sdj6R4ivYYkMp1uEPjiwNCvvkobhrAP4EVBxbxCsYcbHYLd5/THn
	cxZtJ8zYp02ZO37RY9NMHhQlGOX8Uxh2HvSztw==

其中字段的含义如下:

v=1: 版本

a=rsa-sha256:哈希和签名算法

c=relaxed/relaxed:信息的标准化/规范化(canonicalization)方式。可选的值有simplerelaxed。 具体请参考RFC6376 Section 3.4

d=nyan.im:查询DKIM记录的域名

h=cc :content-type:content-type:date:date:from:from:in-reply-to :message-id:mime-version:reply-to:subject:subject:to:to:需要被签名的头字段

s=fm3:用于查询DKIM记录的DNS子域名。例如s=fm3d=nyan.im,则应向fm3._domainkey.nyan.im查询DKIM记录

t=1705722369:签名时间戳

x=1705808769:过期时间戳

bh=ULqA9++UbPZqGI33Fvdg+Ogy/g+TdMiA er5LoQ8Dh8Y=:Body hash,将邮件正文经过标准化和哈希而成

b=f/C5iY9E+ooeU6kRwLNh+h3U1/TJPv6UObQIc2CE3gduXnEX nX0MjHnpkMB1BdVnTwPeAPmixCXEqJ56//WgyM39JOkgMMy4E1csAIlDL0SZ+TjM 0fHHPUIIZh1s/5GNFqbFxBK1qf6JQ7oJ489awlRPZ5rjm6swFLmWzDXUWE4La15D i+3w8BECGCTwHuiO3bgDjP32z6COCglPoj7ApwAOahwpMqOga52/HW9udQxYCB5k WiM1TGTbP6c6sdj6R4ivYYkMp1uEPjiwNCvvkobhrAP4EVBxbxCsYcbHYLd5/THn cxZtJ8zYp02ZO37RY9NMHhQlGOX8Uxh2HvSztw==:经base64编码的签名

DKIM记录

和SPF类似,DKIM记录是域名所有者需要添加到DNS记录中的一段TXT记录,其中包含了公钥等信息,供收件方收取和验证。如果你使用电子邮件托管服务,这个记录也可能是一个CNAME,实际的DKIM记录由服务提供方管理。

$ dig +short txt fm3._domainkey.nyan.im
fm3.nyan.im.dkim.fmhosted.com.
"v=DKIM1; k=rsa; p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA60xfhfS80aBeqoHdFRHrYLXyAYn8xpApRdHMJaGw5qArkkLaisxvbmQ9+XCWUXIJ6YYW7GCIfn2rKhSMy1yOob59SpPX9YnnSx4Z28TBxKWD4hHtxIjplmvuHJlk/6nnI7aduhhj7Zc63to1OiGKApZrg45QVc1aZJHZWfQGQ9S4OeDX1g5Rq4FZH1qNNtbws" "G/k2yySDb7Db5cS4kXP1udNdVylg9uzO52KHE5cu6GttJhZVTPgt9b/jmtEUFNnG7gxhRgoZiFqrC5sWyS3IAE+dWIZvRxSdSYJLQVZMYN4oQ51nkHo7odfDKSO3FtnmL3Tn5S+HUvkmWwghowhawIDAQAB"

其中字段的含义如下:

v:版本

k:密钥类型,默认为RSA

p:公钥文本

验证

当收件方收到带有此签名的邮件后,将通过如下步骤来验证:

  1. 解析DKIM头,构建出查询DKIM记录的DNS名。
  2. 查询上一步得到的DNS名,得到DKIM记录,其中包含公钥。
  3. 将正文部分哈希并得到body hash,并对比DKIM头中的bh
  4. h中包含的头字段进行哈希并使用DKIM记录中的公钥签名
  5. 对比DKIM头中的签名

如果你想要亲手尝试如何验证DKIM,请参考:https://github.com/kmille/dkim-verify

DMARC

基于域的消息认证、报告与一致性(Domain-based Message Authentication, Reporting, and Conformance, DMARC)是一种电子邮件验证策略,它帮助域名所有者保护他们的域名不被滥用进行伪造邮件发送。DMARC 依赖于两种已有的电子邮件验证技术:SPF和DKIM。这两种技术用于验证发出的邮件是否经过域名所有者的授权。

DMARC策略(DMARC Policy)

通过在DNS记录中发布一个DMARC记录,域名所有者可以配置DMARC策略,来告诉接收方服务器,如果邮件没有通过SPF或DKIM的验证,应该如何处理这些邮件。这个策略可以是:

  • none: 不采取任何行动
  • quarantine: 将邮件标记为垃圾邮件或移到垃圾邮件文件夹
  • reject: 拒绝邮件

此外,域名所有者还可以配置DMARC记录以要求接收方服务器发送使用他们的域名发出的邮件的验证情况及未经授权的使用情况的聚合报告。来帮助域名所有者了解和优化他们的电子邮件发送策略。

如下是本站的DMARC策略

$ dig +short txt _dmarc.nyan.im
"v=DMARC1; p=none; rua=mailto:[email protected]"

其中v为版本;p为策略,指定了如何处理没有通过SPF或DKIM验证的邮件,这里选择的是none,也就是不采取任何行动。rua指定了接受报告的邮箱。

DMARC验证

邮件接收方进行DMARC验证的过程涉及检查发件人域的DMARC记录,并根据该记录中定义的策略来验证和处理接收到的邮件。这个过程一般遵循以下几个步骤:

  1. 邮件服务器首先会查找发件人域的DMARC DNS记录。DMARC记录为TXT记录,且名称为_dmarc.<域名>
  2. 在找到DMARC记录后,邮件服务器会使用前文提到的步骤对邮件进行SPF和DKIM验证。
  3. 如果邮件没有通过SPF和DKIM验证,收件方将根据DMARC记录中指定的策略来决定如何处理邮件。

对齐(Alignment)

SPF和DKIM在单独使用时仍然有如下漏洞会被攻击者利用:SPF只检查邮件信封上的发件人地址(Return-Path),而不检查邮件头部的From地址。这意味着攻击者可以伪造头部的From地址,使SPF检查通过;DKIM要求发件人对邮件进行数字签名,但实际上DKIM可以使用任何域名签名,攻击者可能使用自己的域名对邮件进行签名,而这个签名技术本身不能确保邮件头部的From地址的真实性。

在DMARC中,对齐是指验证过程中发件人域名在SPF和DKIM验证中的一致性要求,确保了邮件的发件人域名与邮件中用于SPF验证的域名和/或用于DKIM签名的域名匹配。

DMARC中的Alignment可以是以下两种类型之一,可以在DMARC策略中使用aspf(SPF)或adkim (DKIM)来设置。

宽松(Relaxed)

在宽松模式下,SPF验证要求邮件的Return-Path域名(也称为信封发件人域名)必须与From头部中的域名相同,但是该域名的子域名也可以通过验证。例如,如果From头部的域名是example.com,那么Return-Path中的域名如sub.example.com也将通过宽松模式验证。对于DKIM,DKIM签名中的d=域名(即签名域名)需要满足相同的要求。

严格(Strict)

严格模式下,SPF和DKIM验证的要求更为严格。SPF验证要求Return-Path域名必须与From头部中的域名完全匹配。同样,DKIM的d=域名也必须与From头部中的域名完全匹配。

DMARC报告(DMARC Report)

如果在DMARC记录中指定了报告的邮箱地址,接收方会定期向该邮箱发送DMARC报告。这些报告提供了关于邮件合规与否的处理信息,帮助发件人分析和改进他们的邮件发送策略。

这是一个示例报告文件:https://gist.github.com/frankgx97/3388177b973e298cf81d7f10bbd3ccbb

这些报告通常是XML格式,有一些网站(DMARC Report Analyzer – DMARC Email XML Parser – MxToolbox)可以提供报告的分析或可视化。

郭泽宇评论中提到:

关于 DMARC Report,如果只是将报告地址设置为自己的邮箱,那收到的都是给电脑看的原始数据。其实有很多现成的解决方案都是将 DMARC Report 的邮箱设置为第三方邮箱,由第三方汇总并生成更有意义的报告。我目前在用的免费的 Postmark DMARC 可以自动化处理 DMARC Report https://dmarc.postmarkapp.com ,每周会发送报告,感觉很好用

Reference

[1] DomainKeys Identified Mail – Wikipedia

[2] Sender Policy Framework – Wikipedia

[3] https://www.rfc-editor.org/rfc/rfc6376.txt

[4] https://www.rfc-editor.org/rfc/rfc7208.txt

[5] DMARC Alignment – dmarcian




Posted

in

by

Comments

3 responses to “电子邮件防伪:SPF, DKIM与DMARC”

  1. ccbbp Avatar

    又遇到专业大佬,膜拜

  2. 郭泽宇 Avatar

    关于 DMARC Report,如果只是将报告地址设置为自己的邮箱,那收到的都是给电脑看的原始数据。其实有很多现成的解决方案都是将 DMARC Report 的邮箱设置为第三方邮箱,由第三方汇总并生成更有意义的报告。我目前在用的免费的 Postmark DMARC 可以自动化处理 DMARC Report https://dmarc.postmarkapp.com ,每周会发送报告,感觉很好用

    1. Frank Avatar

      学习了。我刚注册了postmark的这个report,试试看好不好用。

发表回复/Leave a Reply

您的电子邮箱地址不会被公开。/Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.