エラーメッセージ
dkim=fail (body hash did not verify)
別の表記
- dkim=neutral (body hash did not verify)
mailauth は、strict モードでは `dkim=fail (body hash did not verify)`、デフォルトの寛容(lenient)モードでは `dkim=neutral (body hash did not verify)` と記録します(どちらも 8.0.1 で再現)。OpenDKIM は同じ状況を `dkim=fail reason="signature verification failed"` と報告します(2.11.0 で再現)。
DKIM verifiers (Gmail, mailauth, Rspamd…) — Authentication-Results after the body changed in transit
このエラーの意味
DKIM 署名の `bh=` タグには、送信者が署名した時点のメッセージ本文のハッシュが入っています。受信者が受け取った本文を(正規化したうえで)ハッシュしたところ値が異なったため、本文は配送中に変更されたことになります。ヘッダーの署名はそもそも問題になっていません。RFC 6376 では、本文ハッシュの不一致は恒久的な失敗として扱われます。典型的な原因は、メーリングリストのフッター、免責事項、リンクを書き換えるセキュリティゲートウェイです。
発生する理由
フッターや免責事項が追加された
よくあるメーリングリスト(配信停止用のフッター)、送信ゲートウェイが追加する企業の免責事項、中継サーバーが追加する「Sent from…」の行は、正規化後の本文を変えてしまいます。
セキュリティゲートウェイが本文を書き換えた
よくある受信側または送信側のフィルターによるリンクの書き換え(Safe Links、URL defense)、添付ファイルの削除、バナーの挿入が原因です。
MIME の転送エンコーディングが変わった
ときどき8BITMIME に対応していない中継サーバーは、8 ビットのコンテンツを quoted-printable または base64 に変換します。デコード後のテキストは同一でも、署名されたバイト列は同一ではありません。
署名者が異なる改行コードでハッシュした
ときどきメッセージが CRLF で送信される(または後で行末の空白が削除される)のに LF の改行コードでハッシュする署名コードでは、`simple` 正規化で一致することのない本文ハッシュが生成されます。
修正方法
- 1.
bh= を自分で再計算する
送信時のコピーと受信時のコピーでそれぞれ本文ハッシュを再計算して比較すれば、原因が署名者にあるのか中継サーバーにあるのかが分かります。
bash # Recompute bh= for relaxed body canonicalization and compare with the header's bh= value python3 - message.eml <<'EOF' import base64, hashlib, re, sys raw = open(sys.argv[1], "rb").read().replace(b"\r\n", b"\n") body = raw.split(b"\n\n", 1)[1] lines = [re.sub(rb"[ \t]+", b" ", l).rstrip(b" \t") for l in body.split(b"\n")] canon = b"\r\n".join(lines).rstrip(b"\r\n") + b"\r\n" print("computed bh=", base64.b64encode(hashlib.sha256(canon).digest()).decode()) EOF grep -o "bh=[^;]*" message.eml - 2.
すべての変更の後に署名する
DKIM の署名処理を送信経路の最後のステップにしてください。管理下にない中継者については、可能であれば ARC と、SPF による DMARC アライメントに頼ってください。
text # Postfix: run content filters (disclaimers, antivirus) BEFORE the DKIM signing milter smtpd_milters = inet:127.0.0.1:10025, inet:127.0.0.1:8891 # ^ disclaimer milter ^ OpenDKIM (signs last)
関連するエラー
dkim=fail reason="signature verification failed"OpenDKIM (Authentication-Results header added by the opendkim milter); mailauth reports the same as "bad signature"dkim=permerrorOpenDKIM (Authentication-Results); mailauth reports syntax errors as dkim=neutraldkim=fail reason="key not found in DNS"OpenDKIM (Authentication-Results); mailauth reports it as dkim=neutral (no key)