Skip to content

필사 모드: DMARC 时隔 11 年终于成为标准 — RFC 9989 的树遍历、pct 的废除,以及 p=reject 的警告

中文
0%
정확도 0%
💡 왼쪽 원문을 읽으면서 오른쪽에 따라 써보세요. Tab 키로 힌트를 받을 수 있습니다.

引言 — 人人都在用,却算不上标准的协议

先从一个奇怪的事实说起。Gmail 和 Yahoo 从 2024 年起就已经事实上强制要求大宗发件人使用 DMARC,银行和政府机构的采用情况会被审计,一整个电子邮件安全创业生态都建立在它之上 — 可定义 DMARC 的RFC 7489从来就不是 IETF 标准。这份 2015 年 3 月发布的文档,是一份从未经过 IETF 工作组共识的 Independent Submission,分类也是 Informational。仅从文档地位来看,全世界的电子邮件认证,是在一份记录着「据说有人是这么做的」的文档之上运转了 11 年。

2026 年 5 月,这种状态结束了。IETF DMARC 工作组所谓的 DMARCbis 工作成果以RFC 9989的形式发布,DMARC 由此成为 Standards Track 文档,并废弃(obsolete)了 RFC 7489 以及(曾处理 PSD DMARC 的实验性文档)RFC 9091。据 datatracker 记录,这是第 41 版草案修订,正文长达 83 页。

如果只当作「恭喜升级为标准」一笔带过就太可惜了,因为这次修订实际改变了协议的行为。判定组织域的算法被整体替换,几个标签消失又新增,最重要的是,过去十年里社区心照不宣的运营原则,第一次被写成了 MUST 与 SHOULD NOT 这样的规范性语言。我们一项一项来看。(如果对 SMTP 和 DNS 本身还不熟悉,可以先读一读DNS 与电子邮件协议基础整理。)

发布了什么 — 一分为三的 DMARC

原本合而为一的 RFC 7489 规范,被拆成了三份文档。三者都在 2026 年 5 月同时发布,全部是 Standards Track。

  • RFC 9989 — DMARC 核心。策略记录语法、对齐(alignment)评估、策略发现。它废弃了 RFC 7489 和 RFC 9091。编辑是 Valimail 的 T. Herr 与 Standcore 的 J. Levine。
  • RFC 9990 — 汇总报告(aggregate reporting)。XML 报告格式和传输方式被分离到了这里。
  • RFC 9991 — 失败报告(failure reporting)。它更新了 RFC 6591。

报告规范的拆分并不只是文档整理,而是一次结构性变更 — 今后报告格式可以独立于核心规范演进。顺带一提,RFC 7489 在 11 年间累积的 15 条勘误(errata)分别是如何处理的,也逐条记录在 RFC 9989 的附录 C.9 中。

先说没变的 — 你的记录依然有效

对实务人员来说,最重要的事实是这个:版本字符串没有变。 RFC 9989 中 v 标签的定义依然规定 v=DMARC1 是唯一的有效值(区分大小写,且必须是记录中的第一个标签)。曾经在社区流传的「DMARC2 要来了」的说法并未成真。现在 DNS 里的记录,在新规范下依然有效,不存在所谓的迁移事件。

之所以能做到这一点,原因在于规范的扩展规则 — 未知标签必须(MUST)被忽略,所以新增标签不要求版本号升级。这正是后面会看到的 tnppsd 标签都能加在 v=DMARC1 之内的原因。反过来,像 pct 这样被废除的标签,对新一代接收方来说不过是「未知标签」,会被悄悄忽略。

最大的变化 — PSL 出局,DNS 树遍历入场

在 RFC 7489 中,判定组织域(Organizational Domain)的方法是 Public Suffix List(PSL)。这种做法的问题,RFC 7489 自己也心知肚明 — 它没有强制要求使用哪一份 PSL(只是建议了 publicsuffix.org),也没有给出更新周期的指引,并且承认不同接收方使用不同 PSL 会造成互操作性问题,还写下了「一旦出现更可靠的方法就应当被取代」这样的话。一份由 IETF 之外的志愿者维护的列表文件,竟然是全世界邮件策略判定的基准点,这始终是一种令人不安的依赖关系。

RFC 9989 把它换成了DNS 树遍历。不再依赖外部列表,而是直接沿着 DNS 层级向上走,寻找 DMARC 记录。

具体运作是这样的。首先在加了 _dmarc. 前缀的发件域(RFC5322.From 中的域名)上查询 TXT 记录,如果没有,就一层一层剥掉标签往上走。为了防止 DoS,查询次数设有上限 — 最多 8 次。标签数超过 8 个的域名会跳过中间部分,直接跳到从右数第 7 个标签的位置。照搬 RFC 自己给出的例子,一个有 13 个标签的域名,完整的树遍历会以下面这 8 次查询结束。

发送域: a.b.c.d.e.f.g.h.i.j.mail.example.com

1. _dmarc.a.b.c.d.e.f.g.h.i.j.mail.example.com   (原始域名)
2. _dmarc.g.h.i.j.mail.example.com               (跳到最右侧7个标签)
3. _dmarc.h.i.j.mail.example.com
4. _dmarc.i.j.mail.example.com
5. _dmarc.j.mail.example.com
6. _dmarc.mail.example.com
7. _dmarc.example.com
8. _dmarc.com

把上限定为 8 的理由文档里也有说明 — 在发布时观测到的数据中,实际使用中的发件域名标签数最多到 7 个,再加一个作为余量。

在沿途找到的记录中挑选组织域的规则,与新的 psd 标签挂钩。概括起来是这样。

  • 如果有效记录中带有 psd=n,那个域名就是组织域,到此为止。
  • 如果走访途中遇到的记录带有 psd=y(声明这是一个公共后缀域名),那么它下一级的域名就是组织域。
  • 如果两者都没有,在找到有效记录的那些名字里,标签数最少的那个就是组织域。

得益于这个设计,RFC 9091 曾经试验性尝试的 PSD DMARC(公共后缀级别的策略,例如国家 TLD 运营方阻止冒充其下不存在域名)得以在没有单独注册表的情况下并入核心规范。RFC 9989 平淡地记录下了对 RFC 9091 的实验结论 ——「未按原文所写的方式被实现」,并将其废弃。

过渡期的陷阱同样写进了规范。 实现 RFC 7489(基于 PSL)的接收方和实现 RFC 9989(树遍历)的接收方,对同一封邮件可能得出不同的组织域,进而是不同的策略与不同的对齐判定。规范给出的应对办法有两个 — 在实际用于发信的所有域名上都发布明确的 DMARC 记录,以及使用 strict 对齐。只要发件域名本身有记录,两种接收方都会在开始遍历之前的第一次查询就结束,算法上的差异也就不会显现出来。

标签整理 — pct 为什么消失了

这次修订新增了三个标签(nppsdt),删除了三个(pctrfri)。

pct 被废除的原委很有意思。它最初的设想是一种渐进式过渡装置 —「只对 N% 的邮件应用该策略」— 但 RFC 9989 附录 A.6 记录的运营经验是这样的:除了 0 和 100 之外,其他数值很少被精确执行,各家实现的偏差也很大。不过其中 pct=0 却以完全不同的用途存活了下来。一些中间方(邮件列表等)和邮箱服务商开始把 pct=0 解读为「这个域名即将开启策略」的信号,并以此作为触发条件,改写 From 头以避免 DMARC 失败。站在域名所有者的角度,比较开启 pct=0 前后的汇总报告,就能估算出「有多少流量经过了不改写 From 的中间方」,这在判断是否可以转向 enforcement 时确实很有用。

因此 RFC 9989 没有保留这个有效值实质上只有两种的百分比标签,而是只提取出那部分存活下来的功能,替换成了 t 标签(testing)。t=y 对应 pct=0,默认值 t=n 对应 pct=100t=y 的含义有明确定义 — 这是要求验证方不要照原样应用已声明的策略,而是降一级来执行p=reject 配上 t=y 会被当作 quarantine 处理,p=quarantine 配上 t=y 会被当作 none 处理,且不影响报告的生成。

np 标签是从 RFC 9091 引入的,它是针对不存在的子域名(NXDOMAIN,依据 RFC 8020 的语义)的策略。回退顺序是:没有 np 就用 sp,没有 sp 就用 p。在实务中,这是一个可以直接用来防御子域名冒充的工具 — 可以用 sp=none 观察真实存在的子域名,同时用 np=reject 立即封锁那些根本不存在的名字的冒充。

_dmarc.example.com. IN TXT "v=DMARC1; p=quarantine; t=y; sp=none; np=reject; rua=mailto:dmarc-rpt@example.com"

rf(失败报告格式)和 ri(报告间隔)标签被删除,在报告 URI 中指定最大尺寸的语法也一并消失(旧语法将被忽略)。报告相关的细节现在属于 RFC 9990/9991 的范畴。

标准第一次明文写下的运营原则

依我之见,这次修订真正的分量并不在算法,而在这里。过去十年里「大家都是这么做的」这类心照不宣的经验,第一次变成了规范性语言(MUST/SHOULD)。以下摘自 RFC 9989 的第 7.4 节和第 8 节。

第一,p=reject 域名不得只依赖 SPF(MUST NOT)。DKIM 签名是强制要求(MUST)。 原因在于转发。在校友邮件中继、基于角色的别名之类会中转邮件的流程里,SPF 几乎必然会失效 — 因为最终接收方看到的发信 IP 是中继方的,而不是原始发件方的。相反,只要正文没有被修改,DKIM 签名就能在中转后存活下来。如果一个原本单靠 SPF 就能通过 DMARC 的域名开启了 p=reject,正常的中转邮件就会被悄无声息地丢弃。

第二,普通用户会发送邮件的域名不应该发布 p=reject(SHOULD NOT)。 如果员工或成员可以用某个域名向互联网邮件列表发帖,p=reject 会给这些列表及其订阅者带来实实在在的损害。如果非要走这条路,规范甚至规定了流程 — 先用 p=none 至少一个月,再用 p=quarantine 保持同样长的时间,比较汇总报告中的处置结果之后再做决定。这也在暗示:像银行那样只发送机器生成的交易邮件的域名,和人可以自由撰写邮件的域名,理应采用不同的策略。

第三,接收方不得仅凭 p=reject 就拒绝邮件(MUST NOT)。 规范明确写道,如果没有其他佐证分析,仅有 DMARC 失败的情况必须(MUST)按 p=quarantine 的方式处理。也就是说,发件域名的策略声明对接收方而言只是参考输入,而非命令 — Gmail 这类大型接收方实际上一直以来的做法,如今变成了标准里的一句话。

此外,第 8 节定义了「完整参与 DMARC」的检查清单,也值得一读。域名所有者需要同时具备对齐的 SPF 对齐的 DKIM,建立汇总报告收件箱并实际进行分析,还要在发件域名和组织域名两处都发布记录。接收方则应当(SHOULD)至少以每天一次的频率发送汇总报告。

RFC 自己承认的事 — 邮件列表问题没有解决

第 7.4 节里有一段坦率程度在标准文档中并不常见的文字。转述其要旨 — 尽管有上述建议,现实中几乎没有接收方会为间接邮件流程应用缓解措施,也几乎没有组织会考虑对自家用户间接邮件的影响,而且这份文档的任何建议看起来都不太可能改变这个现实。结果就是,未修改 From 而经由邮件列表转发的邮件因为 p=reject 而频繁被拒收,过去十年里所有列表软件都无一例外地采用了改写 From 的应对办法,如今这已经成了既成事实,文档也如实记录了这一点。

那么,不改写 From 也能让列表存活下去的技术,究竟走到哪一步了呢? RFC 9989 直接点名的候选方案是ARC(Authenticated Received Chain,RFC 8617),但评价相当冷静 ——「none of the methods have become widely used」(没有一种方法得到广泛使用)。事实上,RFC 8617 自 2019 年以来至今仍停留在 Experimental 状态。这一节以「等到某种方法获得广泛采用时会再更新本文档」这样一句话收尾。总而言之,DMARC 最古老的副作用即便在标准化之后依然是一道悬而未决的问题,而这一点是标准自己说的。

SPF -all 的盲区 — 报告里看不到的拒绝

第 7.1 节指出的一个运营陷阱,值得单独提一下。SPF 可以在 SMTP 事务的早期、正文尚未传输之前就被评估。因此,SPF 记录以硬失败(-all)结尾的域名,其邮件可能在 DMARC 处理开始之前就被拒绝。这里的问题是双重的。

  • 一封本来带有对齐的 DKIM 签名、原本能通过 DMARC 的邮件,可能在 SPF 阶段就先被拦下。
  • 这种在 DATA 阶段之前就被拒绝的邮件,由于 From 域名还没有被揭示出来,根本不会出现在汇总报告里

如果你正靠 DMARC 汇总报告来监控发信状况,那么由 -all 造成的提前拒绝,恰恰发生在这套监控网络之外。「报告很干净」和「邮件都送达了」在这里成了两个不同的命题,因此使用 -all 的域名需要意识到这个盲区。在软失败(~all)与确保 DKIM 对齐的基础上,靠 DMARC 策略来控制拒绝,在可见性上是更好的选择。

实现走到了哪一步

发布两个月后的现在,显然处于过渡期。列举几个可以核实的点。

  • OpenDMARC 在 2026-05-27 开了一个针对 RFC 9989/9990/9991 的差距分析 issue 进行跟踪,而一个让用户可以在旧版 7489 遍历、PSL、9989 树遍历、自动之间选择组织域探测方式的 walk_mode 选择功能 PR 已在 2026-06-21 合并进 develop 分支。也就是说,即便在参考级的开源实现里,树遍历也才刚刚进入开发分支。
  • 荷兰政府系的诊断工具 Internet.nl 也开着一个把 PSL 换成树遍历的 issue,尚未关闭。
  • Gmail 的发件人指南截至本文写作时依然维持着 2024 年的体系 — 每天通过 Gmail 账户发送 5,000 封以上邮件的发件人,需要同时设置 SPF 和 DKIM 并发布 DMARC,但策略可以是 none(官方文档)。页面上任何地方都没有提到 RFC 9989。

大型邮箱服务商内部是否已经切换到树遍历,目前没有公开资料,这里不做断言。可以确定的是,短期内 PSL 型接收方与树遍历型接收方会在互联网上共存,这也让前面提到的应对办法 — 在实际用于发信的所有域名上发布明确记录 — 成为过渡期切实有效的防护手段。

实务清单 — 现在该做的事,与可以不做的事

先说可以不做的。 记录里的 v=DMARC1 保持不变。不存在所谓迁移到 DMARC2 这回事。现有的部署会继续照常运作。

该做的事大致是这些。

  1. 先确保 DKIM 对齐。 如果你已经是 p=reject,或者正打算走向那里,就得先确认所有发信路径都带有对齐的 DKIM 签名。依赖 SPF 单独通过的 p=reject,如今已经是明确的标准违规(MUST NOT)。
  2. 从记录里清理掉 pctrfri 新一代接收方反正会忽略它们,但旧接收方仍然会解读 pct,这正是两类接收方行为不一致的原因。如果需要渐进式过渡的信号,改用 t=y — 但也要考虑到,旧接收方同样不认识 t
  3. 在实际用于发信的所有域名上发布明确的 DMARC 记录。 这是规范直接推荐的做法,能从源头上杜绝 PSL 型接收方与树遍历型接收方得出不同答案的可能性。
  4. 如果担心不存在的子域名被冒充,就用 np 可以把它和真实存在子域名的策略(sp)分开,专门强力封锁那些解析结果为 NXDOMAIN 的名字。
  5. 如果你在用 -all,请意识到汇总报告里的盲区。 在 DATA 阶段之前被拒绝的邮件不会留在报告里。
  6. 重新考虑普通用户域名上的 p=reject 没有经过标准规定的流程 — none 至少一个月、quarantine 同样时长、比较报告 — 就直接转向 reject,现在已经成了一个有据可依的反对理由。

结语

只看协议层面的细节,这次标准化是一次安静的修订 — 记录本身没变,通过/失败的判定逻辑大部分也没变。但有三件事发生了实质性的变化:组织域的判定,从依赖外部列表(PSL)变成了 DNS 自身的探测(树遍历,最多 8 次查询);渐进式过渡装置,被替换成了经现实检验过的形式(t 标签);运营原则,第一次变成了可以引用的规范性语句 — p=reject 必须配 DKIM,不要对用户域名用 reject,接收方不能仅凭 reject 声明就丢弃邮件。

而这份标准最值得信赖的地方,是它把自己的局限性写进了文档本身。邮件列表问题依然悬而未决,ARC 依然是 Experimental,标准甚至预测了接收方不会遵循它的建议。历时 11 年的标准化,最终的结论不是「完成」,而是「对现实的诚实记录」— 对于电子邮件这样一个已有 40 年历史的系统来说,这样的结局似乎反倒恰如其分。

参考资料

현재 단락 (1/71)

先从一个奇怪的事实说起。Gmail 和 Yahoo 从 2024 年起就已经事实上强制要求大宗发件人使用 DMARC,银行和政府机构的采用情况会被审计,一整个电子邮件安全创业生态都建立在它之上 — 可...

작성 글자: 0원문 글자: 8,431작성 단락: 0/71