当前 Email 通信,还是在使用 SMTP 这个协议。SMTP 的全称为 Simple Mail Transfer Protocol,即「简单邮件传输协议」。正如它的名字锁暗示的,SMTP 实际上是一个非常简单(甚至简陋)的传输协议,本身并没有很好的安全措施。根据 SMTP 的规则,发件人的邮箱地址是可以由发信方任意声明的。在 SMTP 协议制定的时候也许还好,但在垃圾和诈骗邮件横行的今天,这显然是极不安全的。
SPF 出现的目的,就是为了防止随意伪造发件人。
SPF 记录实际上是服务器的一个 DNS 记录,原理其实很简单:
假设邮件服务器收到了一封邮件,来自主机的 IP 是173.194.72.103,并且声称发件人为email@example.com。为了确认发件人不是伪造的,邮件服务器会去查询example.com的 SPF 记录。如果该域的 SPF 记录设置允许 IP 为173.194.72.103的主机发送邮件,则服务器就认为这封邮件是合法的;如果不允许,则通常会退信,或将其标记为垃圾/仿冒邮件。
因为不怀好心的人虽然可以「声称」他的邮件来自example.com,但是他却无权操作example.com的 DNS 记录;同时他也无法伪造自己的 IP 地址。因此 SPF 是很有效的,当前基本上所有的邮件服务提供商(例如 Gmail、QQ 邮箱等)都会验证它。
一条 SPF 记录定义了一个或者多个 mechanism,而 mechanism 则定义了哪些 IP 是允许的,哪些 IP 是拒绝的。
这些 mechanism 包括以下几类:
all | ip4 | ip6 | a | mx | ptr | exists | include
每个 mechanism 可以有四种前缀:
"+" Pass(通过) "-" Fail(拒绝) "~" Soft Fail(软拒绝) "?" Neutral(中立)
测试时,将从前往后依次测试每个 mechanism。如果一个 mechanism 包含了要查询的 IP 地址(称为命中),则测试结果由相应 mechanism 的前缀决定。默认的前缀为+。如果测试完所有的 mechanisms 也没有命中,则结果为 Neutral。
除了以上四种情况,还有 None(无结果)、PermError(永久错误)和 TempError(临时错误)三种其他情况。对于这些情况的解释和服务器通常的处理办法如下:
结果 | 含义 | 服务器处理办法 |
Pass | 发件 IP 是合法的 | 接受来信 |
Fail | 发件 IP 是非法的 | 退信 |
Soft Fail | 发件 IP 非法,但是不采取强硬措施 | 接受来信,但是做标记 |
Neutral | SPF 记录中没有关于发件 IP 是否合法的信息 | 接受来信 |
None | 服务器没有设定 SPF 记录 | 接受来信 |
PermError | 发生了严重错误(例如 SPF 记录语法错误) | 没有规定 |
TempError | 发生了临时错误(例如 DNS 查询失败) | 接受或拒绝 |
注意,上面所说的「服务器处理办法」仅仅是 SPF 标准做出的建议,并非所有的邮件服务器都严格遵循这套规定。
Mechanisms
下面介绍上面提到的 mechanism:
表示所有 IP,肯定会命中。因此通常把它放在 SPF 记录的结尾,表示处理剩下的所有情况。例如:
"v=spf1 -all" 拒绝所有(表示这个域名不会发出邮件) "v=spf1 +all" 接受所有(域名所有者认为 SPF 是没有用的,或者根本不在乎它)
格式为ip4:<ip4-address>或者ip4:<ip4-network>/<prefix-length>,指定一个 IPv4 地址或者地址段。如果prefix-length没有给出,则默认为/32。例如:
"v=spf1 ip4:192.168.0.1/16 -all" 只允许在 192.168.0.1 ~ 192.168.255.255 范围内的 IP
格式和ip4的很类似,默认的prefix-length是/128。例如:
"v=spf1 ip6:1080::8:800:200C:417A/96 -all" 只允许在 1080::8:800:0000:0000 ~ 1080::8:800:FFFF:FFFF 范围内的 IP
这俩的格式是相同的,以a为例,格式为以下四种之一:
a a/<prefix-length> a:<domain> a:<domain>/<prefix-length>
会命中相应域名的 a 记录(或 mx 记录)中包含的 IP 地址(或地址段)。如果没有提供域名,则使用当前域名。例如:
"v=spf1 mx -all" 允许当前域名的 mx 记录对应的 IP 地址。 "v=spf1 mx mx:deferrals.example.com -all" 允许当前域名和 deferrals.example.com 的 mx 记录对应的 IP 地址。 "v=spf1 a/24 -all" 类似地,这个用法则允许一个地址段。
例如,这是一个比较常见的 SPF 记录,它表示支持当前域名的 a 记录和 mx 记录,同时支持一个给定的 IP 地址;其他地址则拒绝:
v=spf1 a mx ip4:173.194.72.103 -all
格式为include:<domain>,表示引入<domain>域名下的 SPF 记录。注意,如果该域名下不存在 SPF 记录,则会导致一个PermError结果。例如:
"v=spf1 include:example.com -all" 即采用和 example.com 完全一样的 SPF 记录
格式为exists:<domain>。将对<domain>执行一个 A 查询,如果有返回结果(无论结果是什么),都会看作命中。
格式为ptr或者ptr:<domain>。使用ptr机制会带来大量很大开销的 DNS 查询,所以连官方都不推荐使用它。
关于v=spf1
这是必须的,这个表示采用 SPF 1 版本(现在它的最新版本是第2版,即spf2,为了兼容性,建议用spf1)
Modifiers
SPF 记录中还可以包括两种可选的 modifier;一个 modifier 只能出现一次。
格式为redirect=<domain>
将用给定域名的 SPF 记录替换当前记录。
格式为exp=<domain>,目的是如果邮件被拒绝,可以给出一个消息。而消息的具体内容会首先对<domain>执行 TXT 查询,然后执行宏扩展得到。
如果你拥有自己的域名,并且用它发送邮件,那么你应该为它添加 SPF。通过域名服务商提供的「域名解析」、「DNS Editor」或者「DNS Zone Editor」等功能添加,并填写正确的 SPF 数据就可以了。
严格来说,SPF 数据应该创建为 SPF 记录。但是鉴于很多 DNS 服务商不支持 SPF 记录,甚至有的邮件服务器也不支持 SPF 记录,因此也可以创建为一条 TXT 记录。目前,你应该至少创建一条 TXT 记录。
因为本质上 SPF 的作用是为一个域名指定合法的发件 IP,所以你需要知道自己使用的邮件服务器的发件 IP 是什么。如果你使用第三方的域名邮箱服务(比如腾讯的域名邮箱),那么他们应该有相应的文档告诉你该怎么填写。如果你用虚拟主机,则主机提供商也应该会告诉你。
SPF 记录本质上是一个 DNS 记录,所以并不是修改之后立即生效的——通常需要几个小时的时间。
虽然我不能帮你决定 SPF 该填什么,但是这里有一些非常好用的工具可以帮助你,点击它们在新窗口打开:
来自话题 spf / email / security
本文作者为 Renfei Song,最后修订于 2014/12/6