错误信息
dkim=fail reason="signature verification failed"
也可能输出为
- dkim=fail (bad signature)
无论改动的是头部还是正文,OpenDKIM 都写出 `dkim=fail reason="signature verification failed"`(用 OpenDKIM 2.11.0 复现)。mailauth 会区分两者:头部改动报告为“bad signature”,正文改动报告为“body hash did not verify”。
含义
接收服务器找到了 DKIM 密钥,并按收到的邮件内容计算签名,但结果不匹配:要么已签名的头部(对 OpenDKIM 来说还包括正文)在发件人签名后被改动过,要么发布的密钥与签名密钥不属于同一个密钥对。DKIM 对规范化后的确切字节签名,因此中继的任何改写——主题标签、页脚、重新编码的 MIME 部分——都会使签名失效。对 DMARC 来说,这算作 DKIM 检查失败。
原因
中继改动了已签名的头部
常见给 Subject 头加标签(`[team]`)的邮件列表、改写 `From` 或 `To` 的网关,或者修改 `Content-Type` 的安全设备。`h=` 中列出的每个头部都在签名覆盖范围内。
页脚、免责声明或重新编码
常见附加的免责声明、链接改写、杀毒软件横幅,或者把 8 位内容转换为 quoted-printable,都会改变正文。没有 `l=` 时,每个字节都计入签名。
DNS 中的密钥与签名密钥不匹配
偶见密钥轮换后,选择器的 TXT 记录中仍是旧公钥;或者两台服务器使用同一个选择器,却用不同的私钥签名。
签名者在签名后修改了邮件
偶见签名发生在内容过滤器添加头部或改写邮件之前(Postfix 中的 milter 顺序),或者发送方所用的库先签名、后改动换行符。
修复方法
- 1.
比较已签名的头部与收到的头部
`h=` 标签列出了签名覆盖的内容。把收到的副本中的这些头部与发件人一侧留存的副本(“已发送”文件夹)逐一比较。
bash # Which headers did the signature cover, and what do they look like now? grep -i "^DKIM-Signature" -A4 received.eml | grep -o "h=[^;]*" grep -iE "^(From|To|Subject|Date|Message-ID|Content-Type):" received.eml - 2.
邮件列表和转发方:ARC 与重新签名
必须修改邮件的中间环节应当添加 ARC 头,并用自己的域名签名,这样接收方仍能评估原始的身份验证结果。
text # Mailing list / forwarder: add ARC and re-sign with the list's own domain (Mailman 3 example) [ARC] enabled: yes authserv_id: lists.example.org domain: lists.example.org selector: arc2026 privkey: /etc/mailman3/arc.private - 3.
对照私钥验证 DNS 中的密钥
`opendkim-testkey` 可以确认该选择器发布的记录与签名者使用的密钥相匹配。
bash opendkim-testkey -d example.com -s sel -k /etc/opendkim/keys/sel.private -vvv # DNS record matches the private key?