DKIM 验签失败怎么系统性定位?该从签名头的哪些标签查起?
1
DKIM 验签失败怎么系统性定位?该从签名头的哪些标签查起?
▼
先取签名头,按标签建立坐标
RFC 6376 第 3.5 节(The DKIM-Signature Header Field)定义了签名头的全部标签。排障时先把这几个取出来,后续每一步都围绕它们展开:
d=签名域、s=选择器 —— 决定去哪里取公钥。a=算法 —— 决定用什么算法验证。c=规范化 —— 决定哈希前如何整理。h=头字段列表 —— 决定哪些头被签名覆盖。bh=正文哈希、b=签名值 —— 两个失败点相互独立的校验对象。t=签名时间、x=过期时间 —— 决定签名是否仍在有效期内。
第一步:能不能取到公钥
用 s= 与 d= 拼出密钥记录名 <s>._domainkey.<d>,直接查询。三种结果对应三类问题:
- 查不到记录:选择器写错、记录未发布,或轮换时旧选择器已被删除而仍有旧签名邮件在途。
- 查到但
p为空:按第 3.6.1 节(Textual Representation),空的p表示该公钥已被撤销,签名将被判定无效。确认是否为有意撤销。 - 查到且
p有值:进入下一步。此时应逐字符比对 DNS 返回的公钥与签名系统持有的公钥——录入时被插入换行或空格是高频故障。
第二步:区分 bh 失败与 b 失败(最关键的一步)
验证包含两个独立环节:先校验正文哈希 bh=,再校验整体签名 b=。分清是哪一个失败,能立刻把排查范围缩小一半:
bh不匹配 → 正文被改动。常见于中转追加内容、编码转换、MIME 重组、行尾处理差异。此时无需再怀疑密钥问题。bh匹配但b校验失败 → 问题在头部或密钥。可能是被签名覆盖的头字段遭改写、规范化选择不当,或公钥与私钥不配对。
这一分叉是 DKIM 排障的主干,务必优先确定,避免在错误方向上浪费时间。
第三步:核对算法与规范化
- 算法(
a=):RFC 6376 第 3.3 节(Signing and Verification Algorithms)定义了签名与验证算法。需确认签名方所用算法为验证方所支持,且与密钥记录中声明的算法一致。算法不匹配会直接导致验证失败。 - 密钥长度:过短的密钥可能被验证方以强度不足为由拒绝。轮换时应一并评估。
- 规范化(
c=):若使用了 simple,对空白与折行零容忍,失败率显著偏高。改为 relaxed/relaxed 是最常见且有效的修复动作。
第四步:检查覆盖范围与有效期
h=列表是否过宽。把大量易变头字段签进去,等于主动扩大失败面。收敛到必要字段。h=中是否包含实际不存在的头字段。这在部分实现中用于防止头字段被后续添加,但配置不当会引发意外失败。x=是否已过期。若设置了过期时间且邮件在队列中长时间重试,到达时签名可能已过期。过期时间不宜设置过短,需覆盖最长在途时间。t=时间是否异常。签名系统时钟偏差过大可能引发时间相关判定问题。
第五步:定位到具体环节
- 确认失败是否普遍。若仅对部分接收方失败,优先怀疑 DNS 传播不一致或对方策略差异;若对所有接收方失败,则是签名侧配置问题。
- 确认失败是否只在特定路径出现。若直投正常、经转发或列表后失败,属于中介修改邮件所致,应从链路层面解决而非调签名参数。
- 确认是否与轮换时点重合。时间上高度吻合的失败,几乎都与密钥轮换步骤顺序有关。
- 用聚合报告交叉验证。报告中的 DKIM 结果与签名域信息,能帮助确认是哪一套发送系统在出问题。
