非官方中文译本声明:本页为 IETF RFC 6376《DomainKeys Identified Mail (DKIM) Signatures》中文译本,由 ztpop.net 整理翻译,仅供学习参考。RFC 文档由 IETF 发布,受 BCP 78 与 IETF 信托法律条款约束;本译本保留原文编号与结构,权威性以英文原文为准。英文原文见 rfc-editor.org/rfc/rfc6376

RFC 6376:域名密钥识别邮件(DKIM)签名

封面与作者信息

本备忘录由互联网工程任务组(IETF)发布,类别为标准跟踪(Standards Track),替代 RFC 4871 与 RFC 5672。三位编辑分别来自 Brandenburg InternetWorking、AT&T Laboratories 与 Cloudmark。文档由 IETF 共识产生,并经互联网工程指导组(IESG)批准出版。

本备忘录的状态

本文档是一份互联网标准跟踪文档。

本文档是互联网工程任务组(IETF)的成果,代表了 IETF 社区的共识,已通过公开评审,并经互联网工程指导组(IESG)批准出版。有关互联网标准的更多信息见 RFC 5741 第 2 节。

关于本文档当前状态、任何勘误以及如何提供反馈的信息,可在 http://www.rfc-editor.org/info/rfc6376 获取。

Copyright (c) 2011 IETF 信托及被列为文档作者的个人。保留所有权利。

本文档受 BCP 78 以及 IETF 信托的《IETF 文档相关法律规定》(http://trustee.ietf.org/license-info)约束,以本文档发布之日生效的版本为准。请仔细审阅这些文档,因为它们描述了您就本文档所享有的权利与限制。从本文档中提取的代码组件必须包含简化 BSD 许可证文本(见信托法律条款第 4.e 节),并按该许可证的说明以"不提供任何担保"的方式提供。

摘要

域名密钥识别邮件(DomainKeys Identified Mail,DKIM)允许拥有签名域的个人、角色或组织,通过将域名与消息关联,从而对消息主张一定的责任。该责任主体可以是作者的组织、运营中继(operational relay),也可以是它们的某个代理。DKIM 将消息签名者的身份问题与消息所谓的作者身份区分开来。责任主张通过密码学签名来验证,并通过对签名者域的直接查询来检索相应的公钥。消息从作者到收件人的传输经由中继完成,这些中继通常不会对消息内容做出实质性修改,因而能保留 DKIM 签名。

本备忘录替代 RFC 4871 与 RFC 5672。

目录

1. 引言

域名密钥识别邮件(DKIM)允许个人、角色或组织,通过将一个域名 [RFC1034] 与消息 [RFC5322] 关联(并且该域名是其被授权使用的),从而对消息主张一定的责任。该责任主体可以是作者的组织、一个运营中继,也可以是它们的某个代理。责任主张通过密码学签名来验证,并通过对签名者域的直接查询来检索相应的公钥,从而验证签名者身份与消息的关联。

一条消息可以包含来自同一组织或多个不同组织的多个签名。

DKIM 所采用的方法与以往的消息签名方法(例如安全/多用途互联网邮件扩展(S/MIME)[RFC5751]、OpenPGP [RFC4880])不同,体现在:

DKIM:

1.1. DKIM 体系结构文档

建议读者熟悉 [RFC4686]、[RFC5585] 与 [RFC5863] 中的内容,它们分别提供了 DKIM 开发的背景、该服务的概述,以及部署与运营的指导和建议。

1.2. 签名身份

DKIM 将消息签名者的身份问题与消息所谓的作者身份区分开来。具体而言,签名中会包含签名者的身份。验证方可以利用签名信息来决定如何处理该消息。签名身份作为签名头字段的一部分被包含在内。

资料性理由:DKIM 签名所指定的签名身份,不要求与任何特定头字段中的地址相匹配,因为接收方邮件系统(包括 MUA)对它的解释方式多种多样。

1.3. 可扩展性

DKIM 旨在支持电子邮件身份识别问题所特有的、极高的可扩展性要求。域的数量数以百万计,而单个地址的数量则更为庞大。

DKIM 力求保留当前电子邮件基础设施的积极方面,例如任何人与其他任何人无需引荐即可通信的能力。

1.4. 简单的密钥管理

DKIM 与传统分层公钥系统的不同之处在于:它不需要证书颁发机构基础设施;验证方直接从被声称的签名者域中的仓库请求公钥,而不是从第三方获取。

DNS 被提议作为公钥的初始机制。因此,DKIM 目前依赖于 DNS 管理与 DNS 系统的安全性。DKIM 被设计为可扩展到其他密钥获取服务,随着它们变得可用而采用。

1.5. 数据完整性

DKIM 签名将 "d=" 名称与对消息部分或全部内容计算出的哈希(见第 3.7 节)相关联,以防止签名被复用到不同的消息上。验证签名即断言被哈希的内容自签名以来未发生变化,除此之外不就"保护"消息的端到端完整性作任何断言。

2. 术语与定义

本节定义文档其余部分使用的术语。

DKIM 被设计为在 [RFC5598] 所定义的互联网邮件服务内运行。基本的电子邮件术语取自该规范。

语法描述使用增广 BNF(ABNF)[RFC5234]。

本文档中的关键词"MUST(必须)"、"MUST NOT(不得)"、"REQUIRED(要求)"、"SHALL(应)"、"SHALL NOT(不应)"、"SHOULD(应该)"、"SHOULD NOT(不应该)"、"RECOMMENDED(推荐)"、"NOT RECOMMENDED(不建议)"、"MAY(可以)"和"OPTIONAL(可选)"应按照 [RFC2119] 中的描述进行解释。这些词仅当以全大写形式出现时才取其规范性含义。

2.1. 签名方(Signers)

邮件系统中代表某个域对消息进行签名的要素称为签名方。它们可以是 MUA(邮件用户代理)、MSA(邮件提交代理)、MTA(邮件传输代理),或其他代理(例如邮件列表分发器)。一般而言,任何签名方都会以某种方式参与将消息注入消息系统。关键在于,消息必须在离开签名方的管理域之前被签名。

2.2. 验证方(Verifiers)

邮件系统中验证签名的要素称为验证方。它们可以是 MTA、邮件投递代理(MDA),或 MUA。在大多数情况下,预计验证方会靠近消息的终端用户(读者)或某个消费型代理(例如邮件列表分发器)。

2.3. 身份(Identity)

一个人、角色或组织。在 DKIM 的语境下,例子包括作者、作者的组织、处理路径上的某个 ISP、独立的信任评估服务,以及邮件列表运营者。

2.4. 标识符(Identifier)

指代某个身份的标签。

2.5. 签名域标识符(SDID)

一个单独的域名,它是 DKIM 的强制性输出载荷,指代通过签名而对消息主张一定责任的身份。它在第 3.5 节中规定。

2.6. 代理或用户标识符(AUID)

一个单独的标识符,指代签名域标识符(SDID)代表其主张责任的代理或用户。AUID 由一个域名和一个可选的 <local-part> 组成。该域名与用于 SDID 的域名相同,或是其子域。就 DKIM 处理而言,AUID 的域名部分只具有基本的域名语义;任何可能的属主特定语义都在 DKIM 的范围之外。它在第 3.5 节中规定。

注意,AUID 的可接受取值可通过公钥记录中的某个标志加以约束(见第 3.6.1 节)。

2.7. 身份评估者(Identity Assessor)

邮件系统中消费 DKIM 载荷(即负有责任的签名域标识符 SDID)的要素。身份评估者专门负责对所投递的标识符进行评估。其他 DKIM(及非 DKIM)取值也可被身份评估者(若可得)用来提供一个更通用的消息评估过滤引擎。然而,这一额外活动不在本规范的范围内。

2.8. 空白字符(Whitespace)

空白字符有三种形式:

它们的正式 ABNF 如下(WSP 和 LWSP 仅作参考给出):

WSP =   SP / HTAB
LWSP =  *(WSP / CRLF WSP)
FWS =   [*WSP CRLF] 1*WSP

FWS 的定义与 [RFC5322] 中的相同,只是排除了 obs-FWS。

2.9. 导入的 ABNF 记号

下列记号按注明的来源从其他 RFC 导入。那些 RFC 应被视为权威来源。

下列记号从 [RFC5321] 导入:

下列记号从 [RFC5322] 导入:

下列记号从 [RFC2045] 导入:

资料性注释:注意 [RFC2045] 中的 ABNF 不遵守 [RFC5234] 的规则,必须相应地加以解释,特别是在大小写折叠方面。

此处未定义的其他记号从 [RFC5234] 导入。这些是不言自明的原语,如 SP、HTAB、WSP、ALPHA、DIGIT、CRLF 等。

2.10. 通用 ABNF 记号

下列 ABNF 记号在本文档其他地方使用:

hyphenated-word =  ALPHA [ *(ALPHA / DIGIT / "-") (ALPHA / DIGIT) ]
ALPHADIGITPS    =  (ALPHA / DIGIT / "+" / "/")
base64string    =  ALPHADIGITPS *([FWS] ALPHADIGITPS)
                     [ [FWS] "=" [ [FWS] "=" ] ]
hdr-name        =  field-name
qp-hdr-value    =  dkim-quoted-printable    ; with "|" encoded

2.11. DKIM-Quoted-Printable

DKIM-Quoted-Printable 编码语法类似于 Quoted-Printable [RFC2045] 第 6.7 节所描述的内容:任何字符都可以编码为"="后跟两个十六进制数字(字母表为 "0123456789ABCDEF",不允许小写字符),表示其十六进制编码的整数值。所有控制字符(值 < %x20)、8 位字符(值 > %x7F)、以及 DEL(%x7F)、SPACE(%x20)和分号(";",%x3B)都必须被编码。注意,所有空白字符(包括 SPACE、CR 和 LF 字符)都必须被编码。编码之后,可在任意位置加入 FWS 以避免出现过长的行;此类空白不是值的一部分,解码前必须被移除。不建议使用 [RFC2049] 中未列为"邮件安全"(mail-safe)的字符。

ABNF:

dkim-quoted-printable =  *(FWS / hex-octet / dkim-safe-char)
                              ; hex-octet is from RFC2045
dkim-safe-char        =  %x21-3A / %x3C / %x3E-7E
                              ; '!' - ':', '<', '>' - '~'

资料性注释:DKIM-Quoted-Printable 与 [RFC2045] 中定义的 Quoted-Printable 在若干重要方面存在差异:

  1. 输入文本中的空白字符(包括 CR 和 LF)必须被编码。[RFC2045] 不要求此类编码,也不允许对作为 CRLF 换行一部分的 CR 或 LF 字符进行编码。
  2. 编码文本中的空白字符被忽略。这是为了允许使用 DKIM-Quoted-Printable 编码的标签按需换行。特别地,[RFC2045] 要求输入中的换行表示为物理换行;此处并非如此。
  3. "软换行"语法("=" 作为行上最后一个非空白字符)不适用。
  4. DKIM-Quoted-Printable 不要求编码行不超过 76 个字符(尽管根据编码文本使用语境的不同,可能还有其他要求)。

3. 协议元素

协议元素是协议的概念性组成部分,它们既非特定于签名方,也非特定于验证方。签名方与验证方的协议描述在后面的章节中给出("签名方动作"见第 5 节,"验证方动作"见第 6 节)。注意:本节必须结合那些章节的语境来阅读。

3.1. 选择器(Selectors)

为了支持每个签名域有多个并存的公钥,密钥命名空间使用"选择器"进行细分。例如,选择器可以表示办公地点的名称(如 "sanfrancisco"、"coolumbeach"、"reykjavik"),签名日期(如 "january2005"、"february2005" 等),甚至某个具体用户。

选择器用于支持一些重要的用例。例如:

选择器中允许使用句点,句点是组件分隔符。当从 DNS 检索密钥时,选择器中的句点以类似于域名中常规用法的方式定义 DNS 标签边界。选择器组件可用于将日期与地点组合,例如 "march2005.reykjavik"。在 DNS 实现中,这可用于允许对选择器命名空间的一部分进行委托。

ABNF:

selector =   sub-domain *( "." sub-domain )

每个域拥有的公钥及相应选择器的数量由域所有者决定。许多域所有者仅使用一个选择器即可满足需求,而管理上分散的组织则可以选择在不同区域或不同邮件服务器上管理不同的选择器与密钥对。

除管理上的便利外,选择器使得能够无缝地定期更换公钥。如果一个域希望从使用与选择器 "january2005" 关联的公钥切换到与选择器 "february2005" 关联的公钥,它只需在邮件可能处于传输途中(尚未被验证)的过渡期内,同时在公钥仓库中公布这两个公钥。在过渡期开始时,出站邮件服务器被配置为使用 "february2005" 私钥签名。在过渡期结束时,公钥 "january2005" 从公钥仓库中移除。

资料性注释:密钥也可以按如下所述被撤销。撤销一个密钥选择器记录与移除它的区别是微妙的。在上述逐步淘汰密钥的情形中,签名域在过渡期之后很可能只是简单地移除该密钥记录。不过,签名域也可以选择将该密钥(但保留密钥记录)撤销一段更长时间。被撤销的密钥与已移除的密钥之间没有定义上的语义差异。

某些域可能希望使选择器取值广为人知,而另一些域则要注意避免以允许外部方采集数据的方式分配选择器名称。例如,如果发放了每用户密钥,域所有者需要决定是将该选择器直接与注册终端用户的名称相关联,还是使其成为一个无关联的随机值(例如公钥的指纹)。

资料性运营注释:将选择器复用于新密钥(例如,更改与用户名称关联的密钥)会使得无法区分"因密钥不再有效而未通过验证的消息"与"实际被伪造的消息"。因此,不建议签名方为新的密钥复用选择器。更好的策略是将新密钥分配给新的选择器。

3.2. 标签=值列表(Tag=Value Lists)

DKIM 在多种语境(包括消息中和域签名记录中)使用简单的 "tag=value" 语法。

值是一系列字符串,包含纯文本、"base64" 文本(定义见 [RFC2045] 第 6.8 节)、"qp-section"(同上,第 6.7 节),或 "dkim-quoted-printable"(定义见第 2.11 节)。标签的名称决定每个值的编码方式。未编码的分号(";")字符不得出现在标签值中,因为分号用于分隔标签规格(tag-spec)。

资料性实现注释:尽管下文定义的"纯文本"(即 "tag-value")仅包含 7 位字符,但希望为未来标准做准备的实作,最好不要排除在 tag=value 列表中使用 UTF-8 编码([RFC3629])的文本。

形式上,ABNF 语法规则如下:

tag-list  =  tag-spec *( ";" tag-spec ) [ ";" ]
tag-spec  =  [FWS] tag-name [FWS] "=" [FWS] tag-value [FWS]
tag-name  =  ALPHA *ALNUMPUNC
tag-value =  [ tval *( 1*(WSP / FWS) tval ) ]
                     ; Prohibits WSP and FWS at beginning and end
tval      =  1*VALCHAR
VALCHAR   =  %x21-3A / %x3C-7E
                     ; EXCLAMATION to TILDE except SEMICOLON
ALNUMPUNC =  ALPHA / DIGIT / "_"

注意,标签周围允许出现 WSP。特别地,"=" 之后的任何 WSP 和终止 ";" 之前的任何 WSP 都不是值的一部分;但值内部的 WSP 是显著的。

标签必须以区分大小写的方式解释。除非特定标签的语义描述规定了大小写不敏感,否则值必须以区分大小写的方式处理。

重复的标签名称不得出现在单个 tag-list 中;如果某个标签名称出现多次,整个 tag-list 无效。

值内部的空白字符必须保留,除非被特定标签描述明确排除。

表示默认值的 tag=value 对可以包含进来以帮助阅读。

无法识别的标签必须被忽略。

具有空值的标签不同于被省略的标签。被省略的标签被视为具有默认值;而具有空值的标签则明确将空字符串指定为值。

3.3. 签名与验证算法

DKIM 支持多种数字签名算法。本规范目前定义了两种算法:rsa-sha1 和 rsa-sha256。签名方必须实现并应该使用 rsa-sha256 签名。验证方必须同时实现 rsa-sha1 和 rsa-sha256。

资料性注释:尽管强烈鼓励使用 rsa-sha256,但某些发送方在权衡安全性强度与性能、复杂性或其他需求时,可能更倾向于使用 rsa-sha1。然而,一般而言,只要可能,应始终使用 rsa-sha256。

3.3.1. rsa-sha1 签名算法

rsa-sha1 签名算法使用 SHA-1 [FIPS-180-3-2008] 作为 hash-alg,按照第 3.7 节的描述计算消息哈希。随后该哈希由签名方使用 RSA 算法(定义于公钥密码学标准(PKCS)#1 1.5 版 [RFC3447])作为 crypt-alg,并用签名方的私钥进行签名。哈希在被签名之前不得被截断或转换为除原生二进制形式之外的任何形式。签名算法应使用 65537 作为公指数。

3.3.2. rsa-sha256 签名算法

rsa-sha256 签名算法使用 SHA-256 [FIPS-180-3-2008] 作为 hash-alg,按照第 3.7 节的描述计算消息哈希。随后该哈希由签名方使用 RSA 算法(定义于 PKCS#1 1.5 版 [RFC3447])作为 crypt-alg,并用签名方的私钥进行签名。哈希在被签名之前不得被截断或转换为除原生二进制形式之外的任何形式。签名算法应使用 65537 作为公指数。

3.3.3. 密钥大小

选择合适的密钥大小是在成本、性能与风险之间的权衡。由于较短的 RSA 密钥更容易遭受离线攻击,签名方必须为长期密钥使用至少 1024 位的 RSA 密钥。验证方必须能够验证密钥长度从 512 位到 2048 位的签名,并且可能能够验证更大密钥的签名。验证方策略可以将签名密钥的长度作为一个度量标准,用以判断签名是否可接受。

影响密钥大小选择的因素包括:

关于选择密钥大小的进一步讨论见 [RFC3766]。

3.3.4. 其他算法

未来可能会定义其他算法。验证方必须忽略任何使用其未实现的算法的签名。

3.4. 规范化(Canonicalization)

某些邮件系统会在传输过程中修改电子邮件,可能使签名失效。对大多数签名方而言,对电子邮件的轻微修改对于验证 DKIM 域名的使用无关紧要。对此类签名方而言,能够经受适度传输修改的规范化算法更受青睐。

其他签名方要求对电子邮件的任何修改(无论多么微小)都导致签名验证失败。这些签名方偏好不容忍对签名电子邮件进行传输修改的规范化算法。

某些签名方可能愿意接受在电子邮件标准(如 [RFC5322])范围内对头字段的修改,但不愿意接受对消息体的任何修改。

为了满足所有要求,针对头字段和消息体分别定义了两种规范化算法:一种"simple(简单)"算法,几乎不容忍任何修改;一种"relaxed(宽松)"算法,容忍常见修改,如空白字符替换和头字段行重新换行。签名方在对电子邮件签名时,可以为头字段或消息体指定任一种算法。如果签名方未指定规范化算法,头字段和消息体都默认使用 "simple" 算法。验证方必须实现这两种规范化算法。注意,头字段和消息体可以使用不同的规范化算法。未来可能会定义进一步的规范化算法;验证方必须忽略使用无法识别的规范化算法的任何签名。

规范化只是为将电子邮件呈现给签名或验证算法做准备。它不得以任何方式改变被传输的数据。头字段和消息体的规范化如下所述。

注意:本节假设消息已经处于"网络规范"格式(文本为 ASCII 编码,行以 CRLF 字符分隔等)。另见第 5.3 节关于规范化消息的信息。

3.4.1. "simple" 头字段规范化算法

"simple" 头字段规范化算法不以任何方式改变头字段。头字段必须以它们在被签名或被验证消息中的原样呈现给签名或验证算法。特别地,头字段名称不得进行大小写折叠,空白字符不得被改变。

3.4.2. "relaxed" 头字段规范化算法

"relaxed" 头字段规范化算法必须按顺序应用以下步骤:

3.4.3. "simple" 消息体规范化算法

"simple" 消息体规范化算法忽略消息体末尾的所有空行。空行是指去除行终止符后长度为零的行。如果消息体为空或消息体末尾没有结尾 CRLF,则添加一个 CRLF。它对消息体不做其他修改。更形式化地说,"simple" 消息体规范化算法将体末尾的 "*CRLF" 转换为单个 "CRLF"。

注意,完全为空或缺失的消息体被规范化为单个 "CRLF";即规范化后的长度为 2 个八位组。

空消息体(规范化为 "CRLF")的 SHA-1 值(base64 形式)为:

uoq1oCgLlTqpdDX/iUbLy7J1Wic=

SHA-256 值为:

frcCV1k9oG9oKj3dpUqdJg1PxRT2RSN/XKdLCPjaYaY=

3.4.4. "relaxed" 消息体规范化算法

"relaxed" 消息体规范化算法必须按顺序应用以下步骤 (a) 和 (b):

a. 缩减空白:

b. 忽略消息体末尾的所有空行。"空行"的定义见第 3.4.3 节。如果消息体非空但不以 CRLF 结尾,则添加一个 CRLF。(对于电子邮件,这仅在使用 SMTP 扩展或非 SMTP 传输机制时才可能发生。)

空消息体(规范化为空输入)的 SHA-1 值(base64 形式)为:

2jmj7l5rSw0yVb/vlWAYkK/YBwk=

SHA-256 值为:

47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU=

3.4.5. 规范化示例(资料性)

在下列示例中,实际的空白字符仅用于清晰起见。实际的输入与输出文本使用带括号的描述符表示:"<SP>" 表示空格字符,"<HTAB>" 表示制表符,"<CRLF>" 表示回车/换行序列。例如,"X <SP> Y" 和 "X<SP>Y" 表示相同的三个字符。

示例 1:一条读取如下的消息:

A: <SP> X <CRLF>
B <SP> : <SP> Y <HTAB><CRLF>
                <HTAB> Z <SP><SP><CRLF>
<CRLF>
<SP> C <SP><CRLF>
D <SP><HTAB><SP> E <CRLF>
<CRLF>
<CRLF>

当使用 relaxed 规范化对头字段和消息体都进行规范化时,得到的头字段为:

a:X <CRLF>
b:Y <SP> Z <CRLF>

得到的消息体为:

<SP> C <CRLF>
D <SP> E <CRLF>

示例 2:同一条消息使用 simple 规范化对头字段和消息体都进行规范化时,得到的头字段为:

A: <SP> X <CRLF>
B <SP> : <SP> Y <HTAB><CRLF>
       <HTAB> Z <SP><SP><CRLF>

得到的消息体为:

<SP> C <SP><CRLF>
D <SP><HTAB><SP> E <CRLF>

示例 3:当使用 relaxed 头字段规范化和 simple 消息体规范化处理时,规范化版本的头字段为:

a:X <CRLF>
b:Y <SP> Z <CRLF>

消息体为:

<SP> C <SP><CRLF>
D <SP><HTAB><SP> E <CRLF>

3.5. DKIM-Signature 头字段

电子邮件的签名存储在 DKIM-Signature 头字段中。该头字段包含所有签名与密钥获取数据。DKIM-Signature 取值是一个如第 3.2 节所述的 tag-list。

DKIM-Signature 头字段应被视为 [RFC5322] 第 3.6 节定义的追踪(trace)头字段,因此不应被重排,并且应被前置(prepended)到消息中。

正在被创建或验证的 DKIM-Signature 头字段总是被包含在签名计算中,位于其他被签名的头字段之后;但是,在计算或验证签名时,该 DKIM-Signature 头字段的 "b=" 标签(签名值)的取值必须被视为空字符串。DKIM-Signature 头字段中无法识别的标签必须被包含在签名计算中,但在其他方面必须被验证方忽略。被包含在签名中的其他 DKIM-Signature 头字段应被视为普通头字段;特别地,"b=" 标签不被特殊处理。

各字段类型的编码如下。被描述为 qp-section 的标签按照 MIME 第一部分 [RFC2045] 第 6.7 节编码,并额外将分号字符转换为 "=3B";直观地说,这是一行 quoted-printable 编码的文本。dkim-quoted-printable 语法定义在第 2.11 节。

DKIM-Signature 头字段上的标签及其类型与要求状态如下所示。无法识别的标签必须被忽略。

v= 版本(纯文本;必需)。该标签定义适用于该签名记录的本规范版本。对于符合本版本 DKIM 的实现,它必须具有值 "1"。

ABNF:

sig-v-tag       = %x76 [FWS] "=" [FWS] 1*DIGIT

资料性注释:随着本规范新版本的发布,DKIM-Signature 版本号可能会按算术递增。

a= 用于生成签名的算法(纯文本;必需)。验证方必须支持 "rsa-sha1" 和 "rsa-sha256";签名方应该使用 rsa-sha256 签名。算法描述见第 3.3 节。

ABNF:

sig-a-tag       = %x61 [FWS] "=" [FWS] sig-a-tag-alg
sig-a-tag-alg   = sig-a-tag-k "-" sig-a-tag-h
sig-a-tag-k     = "rsa" / x-sig-a-tag-k
sig-a-tag-h     = "sha1" / "sha256" / x-sig-a-tag-h
x-sig-a-tag-k   = ALPHA *(ALPHA / DIGIT)
                     ; for later extension
x-sig-a-tag-h   = ALPHA *(ALPHA / DIGIT)
                     ; for later extension

b= 签名数据(base64;必需)。该值中的空白被忽略,并且在重组原始签名时必须被忽略。特别地,签名过程可以安全地在任意位置插入 FWS 以符合行长度限制。签名如何计算见"签名方动作"(第 5 节)。

ABNF:

sig-b-tag       = %x62 [FWS] "=" [FWS] sig-b-tag-data
sig-b-tag-data  = base64string

bh= 由 "l=" 标签限定的消息规范化后消息体的哈希(base64;必需)。该值中的空白被忽略,并且在重组原始签名时必须被忽略。特别地,签名过程可以安全地在任意位置插入 FWS 以符合行长度限制。消息体哈希如何计算见第 3.7 节。

ABNF:

sig-bh-tag      = %x62 %x68 [FWS] "=" [FWS] sig-bh-tag-data
sig-bh-tag-data = base64string

c= 消息规范化(纯文本;可选,默认 "simple/simple")。该标签告知验证方用于为签名准备消息的规范化类型。它由用斜杠(%d47)字符分隔的两个名称组成,分别对应于头字段和消息体规范化算法。这些算法在第 3.4 节描述。如果只命名了一个算法,则该算法用于头字段,而 "simple" 用于消息体。例如,"c=relaxed" 被视为与 "c=relaxed/simple" 相同。

ABNF:

sig-c-tag       = %x63 [FWS] "=" [FWS] sig-c-tag-alg
                     ["/" sig-c-tag-alg]
sig-c-tag-alg   = "simple" / "relaxed" / x-sig-c-tag-alg
x-sig-c-tag-alg = hyphenated-word    ; for later extension

d= 主张将消息引入邮件流的 SDID(纯文本;必需)。因此,SDID 取值被用于构造用于检索公钥的查询。SDID 必须对应于一个有效的 DNS 名称,DKIM 密钥记录发布在其下。签名方创建和使用特定 SDID 所遵循的约定与语义不在本规范范围内,对这些约定与语义的任何使用也是如此。当遇到不满足这些要求的签名时,验证方必须将该签名视为无效。

国际化域名必须编码为 A-label,如 [RFC5890] 第 2.3 节所述。

ABNF:

sig-d-tag       = %x64 [FWS] "=" [FWS] domain-name
domain-name     = sub-domain 1*("." sub-domain)
                     ; from [RFC5321] Domain,
                     ; excluding address-literal

h= 被签名的头字段(纯文本,但见描述;必需)。一个冒号分隔的头字段名称列表,标识呈现给签名算法的头字段。该字段必须包含呈现给签名算法的头字段的完整列表(按呈现顺序)。该字段可以包含签名时不存在的头字段名称;不存在的头字段不参与签名计算(即,它们被视为空输入,包括头字段名称、分隔冒号、头字段值以及任何 CRLF 终止符)。该字段可以包含某个头字段名称的多个实例,意味着该对应头字段的多次出现都被包含在头哈希中。该字段不得包含正在被创建或验证的 DKIM-Signature 头字段,但可能包含其他的。折叠空白(FWS)可以出现在冒号分隔符的两侧。头字段名称必须与实际的头字段名称以大小写不敏感的方式比较。该列表不得为空。关于选择要签名的头字段的讨论见第 5.4 节,关于签名单个字段多个实例的要求见第 5.4.2 节。

ABNF:

sig-h-tag       = %x68 [FWS] "=" [FWS] hdr-name
                    *( [FWS] ":" [FWS] hdr-name )

资料性解释:通过"签名"实际并不存在的头字段,签名方可以让验证方检测到在签名之后插入了那些头字段。然而,由于签名方不可能预先知道未来会定义哪些头字段,该机制不能用于防止添加任何可能的未知头字段。

资料性注释:对签名时不存在的字段进行"签名",不仅防止添加字段和值,也防止添加没有值的字段。

i= SDID 代表其主张责任的代理或用户标识符(AUID)(dkim-quoted-printable;可选,默认是一个空的 local-part 后跟一个 "@" 再后跟来自 "d=" 标签的域)。

语法是一个标准的电子邮件地址,其中 local-part 可以省略。地址的域部分必须与 "d=" 标签的取值相同,或是其子域。

国际化域名必须编码为 A-label,如 [RFC5890] 第 2.3 节所述。

ABNF:

sig-i-tag       = %x69 [FWS] "=" [FWS] [ Local-part ]
                    "@" domain-name

AUID 被规定为具有与电子邮件地址相同的语法,但不必具有相同的语义。值得注意的是,域名不必在 DNS 中注册——因此它可能在查询中无法解析——并且 local-part 可能取自与任何邮箱都无关的命名空间。该命名空间的结构与语义细节由签名方决定。验证方或评估者对这些细节的任何了解或使用都在本规范范围之外。签名方可以选择对其 AUID 使用与用户电子邮件地址相同的命名空间,也可以选择其他表示其用户的方式。然而,如果签名方希望为接收方提供将 AUID 用作比 SDID 更细粒度、稳定的标识符的选项,则应为每封旨在被评估为处于同一责任范围内的消息使用相同的 AUID。

资料性注释:"i=" 标签的 local-part 是可选的,因为在某些情况下签名方可能无法确立一个已验证的个别身份。在此类情况下,签名方可能希望主张:尽管它愿意签署到域的级别,但它无法或不愿承诺域内的某个个别用户名。它可以通过包含域部分但不包含身份的 local-part 来做到这一点。

资料性讨论:本规范不要求 "i=" 标签的取值与任何消息头字段中的身份相匹配。这被视为验证方策略问题。"i=" 标签取值与其他头字段中其他身份之间的约束,试图将基本的认证引入与诸如内容作者之类的角色相关联的信任语义中。信任是一个广泛而复杂的主题,信任机制容易受到极具创造性的攻击。除最基本的绑定外,"i=" 取值与其他身份之间的任何绑定的实际效力尚未得到充分确立,其遭受攻击者颠覆的脆弱性亦然。因此,对此类选项使用的依赖应受到严格限制。特别地,典型的最终用户收件人在多大程度上可以依赖成功使用 "i=" 选项可能作出的任何保证,这一点完全不清楚。

l= 消息体长度计数(纯文本无符号十进制整数;可选,默认为整个消息体)。该标签告知验证方电子邮件消息体在规范化之后、包含在密码学哈希中的八位组数量,从紧接在消息体之前的 CRLF 之后、从 0 开始计数。该值不得大于规范化后消息体中实际的八位组数量。进一步讨论见第 8.2 节。

资料性注释:"l=" 标签的取值被约束为 76 位十进制数字。该约束并非意图预测未来消息的大小,也不要求实现使用足以表示最大可能值的整数表示,而是意在提醒实现者在验证时检查该标签及所有其他标签的长度,并在解码该值时测试整数溢出。实现者可能需要将实际表达的值限制在小于 10^76 的值,例如,以使消息能够装入可用的存储空间。

ABNF:

sig-l-tag    = %x6c [FWS] "=" [FWS]
                1*76DIGIT

q= 用于检索公钥的查询方法列表(冒号分隔)(纯文本;可选,默认 "dns/txt")。每个查询方法的形式为 "type[/options]",其中 options 的语法和语义取决于 type 并取决于指定的选项。如果列出了多个查询机制,查询机制的选择不得改变签名的解释。实现必须按呈现顺序使用已识别的查询机制。无法识别的查询机制必须被忽略。

目前,唯一有效的值是 "dns/txt",它定义了本文档别处描述的 DNS TXT 资源记录(RR)查找算法。"dns" 查询类型定义的唯一选项是 "txt",它必须被包含。验证方和签名方必须支持 "dns/txt"。

ABNF:

sig-q-tag        = %x71 [FWS] "=" [FWS] sig-q-tag-method
                    *( [FWS] ":" [FWS] sig-q-tag-method )
sig-q-tag-method = "dns/txt" / x-sig-q-tag-type
                    ["/" x-sig-q-tag-args]
x-sig-q-tag-type = hyphenated-word  ; for future extension
x-sig-q-tag-args = qp-hdr-value

s= 细分 "d="(域)标签命名空间的选择器(纯文本;必需)。

国际化的选择器名称必须编码为 A-label,如 [RFC5890] 第 2.3 节所述。

ABNF:

sig-s-tag    = %x73 [FWS] "=" [FWS] selector

t= 签名时间戳(纯文本无符号十进制整数;推荐,默认未知创建时间)。该签名被创建的时间。格式是自 1970 年 1 月 1 日 00:00:00 UTC 时区以来的秒数。该值以十进制 ASCII 无符号整数表示。该值不受限于装入 31 位或 32 位整数。实现应准备好处理至少大到 10^12 的值(直到大约公元 200,000 年;这可装入 40 位)。为避免拒绝服务攻击,实现可以将任何长于 12 位的数值视为无限。闰秒不计入。实现可以忽略带有未来时间戳的签名。

ABNF:

sig-t-tag    = %x74 [FWS] "=" [FWS] 1*12DIGIT

x= 签名过期时间(纯文本无符号十进制整数;推荐,默认不过期)。格式与 "t=" 标签相同,表示为绝对日期,而非相对于签名时间戳的时间增量。该值以十进制 ASCII 无符号整数表示,对取值的约束与 "t=" 标签相同。如果验证方处的验证时间晚于过期日期,则该签名可被视为无效。验证时间应为消息首次在验证方管理域被接收的时间(若该时间可靠可得);否则应使用当前时间。"x=" 标签的取值(若两者都存在)必须大于 "t=" 标签的取值。

资料性注释:"x=" 标签并非用作抗重放防御。

资料性注释:由于时钟漂移,接收方关于何时认为签名过期的概念可能与发送方的预期不完全一致。接收方可以添加一个"容差因子"以允许此类可能的漂移。

ABNF:

sig-x-tag    = %x78 [FWS] "=" [FWS]
                1*12DIGIT

z= 被复制的头字段(dkim-quoted-printable,但见描述;可选,默认为空)。一个竖线分隔的、签名时存在的所选头字段列表,包含字段名和值。不要求包含签名时存在的所有头字段。该字段无需包含 "h=" 标签中列出的相同头字段。头字段文本本身必须对竖线("|",%x7C)字符进行编码(即 "z=" 文本中的竖线是元字符,复制头字段中任何实际的竖线字符必须被编码)。注意,所有空白字符都必须被编码,包括冒号与头字段值之间的空白。编码之后,可在任意位置加入 FWS 以避免出现过长的行;此类空白不是头字段值的一部分,解码前必须被移除。

"h=" 标签引用的头字段是指消息 [RFC5322] 头中的字段,而非 "z=" 标签中的任何复制字段。复制的头字段值用于诊断目的。

ABNF:

sig-z-tag      = %x7A [FWS] "=" [FWS] sig-z-tag-copy
                    *( "|" [FWS] sig-z-tag-copy )
sig-z-tag-copy = hdr-name [FWS] ":" qp-hdr-value

资料性示例:一个跨多行续行的签名头字段:

DKIM-Signature: v=1; a=rsa-sha256; d=example.net; s=brisbane;
   c=simple; q=dns/txt; i=@eng.example.net;
   t=1117574938; x=1118006938;
   h=from:to:subject:date;
   z=From:foo@eng.example.net|To:joe@example.com|
    Subject:demo=20run|Date:July=205,=202005=203:44:08=20PM=20-0700;
   bh=MTIzNDU2Nzg5MDEyMzQ1Njc4OTAxMjM0NTY3ODkwMTI=;
   b=dzdVyOfAKCdLXdJOc9G2q8LoXSlEniSbav+yuU4zGeeruD00lszZVoG4ZHRNiYzR

3.6. 密钥管理与表示

签名应用需要某种程度的保证,即用于验证的公钥与所声称的签名方相关联。许多应用通过使用受信任第三方颁发的公钥证书来实现这一点。然而,DKIM 只需让验证方查询所声称的签名方的 DNS 条目(或某种安全等价物)以检索公钥,即可在显著增强可扩展性的同时,达到足够的安全水平。

DKIM 密钥可能存储在多种类型的密钥服务器中,并以多种格式存储。密钥的存储与格式对 DKIM 算法的其余部分无关。

密钥查找算法的参数是查找的类型("q=" 标签)、签名方的域(DKIM-Signature 头字段的 "d=" 标签)以及选择器("s=" 标签)。

public_key = dkim_find_key(q_val, d_val, s_val)

本文档定义了一种绑定,使用 DNS TXT RR 来分发密钥。未来可能会定义其他绑定。

3.6.1. 文本表示

预计许多密钥服务器会选择以非结构化的文本格式呈现密钥(例如,XML 形式在此目的下不被视为非结构化文本)。对于以非结构化文本形式表示的任何 DKIM 密钥,必须使用下列定义。

整体语法是一个如第 3.2 节所述的 tag-list。当前有效的标签如下描述。其他标签可以存在,并且必须被不理解它们的任何实现忽略。

v= DKIM 密钥记录的版本(纯文本;推荐,默认 "DKIM1")。如果指定,该标签必须设置为 "DKIM1"(不带引号)。该标签必须是记录中的第一个标签。以任何其他值开头、带有 "v=" 标签的记录必须被丢弃。注意,验证方必须对该值进行字符串比较;例如,"DKIM1" 与 "DKIM1.0" 不同。

ABNF:

key-v-tag    = %x76 [FWS] "=" [FWS] %x44.4B.49.4D.31

h= 可接受的哈希算法(纯文本;可选,默认允许所有算法)。一个冒号分隔的可能使用的哈希算法列表。无法识别的算法必须被忽略。关于签名方与验证方实现的哈希算法的讨论见第 3.3 节。每条记录中该标签列出的算法集合是签名方做出的运营选择。

ABNF:

key-h-tag       = %x68 [FWS] "=" [FWS] key-h-tag-alg
                   *( [FWS] ":" [FWS] key-h-tag-alg )
key-h-tag-alg   = "sha1" / "sha256" / x-key-h-tag-alg
x-key-h-tag-alg = hyphenated-word   ; for future extension

k= 密钥类型(纯文本;可选,默认 "rsa")。签名方和验证方必须支持 "rsa" 密钥类型。"rsa" 密钥类型表示在 "p=" 标签中使用一个 ASN.1 DER 编码的 [ITU-X660-1997] RSAPublicKey(见 [RFC3447] 第 3.1 节和 A.1.1 节)(注意:"p=" 标签进一步使用 base64 算法对值进行编码)。无法识别的密钥类型必须被忽略。

ABNF:

key-k-tag        = %x76 [FWS] "=" [FWS] key-k-tag-type
key-k-tag-type   = "rsa" / x-key-k-tag-type
x-key-k-tag-type = hyphenated-word   ; for future extension

n= 可能令人类感兴趣的通知(qp-section;可选,默认为空)。任何程序都不对其作解释。该标签应谨慎使用于任何有空间限制(尤其是 DNS)的密钥服务器机制中。它供管理员而非终端用户使用。

ABNF:

key-n-tag    = %x6e [FWS] "=" [FWS] qp-section

p= 公钥数据(base64;必需)。空值意味着该公钥已被撤销。该标签取值在被 base64 编码之前的语法和语义由 "k=" 标签定义。

资料性理由:如果私钥已泄露或以其他方式被禁用(例如外包合同已终止),签名方可能希望明确声明它知晓该选择器,但所有使用该选择器的消息都应验证失败。验证方应为任何引用了被撤销密钥的 DKIM-Signature 头字段返回错误代码(详见第 6.1.2 节)。

ABNF:

key-p-tag    = %x70 [FWS] "=" [ [FWS] base64string]

资料性注释:base64string 允许在任意位置包含空白(FWS);但任何 CRLF 必须后跟至少一个 WSP 字符。实现者和管理员应注意确保选择器 TXT RR 符合本规范。

s= 服务类型(纯文本;可选;默认 "*")。一个冒号分隔的、该记录适用的服务类型列表。给定服务类型的验证方如果适当的类型未被列出,则必须忽略该记录。无法识别的服务类型必须被忽略。当前定义的服务类型如下:

该标签旨在约束密钥用于其他目的,以防将来其他服务定义了 DKIM 的使用。

ABNF:

key-s-tag        = %x73 [FWS] "=" [FWS] key-s-tag-type
                    *( [FWS] ":" [FWS] key-s-tag-type )
key-s-tag-type   = "email" / "*" / x-key-s-tag-type
x-key-s-tag-type = hyphenated-word   ; for future extension

t= 标志,表示为冒号分隔的名称列表(纯文本;可选,默认未设置任何标志)。无法识别的标志必须被忽略。定义的标志如下:

ABNF:

key-t-tag        = %x74 [FWS] "=" [FWS] key-t-tag-flag
                    *( [FWS] ":" [FWS] key-t-tag-flag )
key-t-tag-flag   = "y" / "s" / x-key-t-tag-flag
x-key-t-tag-flag = hyphenated-word   ; for future extension

3.6.2. DNS 绑定

hereby 定义使用 DNS TXT RR 作为密钥服务的绑定。所有实现必须支持该绑定。

3.6.2.1. 命名空间

所有 DKIM 密钥都存储在一个名为 "_domainkey" 的子域中。给定一个 "d=" 标签为 "example.com" 且 "s=" 标签为 "foo.bar" 的 DKIM-Signature 字段,DNS 查询将针对 "foo.bar._domainkey.example.com"。

3.6.2.2. 用于密钥存储的资源记录类型

所用的 DNS 资源记录类型由查询类型("q=")标签的一个选项指定。此基础规范中定义的唯一选项是 "txt",表示使用 TXT RR。本标准的后续扩展可能定义另一种 RR 类型。

TXT RR 中的字符串在使用前必须被连接在一起,中间不加任何插入的空白。对于给定的选择器名称,TXT RR 必须是唯一的;也就是说,如果 RRset 中有多条记录,则结果是未定义的。

TXT RR 按照第 3.6.1 节的描述进行编码。

3.7. 计算消息哈希

签名和验证消息签名都始于计算消息的两个密码学哈希这一步。签名方将如"签名方动作"(第 5 节)所述选择签名的参数;验证方将使用正在被验证的 DKIM-Signature 头字段中指定的参数。在下面的讨论中,使用了 DKIM-Signature 头字段中标签的名称,这些标签要么存在(验证时),要么将被创建(签名时)。注意,规范化(第 3.4 节)仅用于为签名或验证准备电子邮件;它不以任何方式影响被传输的电子邮件。

签名方/验证方必须计算两个哈希:一个针对消息体,一个针对消息的所选头字段。

签名方必须按所示顺序计算它们。验证方可以按对验证方方便的任何顺序计算它们,只要结果在语义上等同于按此顺序计算会得到的结果。

在哈希步骤 1 中,签名方/验证方必须哈希消息体,该消息体使用 "c=" 标签指定的消息体规范化算法进行规范化,然后截断为 "l=" 标签指定的长度。该哈希值随后被转换为 base64 形式,并插入(签名方)或与(验证方)DKIM-Signature 头字段的 "bh=" 标签进行比较。

在哈希步骤 2 中,签名方/验证方必须按指示的顺序将以下内容传递给哈希算法:

  1. 由 "h=" 标签指定的头字段,按该标签中指定的顺序,并使用 "c=" 标签指定的头字段规范化算法进行规范化。每个头字段必须以单个 CRLF 终止。
  2. 存在(验证时)或将插入(签名时)消息中的 DKIM-Signature 头字段,其中 "b=" 标签的取值(包括所有周围的空白)被删除(即,视为空字符串),使用 "c=" 标签指定的头字段规范化算法进行规范化,并且不带结尾的 CRLF。

DKIM-Signature 头字段中的所有标签及其值都包含在密码学哈希中,唯一的例外是 "b="(签名)标签的取值部分,该部分必须被视为空字符串。所有标签都必须被包含,即使验证方可能不理解它们。该头字段必须在消息体之后(而非与其他头字段一起)呈现给哈希算法,并且必须按照 "c="(规范化)标签指定的方式规范化。DKIM-Signature 头字段不得包含在其自身的 "h=" 标签中,但其他 DKIM-Signature 头字段可以被签名(见第 4 节)。

当对将使用 base64 或 quoted-printable 编码传输的消息计算哈希时,签名方必须在编码之后计算哈希。同样,验证方必须在解码 base64 或 quoted-printable 文本之前,将这些值纳入哈希。然而,哈希必须在传输级编码(如 SMTP 的"点填充"(dot-stuffing)——即修改以 "." 开头的行以避免与 SMTP 消息结束标记混淆,如 [RFC5321] 所规定)之前计算。

除第 3.4 节描述的规范化过程外,DKIM 签名过程将消息体视为简单的八位组字符串。DKIM 消息可以是纯文本或 MIME 格式;MIME 内容不享受特殊处理。MIME 格式的消息附件必须被包含在被签名的内容中。

更形式化地说,签名算法的伪代码如下:

body-hash    =  hash-alg (canon-body, l-param)
data-hash    =  hash-alg (h-headers, D-SIG, body-hash)
signature    =  sig-alg (d-domain, selector, data-hash)

其中:

注释:许多数字签名 API 使用单一的 "sign()" 原语同时提供哈希计算和 RSA 私钥的应用。使用此类 API 时,算法中的最后两步可能会合并为一次调用,同时执行 "a-hash-alg" 和 "sig-alg"。

3.8. 输入要求

不符合 [RFC5322]、[RFC2045] 和 [RFC2047] 的消息,可能会遭到中间方尝试纠正或解释此类内容的处理。见 [RFC4409] 第 8 节关于常见修改的示例。此类"纠正"可能使 DKIM 签名失效,或产生其他不良影响,包括涉及改变消息呈现给终端用户方式的那些。

因此,DKIM 的设计以有效输入为前提。因此,签名方和验证方应采取合理步骤,确保它们正在处理的消息根据 [RFC5322]、[RFC2045] 以及任何其他相关消息格式标准是有效的。

进一步讨论见第 8.15 节。

3.9. 输出要求

每个签名的评估以三种状态之一结束,本文档将其称为:

对于每个成功验证或产生 TEMPFAIL 结果的签名,DKIM 算法的输出必须包含以下集合:

输出可以包含其他签名属性或结果元数据,包括 PERMFAIL 或以其他方式被忽略的签名,供消费这些结果的模块使用。

关于签名验证结果代码的讨论见第 6.1 节。

3.10. 父域签名

在某些情形下,一个域期望代表其任何子域应用签名,而无需在每个子域中维护独立的选择器(密钥记录)。默认情况下,与密钥记录对应的私钥可用于对其所在域的任何子域的消息进行签名;例如,域 example.com 的密钥记录可用于验证 AUID(签名的 "i=" 标签)为 sub.example.com,甚至是 sub1.sub2.example.com 的消息。为了在不期望此类能力时限制这些密钥的能力,可以在密钥记录的 "t=" 标签中设置 "s" 标志,以约束 AUID 域的有效性。如果所引用的密钥记录在 "t=" 标签中包含 "s" 标志,则 AUID 的域("i=" 标志)必须与 SDID(d=)域相同。如果该标志缺失,则 AUID 的域必须与 SDID 相同或为其子域。

3.11. SDID 与 AUID 之间的关系

DKIM 的主要任务是从签名方向接收侧的身份评估者传达一个指代负有责任的身份的签名域标识符(SDID)。DKIM 可以选择性地提供一个单独的负有责任的代理或用户标识符(AUID)。

因此,DKIM 向接收侧身份评估者的强制性输出是一个单独的域名。在其作为 DKIM 输出使用的范围内,该名称只具有基本的域名语义;任何可能的属主特定语义都在 DKIM 的范围之外。也就是说,在其作为 DKIM 标识符的角色内,身份评估者不能假定额外的语义。

成功验证签名后,接收侧 DKIM 验证方必须将签名域标识符(d=)传达给消费型身份评估者模块,并且如果存在,可以传达代理或用户标识符(i=)。

若接收方试图为任一标识符推断任何结构化的语义,这是一个启发式功能,在 DKIM 的规范与语义范围之外。

因此,它被归为更高层的服务,例如一个整合多种输入并对其进行启发式分析的投递处理过滤器。

资料性讨论:本文档不要求 SDID 或 AUID 的取值与任何其他消息头字段中的标识符相匹配。该要求反而是一个评估者策略问题。此类关联的其目的是认证另一个头字段中的取值。这反过来又是基于标识符取值应用信任评估的基础。信任是一个广泛而复杂的主题,信任机制容易受到极具创造性的攻击。除最基本的绑定外,SDID 或 AUID 与其他身份之间的任何绑定的实际效力尚未得到充分确立,其遭受攻击者颠覆的脆弱性亦然。因此,对此类绑定的使用的依赖应受到严格限制。特别地,典型的最终用户收件人在多大程度上可以依赖成功使用 SDID 或 AUID 可能作出的任何保证,这一点完全不清楚。

4. 多重签名的语义

4.1. 示例场景

一条消息可能拥有多个签名的原因有很多。例如,假设未来发现 SHA-256 强度不足,而 DKIM 的使用过渡到 SHA-1024。签名方可能立即使用较新的算法签名,同时也继续使用较旧的算法签名,以便与尚未升级的验证方保持互操作。签名方会这样做:添加两个 DKIM-Signature 头字段,每个算法一个。不识别 SHA-1024 为可接受算法的较旧验证方会跳过该签名,而使用较旧的算法;较新的验证方可以任选一个签名使用,并且在其他条件相同的情况下,甚至可能不会尝试验证另一个签名。

类似地,签名方可能签署一条包含所有头字段且没有 "l=" 标签(以满足严格的验证方)的消息,并第二次使用一组受限的头字段和 "l=" 标签(预期消息在发往其他验证方的途中可能被修改)进行签名。验证方随后可以选择它们更偏好的签名。

当然,一条消息也可能因为经过了多个签名方而拥有多个签名。一个常见的情况预计是:一条已签名的消息经过一个也对所有消息进行签名的邮件列表。假设这两个签名都通过验证,收件人如果知道其中任一签名来自可信来源,就可能选择接受该消息。

特别地,收件人可能选择将其已订阅且具备可接受的反滥用策略的邮件列表加入白名单,从而即使来自未知作者也接受发往该列表的消息。它们也可能订阅信任度较低的邮件列表(例如那些没有反滥用保护的),并愿意接受来自特定作者的所有消息,但坚持对其他消息进行额外的滥用扫描。

多重签名方的另一个相关示例是转发服务,例如通常与大学校友网站相关联的那些。例如,收件人可能在 members.example.org 拥有一个地址,该站点的反滥用保护效果略逊于收件人所期望的。这样的收件人可能有一些其消息将被绝对信任的特定作者,但通过了转发方审查的来自未知作者的消息只有中等信任度。

4.2. 解释

向消息添加签名的签名方只是使用 "h=" 选项的通常语义创建一个新的 DKIM-Signature 头。签名方可以使用第 5.4 节描述的签名追踪头字段的方法,对先前已存在的 DKIM-Signature 头字段进行签名。

注意,签名方应意识到,对 DKIM-Signature 头字段进行签名可能导致与那些不识别 DKIM-Signature 头字段为追踪头字段、并无意中对其重排、从而破坏此类签名的中间方之间的签名失败。因此,尽管合法,但不建议对已有的 DKIM-Signature 头字段进行签名。

资料性注释:如果签名了一个具有多个实例的头字段,那些头字段总是自底向上签名。因此,不可能只签名特定的 DKIM-Signature 头字段。例如,如果正在签名的消息已经包含三个 DKIM-Signature 头字段 A、B 和 C,则可以签名它们全部、仅 B 和 C,或仅 C,但不能仅 A、仅 B、仅 A 和 B,或仅 A 和 C。

签名方可以使用不同的参数添加多个 DKIM-Signature 头字段。例如,在过渡期内,签名方可能希望使用两种不同的哈希算法生成签名。

签名方不应移除其正在签名的消息中的任何 DKIM-Signature 头字段,即使它们知道这些签名无法被验证。

在评估具有多个签名的消息时,验证方应独立地、基于自身情况评估每个签名。例如,按策略选择不接受使用已弃用密码学算法的签名的验证方,会将该类签名视为无效。验证方可以按所选的任何顺序处理签名;例如,某些验证方可能选择在处理其他签名之前,先处理与消息头 From 字段对应的签名。关于签名选择的更多信息见第 6.1 节。

资料性实现注释:验证方试图将有效签名与无效签名关联起来以猜测签名为何失败的尝试是不明智的。特别地,验证方无法以通用方式确定一个无效签名曾经有效。

验证方应继续检查签名,直到某个签名成功验证到令验证方满意为止。为限制潜在的拒绝服务攻击,验证方可以限制其将尝试验证的签名总数。

如果验证方模块报告了评估产生 PERMFAIL 结果的签名,身份评估者应忽略那些签名(见第 6.1),如同它们不存在于消息中。

5. 签名方动作

下列步骤由签名方按顺序执行。

5.1. 确定邮件是否应由谁签名

签名方显然只能为它拥有私钥以及相应公钥和选择器信息的域签名电子邮件。然而,除了缺少私钥之外,还有许多其他原因可能导致签名方选择不对电子邮件签名。

资料性注释:签名方可以作为邮件系统中任何适当部分实现,包括 MUA、SUBMISSION 服务器或 MTA。无论在何处实现,签名方都应警惕对可能有问题的消息进行签名(并因此主张责任)。特别地,在受信任的封闭区域内,签名域可能根据本地策略从头字段推导;SUBMISSION 服务器可能只签名来自经过适当认证和授权的用户的消息。

资料性实现者建议:如果出站网关 MTA 混淆(obfuscate)Received 头字段(例如,隐藏内部拓扑的细节),SUBMISSION 服务器不应签名 Received 头字段。

如果由于某种原因无法对电子邮件签名,对该电子邮件如何处理是一个本地策略决策。

5.2. 选择私钥及相应的选择器信息

本规范未定义签名方应选择哪个私钥和选择器信息的依据。目前,就本规范而言所有选择器都是平等的,因此该决策在很大程度上应是一个管理便利性的问题。私钥的分发与管理也在本规范范围之外。

资料性运营建议:当包含相应公钥的选择器预计在验证方有机会验证签名之前被撤销或移除时,签名方不应使用该私钥签名。签名方应预见到验证方可以选择推迟验证,也许直到消息被最终收件人实际读取。特别地,在轮换到新的密钥对时,应立即开始使用新私钥签名,并且旧的公钥应在从密钥服务器移除之前保留一段合理的验证间隔。

5.3. 规范化消息以防止传输转换

某些消息,特别是那些使用 8 位字符的消息,在传输过程中会被修改,尤其是转换为 7 位形式。此类转换会破坏 DKIM 签名。为了尽量减少此类破坏的可能性,签名方应在签名之前,将消息转换为合适的 MIME 内容传输编码,如 [RFC2045] 所述的 quoted-printable 或 base64。此类转换在 DKIM 范围之外;实际的消息应由 MUA 或 MSA 在呈现给 DKIM 算法之前转换为 7 位 MIME。

如果消息以任何会在传输前被修改的本地编码提交给签名方,则该到规范 [RFC5322] 形式的修改必须在签名之前完成。特别地,裸 CR 或 LF 字符(某些系统用作本地行分隔约定)必须在消息被签名之前转换为 SMTP 标准的 CRLF 序列。任何此类转换应应用于实际发送给收件人(们)的消息,而不仅仅是呈现给签名算法的版本。

更一般地,签名方必须按预期被验证方接收的形式(而非某种本地或内部形式)对消息签名。

5.3.1. 消息体长度限制

可以指定一个消息体长度计数,以将签名计算限制在消息体文本的初始前缀,以八位组计量。如果未指定消息体长度计数,则对整条消息体进行签名。

资料性理由:提供此能力是因为邮件列表向消息添加尾部内容(例如,如何退订的说明)非常常见。在那些消息也被签名之前,消息体长度计数对验证方是一个有用的工具,因为它可以按策略接受带有有效签名但带有额外数据的消息。

实际被哈希的长度应插入到 DKIM-Signature 头字段的 "l=" 标签中(见第 3.5 节)。

消息体长度计数允许已签名消息的签名方允许数据被追加到已签名消息体的末尾。消息体长度计数必须遵循规范化算法计算;例如,任何被规范化算法忽略的空白都不作为消息体长度计数的一部分。

消息体长度计数为零意味着消息体完全未被签名。

希望确保不发生任何类型修改的签名方,应为头字段和消息体都指定 "simple" 规范化算法,并省略消息体长度计数。

进一步讨论见第 8.2 节。

5.4. 确定要签名的头字段

From 头字段必须被签名(即,包含在所得 DKIM-Signature 头字段的 "h=" 标签中)。签名方不应签名可能在传输中被合法修改或移除的已有头字段。特别地,[RFC5321] 明确允许在传输中修改或移除 Return-Path 头字段。签名方可以自行决定包含签名时存在的任何其他头字段。

资料性运营注释:选择哪些头字段进行签名并非显而易见。一种策略是签名所有已有的、不可重复的(non-repeatable)头字段。另一种策略是仅签名那些可能显示给接收方或以其他方式可能影响消息在接收方处理的头字段。第三种策略是仅签名"众所周知的"头。注意,验证方可能以极度怀疑的态度对待未签名的头字段,包括拒绝向终端用户显示它们,甚至在签名未覆盖某些头字段时忽略该签名。因此,强烈建议对消息中存在的字段(如 Date、Subject、Reply-To、Sender 以及所有 MIME 头字段)进行签名。

DKIM-Signature 头字段总是被隐式签名,并且不得包含在 "h=" 标签中,除非是为了表明其他已有的签名也被签名。

签名方可以声称已对不存在的头字段进行了签名(即,签名方可以在 "h=" 标签中包含该头字段名称,即使该头字段在消息中不存在)。在计算签名时,不存在的头字段必须被视为空字符串(包括头字段名称、头字段值、所有标点以及结尾的 CRLF)。

资料性理由:这允许签名方显式地主张某个头字段的缺失;如果该头字段后来被添加,签名将失败。

资料性注释:一个头字段名称只需要在签名时比消息中该头字段的实际数量多列出一次,即可防止任何进一步的添加。例如,如果签名时存在单个 Comments 头字段,在 "h=" 标签中列出 Comments 两次就足以防止追加任意数量的 Comments 头字段;在 "h=" 标签中列出三次或更多次是不必要(但合法)的。

关于对一个具有多个特定头字段名称实例的头进行规范化时应遵循的步骤,见第 5.4.2 节。

签名方需要小心那些可能在投递过程中被添加额外实例的头字段,因为此类头字段可能被插入到已签名实例之后,或以其他方式被重排。追踪头字段(如 Received)和 Resent-* 块是唯一被 [RFC5322] 禁止重排的字段。特别地,由于某些中间 MTA 可能重排 DKIM-Signature 头字段,对已有的 DKIM-Signature 头字段签名容易出错。

资料性告诫:尽管 [RFC5322] 不禁止重排头字段,但中间 MTA 对具有多个实例的已签名头字段进行重排将导致 DKIM 签名被破坏;应避免此类反社会行为。

资料性实现者注释:尽管本规范不要求,但所有终端用户可见的头字段都应被签名,以避免可能的"间接垃圾邮件"。例如,如果 Subject 头字段未被签名,垃圾邮件发送者可以重发一封先前已签名的邮件,将合法的标题替换为单行的垃圾邮件。

5.4.1. 推荐的签名内容

DKIM 密码学算法的目的是以一种既对正常的传输相关变更具有鲁棒性、又能抵抗各类重放攻击的方式,将一个标识符附着到消息上。满足这些要求的一个关键方面是选择将哪些头字段纳入哈希、排除哪些字段。

选择要包含的字段的基本规则是:选择那些构成消息内容"核心"的字段。因此,任何重放攻击都必须包含这些字段才能使签名成功;然而,有了这些字段,消息的核心就是有效的,即使它被转发给新的收件人。

带有地址的字段以及与消息体相关的文本内容的字段的常见示例如下:

如果使用 "l=" 签名标签(见第 3.5 节),Content-Type 字段也是一个被包含候选,因为它可能被替换,导致向接收用户呈现完全不同的内容。

对于什么构成消息"核心"的决策存在权衡,对某些字段而言这是一个主观概念。例如,包含诸如 "Message-ID" 之类的字段是有用的,如果你认为能够区分同一消息的不同实例的机制是核心内容的话。类似地,如果认为消息线程是消息的核心部分,那么 "In-Reply-To" 和 "References" 可能值得包含。

另一类可能令人感兴趣的字段是那些传达关于消息的安全相关信息的字段,例如 Authentication-Results [RFC5451]。

选择要排除的字段的基本规则是:选择那些具有同名多个字段、以及在传输中被修改的字段。这些字段的示例如下:

注意,DKIM-Signature 字段也被排除在头哈希之外,因为它的处理是单独规定的。

通常,最好排除其他可选字段,因为有相同名称的额外字段可能在验证前被合法地添加或重排。由于可能应用于消息的、种类繁多的应用特定头字段,其中一些不太可能被复制、修改或重排,这条规则可能会有合理的例外。

签名方应根据它们处理的消息类型及其对风险的厌恶程度选择规范化算法。例如,主要发送购买收据(预计不会被邮件列表或其他可能修改消息的软件处理)的电子商务站点,通常会偏好 "simple" 规范化。

主要发送人对人电子邮件的站点,可能会更倾向于通过使用 "relaxed" 规范化来对传输中的修改更具弹性。

除非邮件经过中间方(如可能向消息体底部添加"退订"说明的邮件列表)处理,否则 "l=" 标签可能不会带来额外好处,反而提供了向消息中未经授权地添加文本的渠道。使用 "l=0" 将这一点推向极端,允许在不使签名失效的情况下完全更改消息文本。此外,验证方有权将部分签名的消息体视为不可接受。建议审慎使用。

5.4.2. 涉及字段多个实例的签名

选择对消息中出现多次(如 Received)的已有头字段进行签名的签名方,必须对该头字段块中物理上最后一个实例进行签名。希望对此类头字段的多个实例进行签名的签名方,必须在 DKIM-Signature 头字段的 "h=" 标签中包含该头字段名称多次,并且必须从头字段块的底部到顶部按顺序对这些头字段进行签名。签名方可以在 "h=" 中包含比实际相应头字段更多的头字段名称实例,以便如果添加了该名称的额外头字段,签名将无法验证。

资料性示例:

如果签名方希望签名两个已有的 Received 头字段,并且已有的头包含:

Received: <A>
Received: <B>
Received: <C>

那么所得的 DKIM-Signature 头字段应为:

DKIM-Signature: ... h=Received : Received :...

并且 Received 头字段 <C> 和 <B> 将按该顺序被签名。

5.5. 计算消息哈希与签名

签名方必须按照第 3.7 节的描述计算消息哈希,然后使用所选的公钥算法对其进行签名。这将产生一个 DKIM-Signature 头字段,其中包含消息体哈希和头哈希的签名,其中该头包含 DKIM-Signature 头字段本身。

诸如邮件列表管理器等实现 DKIM 并在重传消息之前修改消息或某个头字段(例如,插入退订信息)的实体,应检查输入上的任何已有签名,并且必须在对消息重新签名之前进行此类修改。

5.6. 插入 DKIM-Signature 头字段

最后,签名方必须在传输电子邮件之前,插入在上一步创建的 DKIM-Signature 头字段。DKIM-Signature 头字段必须与上述用于计算哈希的相同,除了 "b=" 标签的取值必须是上一步使用 "a=" 标签指定的算法、并使用与 DKIM-Signature 头字段 "s=" 标签给定的选择器相对应的私钥计算出的适当签名的哈希。

DKIM-Signature 头字段必须插入在头字段块中任何其他 DKIM-Signature 字段之前。

资料性实现注释:实现这一目标最简单的方法是将 DKIM-Signature 头字段插入到头字段块的开头。特别地,它可以放在任何已有的 Received 头字段之前。这与将 DKIM-Signature 视为追踪头字段的做法一致。

6. 验证方动作

由于签名方可能随时移除或撤销公钥,建议验证及时进行。在许多配置中,最及时的场所是在边界 MTA 接收期间或之后不久。特别地,不建议将验证推迟到消息被终端用户访问时。

边界或中间 MTA 可以验证消息签名。已执行验证的 MTA 可以通过向传入消息添加验证头字段来传达该验证的结果。这为用户简化了事情,用户现在可以使用已有的邮件用户代理。大多数 MUA 具有基于消息头字段或内容过滤消息的能力;这些过滤器将用于实作用户关于未签名邮件的任何策略。

进行验证的 MTA 可以就不可验证邮件实作策略,无论它是否对签名的消息应用验证头字段。

验证方必须产生一个在语义上等同于按第 6.1、6.1.1 和 6.1.2 节顺序应用这些步骤的结果。在实践中,其中若干步骤可以并行执行以提高性能。

6.1. 从消息中提取签名

验证方尝试 DKIM-Signature 头字段的顺序未作定义;验证方可以按任意喜欢的顺序尝试签名。例如,一个实现可能按文本顺序尝试签名,而另一个可能先尝试与 From 头字段内容匹配身份的签名,再尝试其他签名。验证方不得对多个 DKIM-Signature 头字段的顺序赋予最终意义。特别地,有理由相信某些中继会以潜在任意的方式重排头字段。

资料性实现注释:在没有其他信息的情况下,验证方可能使用顺序作为签名顺序的线索。然而,关于多重签名的语义的其他线索(如将签名主机与 Received 头字段关联)也可能被考虑。

签名在传输后的存活无法保证,并且签名可能由于非签名方过错的原因而验证失败。因此,验证方不应将带有一个或多个坏签名且没有好签名的消息,与完全没有签名的消息区别对待。

当签名成功验证时,验证方将停止处理或尝试验证任何其他签名,由实现自行决定。为避免拒绝服务攻击,验证方可以限制其尝试的签名数量(进一步讨论见第 8.4 节)。

在下面的描述中,文本"返回 状态(解释)"(其中"状态"为 "PERMFAIL" 或 "TEMPFAIL" 之一)意味着验证方必须立即停止处理该签名。验证方应继续下一个签名(如果存在),并完全忽略该坏签名。如果状态为 "PERMFAIL",则该签名失败且不应被重新考虑。如果状态为 "TEMPFAIL",则该签名此时无法验证,但稍后可重试。验证方可以安排推迟消息以便稍后处理,或尝试另一个签名;如果未找到好签名且任何签名产生了 TEMPFAIL 状态,验证方可以安排推迟消息以便稍后处理。"(解释)"不是规范性文本;它仅用于澄清。

准备好验证多个签名头字段的验证方,如果存在,应继续下一个签名头字段。然而,验证方可以记下存在无效签名这一事实,供后续步骤考虑。

资料性注释:该要求的基本原理是允许带有无效签名但同时也有有效签名的消息正常工作。例如,邮件列表分发器可能选择保留原始提交者签名,即使它知道自己正在以某种会破坏该签名的方式修改消息,并且分发器插入自己的签名。在这种情况下,即使存在已知的被破坏签名,消息也应成功。

对于每个要验证的签名,应以下列方式执行这些步骤,以产生在语义上等同于按指示顺序执行的结果。

6.1.1. 验证签名头字段

实现者必须细致地验证 DKIM-Signature 头字段中的格式和取值;任何不一致或意外的取值必须导致该头字段被完全忽略,并且验证方返回 PERMFAIL(签名语法错误)。在这种安全语境中,"对你所接受的持宽松态度"绝对是一个糟糕的策略。但是,注意这不包括 DKIM-Signature 头字段中存在未知标签,那是明确允许的。当遇到 "v=" 标签与本规范不一致的 DKIM-Signature 头字段时,验证方必须返回 PERMFAIL(不兼容的版本)。

资料性实现注释:当然,实现可以选择验证由本规范旧版本生成的签名。

如果第 3.5 节列为"必需"的任何标签从 DKIM-Signature 头字段中省略,验证方必须忽略该 DKIM-Signature 头字段并返回 PERMFAIL(签名缺少必需标签)。

资料性注释:第 3.5 节列为必需的标签是 "v="、"a="、"b="、"bh="、"d="、"h=" 和 "s="。如果本注释与第 3.5 节之间存在冲突,以第 3.5 节为准。

如果 DKIM-Signature 头字段不包含 "i=" 标签,验证方必须表现得如同该标签的取值为 "@d",其中 "d" 是 "d=" 标签的取值。

验证方必须确认 "d=" 标签指定的域与 "i=" 标签域部分的相同或父域。如果不是,则必须忽略 DKIM-Signature 头字段,并且验证方应返回 PERMFAIL(域不匹配)。

如果 "h=" 标签未包含 From 头字段,验证方必须忽略 DKIM-Signature 头字段并返回 PERMFAIL(From 字段未被签名)。

如果 DKIM-Signature 头字段包含 "x=" 标签且签名已过期,验证方可以忽略该 DKIM-Signature 头字段并返回 PERMFAIL(签名已过期)。

如果签名方在 "d=" 标签中使用的域不与有效的签名实体相关联,验证方可以忽略 DKIM-Signature 头字段。例如,带有 "com" 和 "co.uk" 等 "d=" 取值的签名可以被忽略。不可接受的域列表应可配置。

出于任何其他原因,验证方可以忽略 DKIM-Signature 头字段并返回 PERMFAIL(不可接受的签名头),例如,如果签名未对验证方视为必要的头字段进行签名。作为一个实例,如果 MIME 头字段未被签名,某些攻击可能发生,而验证方希望避免这些攻击。

6.1.2. 获取公钥

完成验证过程需要签名对应的公钥。检索公钥的过程取决于 DKIM-Signature 头字段中 "q=" 标签定义的查询类型。显然,只有在成功提取签名信息的过程完成之后,才需要检索公钥。

密钥管理与表示的细节在第 3.6 节描述。验证方必须验证密钥记录,并且必须忽略任何格式错误的公钥记录。

注释:使用覆盖被查询 DKIM 域名的通配符 TXT RR 会产生一个不太可能是有效 DKIM 密钥记录的 DKIM 查询响应。这个问题并非 DKIM 特有,也适用于许多其他类型的查询。处理 DNS 响应的客户端软件需要考虑到这个问题。

验证消息时,验证方必须以在语义上等同于按指示顺序执行这些步骤的方式执行下列步骤;在某些情况下,只要语义保持不变,实现可以并行化或重排这些步骤:

  1. 验证方使用 "q=" 标签中的算法、"d=" 标签中的域和 "s=" 标签中的选择器,按照第 3.6 节的描述检索公钥。
  2. 如果检索公钥的查询未响应,验证方可以通过返回 TEMPFAIL(密钥不可用)来寻求稍后的验证尝试。
  3. 如果检索公钥的查询因相应的密钥记录不存在而失败,验证方必须立即返回 PERMFAIL(签名无密钥)。
  4. 如果检索公钥的查询返回多个密钥记录,验证方可以选择其中一个密钥记录,或可以遍历密钥记录,对每条记录执行这些步骤的其余部分,由实现者自行决定。密钥记录的顺序未指定。如果验证方选择遍历密钥记录,则本节其余部分中"返回……"的措辞意味着"尝试下一个密钥记录(如果有);如果没有,则返回以通常方式尝试另一个签名"。
  5. 如果查询返回的结果不符合本规范定义的格式,验证方必须忽略该密钥记录并返回 PERMFAIL(密钥语法错误)。敦促验证方仔细验证密钥记录的语法,以避免遭受攻击。特别地,验证方必须忽略带有它们未实现的版本代码("v=" 标签)的密钥。
  6. 如果公钥记录中存在 "h=" 标签,并且 DKIM-Signature 头字段 "a=" 标签隐含的哈希算法未被包含在 "h=" 标签的内容中,验证方必须忽略该密钥记录并返回 PERMFAIL(不适当的哈希算法)。
  7. 如果公钥数据("p=" 标签)为空,则该密钥已被撤销,验证方必须将其视为失败的签名检查并返回 PERMFAIL(密钥已撤销)。被撤销的密钥与已移除的密钥记录之间没有定义上的语义差异。
  8. 如果公钥数据不适合与 DKIM-Signature 头字段 "a=" 和 "k=" 标签定义的算法和密钥类型一起使用,验证方必须立即返回 PERMFAIL(不适当的密钥算法)。

6.1.3. 计算验证

给定一个签名方和一个公钥,验证签名由在语义上等同于下列步骤的动作组成:

  1. 基于 "c=" 标签定义的算法、"l=" 标签指定的消息体长度,以及 "h=" 标签中的头字段名称,按照第 3.7 节的描述准备消息的规范化版本(注意,此规范化版本实际上并不替换原始内容)。将 "h=" 标签中的头字段名称与实际的消息头字段匹配时,比较必须大小写不敏感。
  2. 基于 "a=" 标签指示的算法,按照第 3.7 节的描述从规范化副本计算消息哈希。
  3. 验证上一步计算的规范化消息体哈希与 "bh=" 标签传达的哈希值匹配。如果哈希不匹配,验证方应忽略该签名并返回 PERMFAIL(消息体哈希未验证)。
  4. 使用 "b=" 标签传达的签名,针对头哈希、使用适合 "a=" 标签指定的公钥算法的机制验证签名。如果签名未通过验证,验证方应忽略该签名并返回 PERMFAIL(签名未验证)。
  5. 否则,签名已正确验证。

资料性实现者注释:实现可能希望在计算哈希的同时并行发起公钥查询,因为公钥直到最终解密计算时才需要。实现也可以在验证 DKIM-Signature 头字段 "bh=" 标签中列出的消息哈希与实际消息体匹配之前,先验证消息头上的签名;但是,如果消息体哈希不匹配,则整个签名必须被视为失败。

签名 "l=" 标签中指定的消息体长度限制传入验证算法的字节数。超出该限制的所有数据都不被 DKIM 验证。因此,验证方可能以怀疑的态度对待包含超出指示消息体长度的字节的消息,并可以选择将该签名视为无效(例如,通过返回 PERMFAIL(未签名内容))。

如果算法到达这一点,验证已成功,DKIM 为该签名报告 SUCCESS。

6.2. 传达验证结果

希望将验证结果传达给邮件系统其他部分的验证方,可以以它们认为合适的任何方式进行。例如,实现可能选择在传递消息之前向消息添加一个电子邮件头字段。任何此类头字段应插入在头字段块中任何已有的 DKIM-Signature 或已有的认证状态头字段之前。Authentication-Results: 头字段([RFC5451])可用于此目的。

面向 MUA 过滤器作者的资料性建议:旨在搜索结果头字段以为终端用户可见地标记已认证邮件的模式,应验证此类头字段是由适当的验证域添加的,并且被验证的身份与 MUA 将显示的作者身份匹配。特别地,MUA 过滤器不应受攻击者添加的伪造结果头字段的影响。为规避此攻击,验证方可能希望在验证之后、在安排添加新头字段之前,请求删除已有的结果头字段。

6.3. 解释结果/应用本地策略

描述身份评估者可以采取什么动作超出了本规范的范围,但携带已验证 SDID 的邮件为身份评估者提供了一个未经认证的邮件所没有的机会。具体而言,已认证的邮件创建了一个可预测的标识符,可以可靠地据此管理其他决策,如信任与声誉。相反,未经认证的邮件缺乏可用于分配信任和声誉的可靠标识符。将未经认证的邮件视为缺乏任何信任且不具有正面声誉是合理的。

一般而言,消费 DKIM 验证输出的模块不应仅基于缺少任何签名或基于不可验证的签名来决定消息的可接受性;此类拒收会导致严重的互操作性问题。如果 MTA 确实希望在 SMTP 会话期间拒收此类消息(例如,在与已预先约定只发送签名消息的对等方通信时),并且签名缺失或无法验证,处理中的 MTA 应使用 550/5.7.x 回复码。

在验证方集成于 MTA 内部且无法获取公钥的情况下(也许是因为密钥服务器不可用),可以使用 451/4.7.5 回复码生成临时失败消息,例如:

451 4.7.5 Unable to verify signature - key server unavailable

诸如无法访问密钥服务器或其他外部服务的临时失败,是唯一应使用 4xx SMTP 回复码的情况。特别地,密码学签名验证失败不得引发 4xx SMTP 回复。

一旦签名被验证,该信息必须传达给身份评估者(如显式的允许/白名单和声誉系统)和/或终端用户。如果 SDID 与 From: 头字段中的地址不同,邮件系统应尽力确保实际的 SDID 对读者清晰。

虽然验证失败的症状显而易见——签名未通过验证——但确定确切原因可能更困难。如果找不到选择器,是因为选择器已被移除,还是其值在传输中某处被更改?如果签名行缺失,是因为它从未存在,还是被过于热心的过滤器移除了?出于诊断目的,验证失败的准确原因应可得知,并可能记录在系统日志中。

如果电子邮件无法被验证,那么它应被视为与所有未验证的电子邮件相同,无论它看起来是否像被签名。

进一步讨论见第 8.15 节。

7. IANA 考量

DKIM 已在 IANA 注册了命名空间。在所有情况下,新值仅分配给那些在具有 IETF 共识 [RFC5226] 的已出版 RFC 中予以记载的取值。

本备忘录按如下所述更新了这些注册表。值得注意的是新增了一个 "status(状态)" 列。所有注册到这些命名空间的内容必须包含被注册的名称、注册或更新它的文档,以及其当前状态的指示,状态必须是 "active(在使用中)" 或 "historic(不再使用中)" 之一。

与 [RFC4871] 相比,本规范未定义新的标签,但有一个被指定为 "historic(历史)"。

此外,"Email Authentication Methods(电子邮件认证方法)"注册表被修订以引用本更新。

7.1. 电子邮件认证方法注册表

"Email Authentication Methods" 注册表被更新,以表明 "dkim" 定义于本备忘录。

7.2. DKIM-Signature 标签规范

DKIM-Signature 提供了一组标签规范列表。IANA 已建立 "DKIM-Signature Tag Specifications" 注册表,用于可在 DKIM-Signature 字段中使用的标签规范。

表 1:DKIM-Signature 标签规范注册表更新值
TYPEREFERENCESTATUS
v(本文档)active
a(本文档)active
b(本文档)active
bh(本文档)active
c(本文档)active
d(本文档)active
h(本文档)active
i(本文档)active
l(本文档)active
q(本文档)active
s(本文档)active
t(本文档)active
x(本文档)active
z(本文档)active

7.3. DKIM-Signature 查询方法注册表

"q=" 标签规范(在第 3.5 节规定)提供了一组查询方法列表。

IANA 已建立 "DKIM-Signature Query Method" 注册表,用于可用来检索允许对使用 DKIM 签名的消息进行验证处理的密钥的机制。

表 2:DKIM-Signature 查询方法注册表更新值
TYPEOPTIONREFERENCESTATUS
dnstxt(本文档)active

7.4. DKIM-Signature 规范化注册表

"c=" 标签规范(在第 3.5 节规定)提供了消息头字段和消息体规范化算法的说明符。

IANA 已建立 "DKIM-Signature Canonicalization Header" 注册表,用于在对消息进行签名或验证之前将其转换为规范化形式的算法。

表 3:DKIM-Signature 规范化头字段注册表更新值
TYPEREFERENCESTATUS
simple(本文档)active
relaxed(本文档)active
表 4:DKIM-Signature 规范化消息体注册表更新值
TYPEREFERENCESTATUS
simple(本文档)active
relaxed(本文档)active

7.5. _domainkey DNS TXT 资源记录标签规范

_domainkey DNS TXT RR 提供了一组标签规范列表。IANA 已建立 DKIM "_domainkey DNS TXT Record Tag Specifications" 注册表,用于可在 DNS TXT 资源记录中使用的标签规范。

表 5:_domainkey DNS TXT 记录标签规范注册表更新值
TYPEREFERENCESTATUS
v(本文档)active
g[RFC4871]historic
h(本文档)active
k(本文档)active
n(本文档)active
p(本文档)active
s(本文档)active
t(本文档)active

7.6. DKIM 密钥类型注册表

"k=" <key-k-tag>(在第 3.6.1 节规定)和 "a=" <sig-a-tag-k>(在第 3.5 节规定)标签提供了一组可用于解码 DKIM 签名的机制列表。

IANA 已为这类机制建立 "DKIM Key Type" 注册表。

表 6:DKIM 密钥类型注册表更新值
TYPEREFERENCESTATUS
rsa[RFC3447]active

7.7. DKIM 哈希算法注册表

"h=" <key-h-tag>(在第 3.6.1 节规定)和 "a=" <sig-a-tag-h>(在第 3.5 节规定)标签提供了一组可用于生成消息数据摘要的机制列表。

IANA 已为这类机制建立 "DKIM Hash Algorithms" 注册表。

表 7:DKIM 哈希算法注册表更新值
TYPEREFERENCESTATUS
sha1[FIPS-180-3-2008]active
sha256[FIPS-180-3-2008]active

7.8. DKIM 服务类型注册表

"s=" <key-s-tag> 标签(在第 3.6.1 节规定)提供了一组该选择器可能适用的服务类型列表。

IANA 已为服务类型建立 "DKIM Service Types" 注册表。

表 8:DKIM 服务类型注册表更新值
TYPEREFERENCESTATUS
email(本文档)active
*(本文档)active

7.9. DKIM 选择器标志注册表

"t=" <key-t-tag> 标签(在第 3.6.1 节规定)提供了一组用于修改选择器解释的标志列表。

IANA 已为额外的标志建立 "DKIM Selector Flags" 注册表。

表 9:DKIM 选择器标志注册表更新值
TYPEREFERENCESTATUS
y(本文档)active
s(本文档)active

7.10. DKIM-Signature 头字段

IANA 已将 DKIM-Signature 添加到 "Permanent Message Header Field Names" 注册表(见 [RFC3864])中,用于 "mail" 协议,以本文档作为参考。

8. 安全考量

据观察,任何试图遏制垃圾邮件流动的引入机制都会遭受密集攻击。DKIM 需要被仔细审查,以识别潜在的攻击向量以及各自面临的脆弱性。另见 [RFC4686]。

8.1. ASCII 艺术攻击

relaxed 消息体规范化算法可能促成某些极其粗糙的"ASCII 艺术"攻击,即通过调整词间间距来传达一条消息。如果这是一个顾虑,应改用 "simple" 消息体规范化算法。

8.2. 滥用消息体长度限制("l=" 标签)

使用 "l=" 标签可能在不向终端用户给出适当警告的情况下显示欺诈性内容。"l=" 标签旨在向既修改其内容又不对其修改后的消息签名的邮件列表发送时,提高签名的鲁棒性。然而,使用 "l=" 标签会使得怀有恶意的中间方能够修改消息,以包含仅有利于攻击者的内容。被追加的内容有可能在最终收件人眼中完全替换原始内容,并破坏重复消息检测算法。

此类攻击的一个示例包括更改 MIME 结构、利用 MUA 中宽松的 HTML 解析,以及破坏重复消息检测算法。

为避免此类攻击,签名方应极其谨慎地使用此标签,评估者可能希望忽略使用该标签的签名。

8.3. 被挪用的私钥

与任何其他使用公私钥对的安全应用一样,DKIM 需要对密钥的处理和保护保持谨慎。被泄露的私钥或对其的访问,意味着入侵者或恶意软件可以发送由公布匹配公钥的域签名的邮件。

因此,发放给用户而非 ADMD 自身使用的私钥,会带来通常的、保护可能影响 ADMD 的个人资源上所存储数据的问题。

一种更安全的架构是:通过出站 MTA 发送消息,该 MTA 可以使用现有技术(如 SMTP 认证)认证提交者,可能验证消息本身(例如,验证头是否合法且内容通过垃圾邮件内容检查),并使用适合提交者地址的密钥对消息签名。此类 MTA 还可以对每个用户被允许发起的出站邮件量施加控制,以进一步限制恶意软件生成批量邮件的能力。

8.4. 密钥服务器拒绝服务攻击

由于密钥服务器是分布式的(对每个域可能各自独立),要在整个互联网范围内击败该机制,需要攻击的服务器数量非常庞大。然而,单个域的密钥服务器可能受到攻击,阻碍来自该域的消息的验证。这与攻击者拒绝向给定域的邮件交换器提供服务的能力并无显著不同,尽管它影响的是出站邮件而非入站邮件。

该攻击的一种变体涉及使用来自给定域的伪造签名发送极大量的邮件:该域的密钥服务器可能在拒绝服务攻击中被请求淹没(见 [RFC4732])。然而,鉴于验证相对于处理电子邮件消息本身的开销很低,此类攻击难以发动。

8.5. 针对 DNS 的攻击

由于 DNS 是密钥服务所必需的绑定,必须考虑针对 DNS 的具体攻击。

虽然 DNS 当前是不安全的 [RFC3833],但这些安全问题正是 DNS 安全(DNSSEC)[RFC4033] 的动因,所有 DNS 用户都将从该工作中受益。

DKIM 仅旨在作为证明真实性的"充分"方法。它不旨在就作者身份或内容提供强密码学证明。OpenPGP [RFC4880] 和 S/MIME [RFC5751] 等其他技术处理那些需求。

与 DNS 相关的第二个安全问题围绕由于获取基于选择器的数据以及获取签名域策略而导致的 DNS 流量增加。DKIM 的广泛部署将导致对所称签名域的 DNS 查询显著增加。在大规模伪造的情况下,DNS 服务器可能看到查询的大幅增加。

DKIM 验证方应考虑的一个具体 DNS 安全问题是 [RFC3833] 第 2.3 节描述的名称链接(name chaining)攻击。DKIM 验证方在验证 DKIM-Signature 头字段时,可能被提示检索攻击者选择的密钥记录。通过确保验证方使用的名称服务器(包括递归名称服务器)对 DNS 响应中的"glue(粘附)"和其他附加信息执行严格检查,从而不易受此攻击,可以将此威胁降到最低。

8.6. 重放/垃圾邮件攻击

在此攻击中,垃圾邮件发送者通过对其签名的 MTA 发送一条垃圾邮件,押注签名域(例如,一个大型流行邮箱提供商)而非其自身的声誉,然后将该消息重发给大量预期收件人。收件人观察到来自知名域的有效签名,从而提升他们对消息的信任,并增加投递和呈现给用户的可能性。

该问题的部分解决方案涉及使用声誉服务来传达特定电子邮件地址正被用于垃圾邮件、并且来自该签名方的消息很可能是垃圾邮件这一事实。这需要一种实时检测机制,以便足够快地做出反应。然而,如果攻击者重发从受害者处收到的大量消息以使受害者看起来像垃圾邮件发送者,此类措施可能容易被滥用。

大型验证方可能能够检测在短时间内具有相同签名的异常大量邮件。较小的验证方可以通过现有的协作系统获得基本相同的数量信息。

8.7. 撤销密钥的局限

当大型域检测到其某个用户的不当行为时,它可能希望撤销用于签名该用户消息的密钥,以否认对尚未验证或正遭受重放攻击的消息的责任。然而,如果该密钥出于可扩展性原因被用于为许多其他用户签名消息,域这样做的能力会受到限制。针对每地址显式撤销密钥的机制已被提出,但就其效用及所代表的 DNS 负载而言,还需要进一步研究。

8.8. 故意构造的畸形密钥记录

攻击者可能在 DNS 中发布故意构造畸形的密钥记录,意图对不够健壮的验证方实现发起拒绝服务攻击。攻击者随后可以通过向其一用户发送一条消息(在(不一定有效的)签名中引用该畸形记录)来使验证方读取该畸形密钥记录。验证方必须彻底验证所有从 DNS 检索到的密钥记录,并对故意以及无意构造畸形的密钥记录都保持健壮。

8.9. 故意构造的畸形 DKIM-Signature 头字段

验证方必须准备好接收带有畸形 DKIM-Signature 头字段的消息,并在依赖其任何内容之前彻底验证该头字段。

8.10. 信息泄露

攻击者可以通过使用每消息选择器,然后监控其 DNS 流量以进行密钥查找,来确定特定签名何时被验证。这相当于针对验证时间(而非消息被读取的时间)的"网络信标"(web bug)。

8.11. 远程时序攻击

在某些情况下,可能可以使用远程时序攻击 [BONEH03] 提取私钥。实现应考虑混淆时序以防止此类攻击。

8.12. 重排的头字段

现有标准允许中间 MTA 重排头字段。如果签名方对两个或多个同名头字段进行签名,这可能导致原本合法的消息出现虚假的验证错误。特别地,对任何已有 DKIM-Signature 字段进行签名的签名方,冒着使消息不正确地验证失败的风险。

8.13. RSA 攻击

攻击者可创建一个具有小指数的大型 RSA 签名密钥,从而要求验证密钥具有大指数。这将迫使验证方使用相当多的计算资源来验证签名。验证方可以通过拒绝验证引用具有不合理指数的公钥的选择器的签名,来避免此攻击。

一般而言,攻击者可能试图通过用需要验证的消息淹没验证方来压制它。这类似于其他 MTA 拒绝服务攻击,应以类似方式处理。

8.14. 父域的不当签名

第 3.10 节描述的信任关系,可能会被父域构想用来对子域中、在管理上与父域无关的身份进行签名。例如,".com" 注册局可以创建带有 example.com 域中 "i=" 取值的签名消息。对此问题没有通用的解决方案,因为管理上的切割可能发生在域名的任何位置。例如,在 "example.podunk.ca.us" 域中,有三个管理切割(podunk.ca.us、ca.us 和 us),其中任何一个都可以创建带有完整域中身份的消息。

资料性注释:这被视为可接受的风险,原因与域委托可接受相同。例如,在上述情况中,任何域都可能简单地将 "example.podunk.ca.us" 委托给它们选择的服务器,并完全替换所有 DNS 服务的信息。注意,如第 6.1.1 节所讨论,验证方可以忽略来自不太可能域(如 ".com")的签名。

8.15. 涉及额外头字段的攻击

许多电子邮件组件(包括 MTA、MSA、MUA 和过滤模块)仅松散地实现消息格式检查。这样做是出于多年来行业施加的压力——为了降低支持成本而宽松接受进入邮件流的内容;格式不当的消息常常在传输中被悄悄修复、未修复地投递,或被不适当地显示(例如,只显示多个 From: 字段中的第一个)。

评估或应用 DKIM 输出的代理需要意识到:DKIM 签名方可以对格式不当的消息(例如,违反 [RFC5322],如具有仅允许出现一次的字段的多个实例)进行签名,这些消息可能在传输中变为格式不当,或包含不真实、无效的头字段或消息体内容。对此类消息使用 DKIM 可能构成针对接收方的攻击,尤其是在未对签名方进行充分评估的情况下给予签名消息额外信任的情形中。

这些可能代表严重的攻击,但它们与 DKIM 无关;它们是对接收方或被错误识别的作者进行的攻击。

此外,代理若仅因一个头字段被签名就推断该头字段的所有实例都被签名,那是不正确的。

可以通过合法手段获得来自被攻击域的真实签名,但随后可以通过拦截或重放添加额外的头字段。在此场景中,DKIM 可以帮助检测传输中特定字段的添加。这是通过让签名方在 "h=" 标签中额外列出一次该字段名称(例如,对于带有一个 From 字段的消息使用 "h=from:from:..."),以便该字段的实例在下游被添加时将使签名无法验证来实现的(详见第 3.5 节)。这在本质上是一个明确的指示:签名方拒绝为此类格式不当的消息负责。

DKIM 对其被告知要签名和验证的数据进行签名和验证,并且工作正确。因此在这种情况下,DKIM 已经完成了交付一个已验证域("d=" 取值)的工作,并且鉴于 DKIM 签名的语义,签名方实质上对该问题消息承担了一定的责任。这由身份评估者或某个后续代理根据需要对该消息采取行动,例如降低消息(或签名方)的信任、警告收件人,甚至拒收投递。

邮件系统中所有对其他邮件标准执行松散强制的组件,在纳入 DKIM 时都需要重新审视那种姿态,尤其是在考虑诸如所述潜在攻击的问题时。

9. 参考文献

9.1. 规范性参考文献

9.2. 资料性参考文献

附录 A. 使用示例(资料性)

本节展示了从提交到最终投递的电子邮件完整流程,演示各个组件如何组合在一起。本示例中使用的密钥见附录 C。

A.1. 用户撰写电子邮件

From: Joe SixPack <joe@football.example.com>
To: Suzie Q <suzie@shopping.example.net>
Subject: Is dinner ready?
Date: Fri, 11 Jul 2003 21:00:37 -0700 (PDT)
Message-ID: <20030712040037.46341.5F8J@football.example.com>

Hi.

We lost the game.  Are you hungry yet?

Joe.

图 1:用户撰写电子邮件

A.2. 邮件被签名

该电子邮件由 example.com 的出站邮件服务器签名,现在如下所示:

DKIM-Signature: v=1; a=rsa-sha256; s=brisbane; d=example.com;
     c=simple/simple; q=dns/txt; i=joe@football.example.com;
     h=Received : From : To : Subject : Date : Message-ID;
     bh=2jUSOH9NhtVGCQWNr9BrIAPreKQjO6Sn7XIkfJVOzv8=;
     b=AuUoFEfDxTDkHlLXSZEpZj79LICEps6eda7W3deTVFOk4yAUoqOB
     4nujc7YopdG5dWLSdNg6xNAZpOPr+kHxt1IrE+NahM6L/LbvaHut
     KVdkLLkpVaVVQPzeRDI009SO2Il5Lu7rDNH6mZckBdrIx0orEtZV
     4bmp/YzhwvcubU4=;
Received: from client1.football.example.com  [192.0.2.1]
     by submitserver.example.com with SUBMISSION;
     Fri, 11 Jul 2003 21:01:54 -0700 (PDT)
From: Joe SixPack <joe@football.example.com>
To: Suzie Q <suzie@shopping.example.net>
Subject: Is dinner ready?
Date: Fri, 11 Jul 2003 21:00:37 -0700 (PDT)
Message-ID: <20030712040037.46341.5F8J@football.example.com>

Hi.

We lost the game.  Are you hungry yet?

Joe.

图 2:邮件被签名

签名邮件服务器需要访问与 "brisbane" 选择器关联的公钥,才能生成此签名。

A.3. 邮件签名被验证

签名通常由入站 SMTP 服务器或可能的最终投递代理验证。然而,中间 MTA 如果选择也可以执行此验证。验证过程使用从 DKIM-Signature 头字段的 "d=" 标签提取的域 "example.com" 和从 "s=" 标签提取的选择器 "brisbane",构造 DNS DKIM 查询:brisbane._domainkey.example.com。

签名验证从物理上最后一个 Received 头字段、From 头字段等开始,按 "h=" 标签中列出的顺序。验证接着以一个 CRLF 后跟消息体(从 "Hi." 开始)继续。该电子邮件使用 "simple" 方法进行规范化准备以进行验证。查询及随后的签名验证结果(在此示例中)存储在 X-Authentication-Results 头字段行中。成功验证后,电子邮件如下所示:

X-Authentication-Results: shopping.example.net
  header.from=joe@football.example.com; dkim=pass
Received: from mout23.football.example.com (192.168.1.1)
  by shopping.example.net with SMTP;
  Fri, 11 Jul 2003 21:01:59 -0700 (PDT)
DKIM-Signature: v=1; a=rsa-sha256; s=brisbane; d=example.com;
  c=simple/simple; q=dns/txt; i=joe@football.example.com;
  h=Received : From : To : Subject : Date : Message-ID;
  bh=2jUSOH9NhtVGCQWNr9BrIAPreKQjO6Sn7XIkfJVOzv8=;
  b=AuUoFEfDxTDkHlLXSZEpZj79LICEps6eda7W3deTVFOk4yAUoqOB
    4nujc7YopdG5dWLSdNg6xNAZpOPr+kHxt1IrE+NahM6L/LbvaHut
    KVdkLLkpVaVVQPzeRDI009SO2Il5Lu7rDNH6mZckBdrIx0orEtZV
    4bmp/YzhwvcubU4=;
Received: from client1.football.example.com  [192.0.2.1]
  by submitserver.example.com with SUBMISSION;
  Fri, 11 Jul 2003 21:01:54 -0700 (PDT)
From: Joe SixPack <joe@football.example.com>
To: Suzie Q <suzie@shopping.example.net>
Subject: Is dinner ready?
Date: Fri, 11 Jul 2003 21:00:37 -0700 (PDT)
Message-ID: <20030712040037.46341.5F8J@football.example.com>

Hi.

We lost the game.  Are you hungry yet?

Joe.

图 3:成功验证

附录 B. 用例(资料性)

DKIM 签名与验证可以以不同方式用于不同的运营场景。本附录讨论一些常见示例。

注释:本附录中的描述仅用于提供信息。它们描述了在给定特定约束和需求的情况下,使用 DKIM 的各种方式。在任何情况下,这些示例都不旨在被当作在创建实现时提供关于 DKIM 规范细节的解释或指导。

B.1. 替代的提交场景

在最简单的场景中,用户的 MUA、MSA 和互联网(边界)MTA 都在同一个管理环境中,使用相同的域名。因此,参与提交和初始传输的所有组件都是相关的。然而,两个或多个组件处于独立管理控制之下是很常见的。这为选择和管理用于签名的域名及其与常见电子邮件身份头字段的关系带来了挑战。

B.1.1. 委托的业务职能

一些组织将特定的业务职能分配给组织内部或外部的独立小组。那么,目标是授权该小组对某些邮件进行签名,但约束它们能生成的签名。DKIM 选择器("s=" 签名标签)促进了这种受限授权。这些外包业务职能的示例包括合法的电子邮件营销提供商和企业福利提供商。

在这里,被委托的小组需要能够使用客户公司的电子邮件域发送已签名的消息。同时,客户通常不愿意为提供商注册一个授予向该域中任意地址发送消息能力的密钥。

有多种方式来管理这些使用场景。在一种情况下,客户组织提供所有的公共查询服务(例如 DNS)管理;在另一种情况下,它使用 DNS 委托,使被委托小组能够进行该 DKIM 密钥记录的所有持续管理。

如果客户组织保留所有 DNS 管理的责任,外包公司可以生成密钥对,将公钥提供给客户公司,然后客户公司使用唯一的选择器在查询服务中注册它。客户公司保留对委托密钥使用的控制,因为它保留随时撤销该密钥的能力。

如果客户希望由被委托小组进行 DNS 管理,它可以使选择器指定的域名指向提供商的 DNS 服务器。然后提供商为该选择器创建并维护所有的 DKIM 签名信息。因此,客户无法对获得签名的地址的 local-part 施加约束,但可以通过移除 DNS 委托记录来撤销提供商的签名权。

B.1.2. PDA 及类似设备

PDA 表明了对每域使用多个密钥的需求。假设 John Doe 希望使用其公司电子邮件地址 jdoe@example.com 发送消息,而其电子邮件设备由于设备限制或其互联网接入提供商的约束,无法与公司的网络建立虚拟专用网络(VPN)连接。如果设备配备了由 example.com 域管理员为 jdoe@example.com 注册、并带有签名消息软件的私钥,John 可以在设备本身上、在通过接入服务商的出站网络传输之前对消息进行签名。

B.1.3. 漫游用户

漫游用户经常发现自己处于方便或必要使用其家庭服务器以外的 SMTP 服务器的情形;例如会议和许多酒店。在此类情形下,由提交服务添加的签名将使用与用户家庭系统不同的身份。

理想情况下,漫游用户会使用 VPN 或运行在 587 端口带有 SMTP AUTHentication 的 SUBMISSION 服务器连接回其家庭服务器。如果签名能在漫游用户的笔记本电脑上执行,那么他们可以在提交之前签名,尽管进一步被修改的风险很高。如果这两种都不可能,这些漫游用户将无法使用其自身域密钥发送已签名的邮件。

B.1.4. 独立(信息亭)消息提交

独立服务,如路边信息亭和基于 Web 的信息服务,与用户没有持久的电子邮件服务关系,但用户偶尔请求代其发送邮件。例如,提供新闻的网站通常允许读者将文章副本转发给朋友。这通常使用读者自己的电子邮件地址来完成,以指示作者是谁。这有时被称为 "Evite" 问题,以允许用户在朋友间发送邀请的同名网站命名。

处理此问题的常见方式是继续将读者的电子邮件地址放在消息的 From 头字段中,但将一个由电子邮件发布站点拥有的地址放入 Sender 头字段。发布站点随后可以使用 Sender 字段中的域对消息进行签名。这为接收电子邮件站点提供了有用信息,使其能够将被签名域与初始提交电子邮件角色关联起来。

接收站点通常希望向其终端用户提供以这种方式中介的邮件信息。尽管不同方法的实际效力是人机工程学可用性研究的主题,但所使用的一种技术是让验证系统重写 From 头字段以指示被验证的地址,例如:From: John Doe via news@news-site.example <jdoe@example.com>。(注意,此类重写将破坏签名,除非它在验证过程完全完成之后进行。)

B.2. 替代的投递场景

电子邮件经常在具有与初始提交所用地址不同的地址的邮箱处被接收。在这些情况下,一个中间机制在最初使用的地址上运作,然后将消息传递给最终目的地。此中介过程对 DKIM 签名提出了一些挑战。

B.2.1. 亲和地址

"亲和地址"允许用户拥有一个稳定的电子邮件地址,即使该用户在不同的电子邮件提供商之间移动。它们通常与大学校友会、专业组织和娱乐组织相关联,用户预期与之有长期关系。这些域通常提供入站电子邮件的转发,并且通常有一个关联的 Web 应用,用于认证用户并允许更改转发地址。

然而,这些服务通常依赖用户通过其自身服务提供商的 MTA 发送出站消息。因此,用亲和地址域签名的邮件并非由拥有该域的组织所管理的实体签名。

借助 DKIM,亲和域可以使用 Web 应用让用户注册每用户密钥,用于代表其亲和地址对消息签名。用户将取走密钥对中的秘密一半用于签名,而亲和域将公钥一半发布到 DNS 中供验证方访问。

这是另一个利用用户级密钥的应用,用于亲和地址的域通常会有非常大量的用户级密钥。或者,亲和域可以处理出站邮件,运营一个在接收并为其用户签名之前先认证用户的邮件提交代理。当然,这取决于用户服务提供商不阻塞用于邮件提交的相关 TCP 端口。

B.2.2. 简单地址别名(.forward)

在某些情况下,允许收件人配置一个电子邮件地址,使消息从原地址自动重定向到另一个地址,例如通过使用 Unix 的 .forward 文件。在这种情况下,消息通常由收件人域的邮件处理服务重定向,除添加 Received 头字段和更改信封收件人地址外不做修改。在这种情况下,最终地址邮箱处的收件人很可能能够验证原始签名,因为被签名的内容未改变,DKIM 能够验证消息签名。

B.2.3. 邮件列表与再发布者

接收消息然后重新提交的服务行为差异很大。一个主要示例是邮件列表(以下统称"转发者"),从那些除添加 Received 头字段和更改信封信息外不修改消息本身的,到那些添加头字段、更改 Subject 头字段、向消息体添加内容(通常在末尾)、或以某种方式重新格式化消息体的都有。简单的那些产生的消息与自动化别名服务非常相似。更复杂的系统本质上是创建一条新消息。

不修改消息体或已签名头字段的转发者,很可能维持现有签名的有效性。它也可以选择向消息添加自己的签名。

以可能使现有签名失效的方式修改消息的转发者,特别适合添加自己的签名(例如 mailing-list-name@example.net)。由于(重新)签名是对消息内容承担责任,这些签名的转发者可能会有所选择,仅在消息带有有效签名到达、或它们有其他理由知晓消息非伪造时才转发或重新签名。

主要作为邮件再分发者的系统的一个常见做法,是向消息添加 Sender 头字段以标识用于签名消息的地址。此做法将按 [RFC5322] 的要求移除任何已有的 Sender 头字段。转发者应用一个新的 DKIM-Signature 头字段,带有转发者的签名、公钥和相关信息。

相关主题和讨论见 [RFC6377]。

附录 C. 创建公钥(资料性)

默认签名是对完整电子邮件的 RSA 签名的 SHA-256 摘要。为便于解释,使用 openssl 命令来描述管理密钥和签名的机制。生成适合 DKIM 的 1024 位未加密私钥的一种方式如下:

$ openssl genrsa -out rsa.private 1024

为了提高安全性,也可以添加 "-passin" 参数来加密私钥。使用该参数将要求在后续若干步骤中输入密码。服务器可能倾向于使用硬件加密支持。

"genrsa" 步骤生成文件 rsa.private,其中包含类似于如下的密钥信息:

-----BEGIN RSA PRIVATE KEY-----
MIICXwIBAAKBgQDwIRP/UC3SBsEmGqZ9ZJW3/DkMoGeLnQg1fWn7/zYtIxN2SnFC
jxOCKG9v3b4jYfcTNh5ijSsq631uBItLa7od+v/RtdC2UzJ1lWT947qR+Rcac2gb
to/NMqJ0fzfVjH4OuKhitdY9tf6mcwGjaNBcWToIMmPSPDdQPNUYckcQ2QIDAQAB
AoGBALmn+XwWk7akvkUlqb+dOxyLB9i5VBVfje89Teolwc9YJT36BGN/l4e0l6QX
/1//6DWUTB3KI6wFcm7TWJcxbS0tcKZX7FsJvUz1SbQnkS54DJck1EZO/BLa5ckJ
gAYIaqlA9C0ZwM6i58lLlPadX/rtHb7pWzeNcZHjKrjM461ZAkEA+itss2nRlmyO
n1/5yDyCluST4dQfO8kAB3toSEVc7DeFeDhnC1mZdjASZNvdHS4gbLIA1hUGEF9m
3hKsGUMMPwJBAPW5v/U+AWTADFCS22t72NUurgzeAbzb1HWMqO4y4+9Hpjk5wvL/
eVYizyuce3/fGke7aRYw/ADKygMJdW8H/OcCQQDz5OQb4j2QDpPZc0Nc4QlbvMsj
7p7otWRO5xRa6SzXqqV3+F0VpqvDmshEBkoCydaYwc2o6WQ5EBmExeV8124XAkEA
qZzGsIxVP+sEVRWZmW6KNFSdVUpk3qzK0Tz/WjQMe5z0UunY9Ax9/4PVhp/j61bf
eAYXunajbBSOLlx4D+TunwJBANkPI5S9iylsbLs6NkaMHV6k5ioHBBmgCak95JGX
GMot/L2x0IYyMLAz6oLWh2hm7zwtb0CgOrPo1ke44hFYnfc=
-----END RSA PRIVATE KEY-----

要从私钥中提取公钥组件,按如下方式使用 openssl:

$ openssl rsa -in rsa.private -out rsa.public -pubout -outform PEM

这将生成文件 rsa.public,其中包含类似于如下的密钥信息:

-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDwIRP/UC3SBsEmGqZ9ZJW3/DkM
oGeLnQg1fWn7/zYtIxN2SnFCjxOCKG9v3b4jYfcTNh5ijSsq631uBItLa7od+v/R
tdC2UzJ1lWT947qR+Rcac2gbto/NMqJ0fzfVjH4OuKhitdY9tf6mcwGjaNBcWToI
MmPSPDdQPNUYckcQ2QIDAQAB
-----END PUBLIC KEY-----

该公钥数据(不含 BEGIN 和 END 标签)被放入 DNS:

$ORIGIN _domainkey.example.org.
brisbane IN  TXT  ("v=DKIM1; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQ"
                     "KBgQDwIRP/UC3SBsEmGqZ9ZJW3/DkMoGeLnQg1fWn7/zYt"
                     "IxN2SnFCjxOCKG9v3b4jYfcTNh5ijSsq631uBItLa7od+v"
                     "/RtdC2UzJ1lWT947qR+Rcac2gbto/NMqJ0fzfVjH4OuKhi"
                     "tdY9tf6mcwGjaNBcWToIMmPSPDdQPNUYckcQ2QIDAQAB")

C.1. 与 DomainKeys 密钥记录的兼容性

DKIM 密钥记录在许多情况下被设计为与 DomainKeys [RFC4870] 使用的密钥记录向后兼容(在 DomainKeys 语境中有时称为"选择器记录")。一个不兼容之处值得特别注意。"g=" 标签值可用于 DomainKeys 和 [RFC4871] 密钥记录,以提供密钥记录对特定 local-part 有效性的更细粒度。DomainKeys 中空的 "g=" 值对该域中的所有地址有效。这与原始 DKIM 规范([RFC4871])中的用法不同,在后者中空 "g=" 值对任何地址都无效。特别地,见 [RFC4870] 第 3.2.3 节中的示例公钥记录。

C.2. RFC 4871 兼容性

尽管 "g=" 标签在本版 DKIM 规范中已弃用(因此现在必须被忽略),仍建议签名方不要在密钥记录中包含 "g=" 标签,因为一些符合 [RFC4871] 的验证方还将在相当时段内使用。

附录 D. MUA 考量(资料性)

当 DKIM 签名被验证时,处理系统有时会将结果提供给收件人的 MUA。如何以有助于用户的方式向用户呈现此信息,是一个持续的人机工程学可用性研究课题。趋势是让 MUA 突出显示 SDID,试图向用户展示主张消息责任的身份。MUA 可以通过图形等视觉提示、在备用视图中包含地址、甚至使用已验证信息重写原始 From 地址来做到这一点。某些 MUA 可能指示哪些头字段受到了已验证 DKIM 签名的保护。这可以通过在已签名头字段上给出正面指示、在未签名头字段上给出负面指示、通过视觉上隐藏未签名头字段,或这些方式的某种组合来实现。如果 MUA 对已签名头字段使用视觉指示,MUA 可能需要小心,不要以使终端用户可能将其理解为已被签名的方式显示未签名头字段。如果消息带有 "l=" 标签且其取值未延伸到消息末尾,MUA 也可能隐藏或标记未被签名的那部分消息体。

上述信息并非旨在详尽无遗。MUA 可以选择突出、强调、隐藏或以其他方式显示任何其(在 MUA 作者看来)可能对终端用户重要的其他信息。

附录 E. 相对 RFC 4871 的变更

附录 F. 致谢

DKIM 之前的 IETF 版本 [RFC4871] 由 Eric Allman、Jon Callas、Mark Delany、Miles Libbey、Jim Fenton 和 Michael Thomas 编辑。

该规范是一项广泛协作努力的结果,参与的还有 Russ Allbery、Edwin Aoki、Claus Assmann、Steve Atkins、Rob Austein、Fred Baker、Mark Baugher、Steve Bellovin、Nathaniel Borenstein、Dave Crocker、Michael Cudahy、Dennis Dayman、Jutta Degener、Frank Ellermann、Patrik Faeltstroem、Mark Fanto、Stephen Farrell、Duncan Findlay、Elliot Gillum、Olafur Gudmundsson、Phillip Hallam-Baker、Tony Hansen、Sam Hartman、Arvel Hathcock、Amir Herzberg、Paul Hoffman、Russ Housley、Craig Hughes、Cullen Jennings、Don Johnsen、Harry Katz、Murray S. Kucherawy、Barry Leiba、John Levine、Charles Lindsey、Simon Longsdale、David Margrave、Justin Mason、David Mayne、Thierry Moreau、Steve Murphy、Russell Nelson、Dave Oran、Doug Otis、Shamim Pirzada、Juan Altmayer Pizzorno、Sanjay Pol、Blake Ramsdell、Christian Renaud、Scott Renfro、Neil Rerup、Eric Rescorla、Dave Rossetti、Hector Santos、Jim Schaad、Spamhaus.org 团队、Malte S. Stretz、Robert Sanders、Rand Wacker、Sam Weiler 和 Dan Wing。

早期的 DomainKeys 是 DKIM 衍生的主要来源。关于 DomainKeys 的更多信息见 [RFC4870]。

本修订版得到了 Steve Atkins、Mark Delany、J.D. Falk、Jim Fenton、Michael Hammer、Barry Leiba、John Levine、Charles Lindsey、Jeff Macdonald、Franck Martin、Brett McDowell、Doug Otis、Bill Oxley、Hector Santos、Rolf Sonneveld、Michael Thomas 和 Alessandro Vesely 的贡献。

作者地址

Dave Crocker(编辑)
Brandenburg InternetWorking
675 Spruce Dr.
Sunnyvale, CA 94086
USA
电话:+1.408.246.8253
电子邮件:dcrocker@bbiw.net
URI:http://bbiw.net

Tony Hansen(编辑)
AT&T Laboratories
200 Laurel Ave. South
Middletown, NJ 07748
USA
电子邮件:tony+dkimsig@maillennium.att.com

Murray S. Kucherawy(编辑)
Cloudmark
128 King St., 2nd Floor
San Francisco, CA 94107
USA
电子邮件:msk@cloudmark.com