本文へスキップ
ecdsa.com
DKIM verifiers (Gmail, mailauth, Rspamd…)DKIM

エラーメッセージ

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 では、本文ハッシュの不一致は恒久的な失敗として扱われます。典型的な原因は、メーリングリストのフッター、免責事項、リンクを書き換えるセキュリティゲートウェイです。

発生する理由

修正方法

  1. 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. 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)

関連するエラー

署名エラーデータベースをすべて見る