DKIM
メールがSMTPの経路上で改竄されていないことを保証する
目次
DKIM(DomainKeys Identified Mail)は、メール送信に関与したMTA(Mail Transfer Agent)が、メールの内容が改竄されていないことを保証する仕組みです。
メールを送信したMTAやSMTPリレーで介在したMTAが、メールbodyとヘッダーの一部からハッシュ値を作成して、これを秘密鍵によって署名してヘッダに付与することで、受信側のMTAはDNSに登録してある公開鍵を使ってハッシュ値を取り出し、且つ、受信MTAでもハッシュ値を計算して検算することで、メールの内容が改竄されていないことを確認できます。
DKIMの仕様は、2011年に公開されたRFC6376に記載されています。
1. DKIM処理プロセス
DKIMは、送信者がメールの一部(通常はbodyと特定のヘッダ)に対して署名を行い、受信側がその署名とハッシュ値を検証することで、メールの改竄や送信者の正当性を確認する仕組みです。
以下は、受信側MTAがDKIMのハッシュ値や署名をどのように利用するかの基本的な流れです。
1.1. 送信側での署名生成
送信MTAでのDKIMの署名作成プロセスは、bodyのハッシュ値計算とヘッダのハッシュ値計算による署名作成の2つから成り立ちます。
送信MTAは、bodyのハッシュ値とヘッダから作成した秘密鍵での署名をメールのヘッダ情報として書き込んでメールを送信します。
- 1. メール作成とcanonicalization
-
送信者はメールを作成し、DKIMの署名対象となるヘッダ群(
h=
タグで指定)とメールbodyを、それぞれ定められたcanonicalization方式(c=
タグ、例:simple
またはrelaxed
)に従って整形します。 - 2. bodyのハッシュ値計算
-
整形したbody部に対して、指定のハッシュアルゴリズム(通常はSHA-256、
a=
タグで指定)を用いてハッシュ値を計算し、その値をDKIM-Signatureヘッダのbh=
タグにセットします。 - 3. ヘッダ署名の作成
-
同じくcanonicalizationしたヘッダ群に対して、送信者は秘密鍵を用いてデジタル署名を行い、その署名値を
b=
タグにセットします。 - 4. DKIM-Signatureヘッダの付加
-
以下の項目でDKIM-Signatureヘッダがメールに付加されます。
- ドメイン
d=
- セレクタ
s=
- canonicalization方式
c=
- 署名アルゴリズム
a=
- 署名対象ヘッダリスト
h=
- bodyハッシュ値
bh=
- 署名値
b=
- ドメイン
以下は、DKIM署名が付加されたメールヘッダの一例です。
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=example.com; s=selector; h=From:Date:Subject:To; bh=MTIzNDU2Nzg5MDEyMzQ1Njc4OTAxMjM0NTY3ODkwMTI=; b=aBcDeFgHiJkLmNoPqRsTuVwXyZ0123456789AbCdEfGhIjKlMnOpQrStUvWxYz;
この例では、以下のような情報が含まれています。
v=1
: DKIM署名のバージョンは1です。a=rsa-sha256
: 署名に使用されたアルゴリズムはRSA-SHA256です。c=relaxed/relaxed
: ヘッダとbodyのキャノニカライゼーションアルゴリズムは、両方ともrelaxedです。d=example.com
: DKIM署名を行ったドメイン名はexample.comです。s=selector
: セレクタは"selector"です。h=From:Date:Subject:To
: 署名対象のヘッダフィールドは、From, Date, Subject, Toです。bh=MTIzNDU2Nzg5MDEyMzQ1Njc4OTAxMjM0NTY3ODkwMTI=
: メールbodyのハッシュ値(Base64エンコード済み)です。b=aBcDeFgHiJkLmNoPqRsTuVwXyZ0123456789AbCdEfGhIjKlMnOpQrStUvWxYz
: 署名データ(Base64エンコード済み)です。秘密鍵で署名されたハッシュ値が格納されています。
1.2. DKIM検証プロセス
受信MTAでのDKIMの検証プロセスは、bodyのハッシュ値と署名の2つの検証から成り立ちます。
メールヘッダに記載されたbodyのハッシュ値と秘密鍵での署名を、受信側MTAがそれぞれbodyとヘッダに対して再計算・再検証することで、メールの整合性と送信者の正当性を確認しています。
- bodyハッシュ値 (
bh=
) -
受信MTAは、メールbodyを指定のcanonicalizationとハッシュアルゴリズムで処理し、計算結果と
bh=
の値が一致するかをチェックすることで、body部の改竄がないかを検証します。 - 署名 (
b=
) -
受信MTAは、
d=
とs=
を使ってDNSから公開鍵を取得し、署名対象のヘッダを再構築して、b=
に記載された署名が公開鍵で正しく検証できるかどうかを確認します。
- 1. DKIM-Signatureヘッダの抽出
-
受信したメールから、DKIM-Signatureヘッダを見つけ、各タグの値を取得します。
- ドメイン
d=
- セレクタ
s=
- canonicalization方式
c=
- 署名アルゴリズム
a=
- 署名対象ヘッダリスト
h=
- bodyハッシュ値
bh=
- 署名値
b=
- ドメイン
- 2. 公開鍵の取得(DNS ルックアップ)
-
DKIM-Signatureヘッダに記載された送信ドメイン(
d=
)とセレクタ(s=
)の値を使って、DNSのTXTレコードを問い合わせます。
このTXTレコードには、送信者が設定した公開鍵が含まれており、これが署名検証に使われます。 - 3. bodyのハッシュ検証
-
- 3.1. Canonicalization
-
受信したメールbodyを、DKIM-Signatureの
c=
タグで指定された方式に従い正規化します。 - 3.2. ハッシュ計算
-
正規化後のbodyに対して、同じハッシュアルゴリズム(
a=
タグで指定)を用いてハッシュ値を計算します。 - 3.3. 比較
-
この計算結果がDKIM-Signatureの
bh=
タグに記載されている値と一致するか確認します。
一致すれば、body部が改竄されていないと判断されます。
不一致の場合は、メールbodyが途中で変更された可能性があるため、検証は失敗となります。
- 4. ヘッダ署名の検証
-
- 4.1. 署名対象ヘッダの再構築
-
DKIM-Signatureの
h=
タグにリストされたヘッダ群を、同じcanonicalization方式で再整形し、署名生成時と同じ形に再構築します。 - 4.2. 署名検証
-
取得した公開鍵を使い、DKIM-Signatureの
b=
タグにある署名を検証します。
署名が正しければ、ヘッダ情報も送信者側で意図した通りであり、改竄されていないと判断されます。
- 5. 検証結果の利用
-
DKIM検証が両方成功(bodyのハッシュ検証とヘッダ署名検証がともに合格)した場合、受信側MTAは「メールは正当な送信者から送られ、途中で改竄されていない」と判断します。
この情報は、スパム判定や迷惑メールフィルタ、さらにDMARCなどの他の認証技術と連携して、メールの受信可否の判断に利用されます。
1.3. 受信側メールサーバの処理
DKIMレコードが設定されていると、受信側のメールサーバは、メールが正当な送信者から送られたかどうかを判断できます。
DKIMの単体仕様では、正当でない送信者からのメールの処理方法は、受信側のメールサーバに委ねられています。
一般的に、多くのメールサーバは、認証に失敗したメールを迷惑メールフォルダに移動する設定になっています。
DMARCポリシーが設定されている場合、そのポリシーに従って処理されます。
2. DKIMの動作例
ここでは、Google Workspace を例に、DKIMの動作を説明します。
例として、example.com の正しいメールサーバが Gmail であると仮定します。
Google Workspaceはデフォルトで、第三者署名(例:d=*.gappssmtp.com
)の鍵を使用して署名します。
しかし、DMARC Alignment Checkでは送信ドメインが一致しないと判断されるため、d=example.com
の DKIM 鍵を発行します。
この公開鍵は、DNSにTXTレコードとして登録され、レコード名は google._domainkey
となります。
- _domainkey
-
DKIMレコードであることを示す固定プレフィックスです。
DNSでDKIMの公開鍵を検索する際に使用されます。 -
これは「セレクタ」と呼ばれ、同一ドメインで複数のDKIM鍵を区別するための識別子です。
メール送信時、使用されたセレクタ情報がヘッダに含まれ、受信側はこの情報を基に適切な公開鍵をDNSから取得し署名を検証します。
なお、サービスごとにユニークな値が必要で、たとえば、Google Workspace では「google」、Microsoft 365 では「selector1/selector2」、SendGrid では「s1/s2」などが使われます。
DNS に公開鍵を登録後、Google 管理コンソールにログインし、「認証を開始」ボタンをクリックして DKIM を有効化します。
詳しい手順については、以下のリンクをご参照ください。
ドメインでDKIMを有効にする - Google Workspace 管理者ヘルプ
例えば、悪意のあるユーザーがsupport@example.com
のアドレスを使い、Gmailアカウントからなりすましメールを送信しようとした場合を考えます。
Gmail のアカウントを取得できれば SPFは通過する可能性がありますが、DKIMではメールヘッダのハッシュ値が秘密鍵で署名されているため、攻撃者が同じ値を再現することはできません。
結果として、受信側で公開鍵を用いた検証により、署名が一致しないためなりすましが検出されます。
3. DKIMの構文
DKIM署名は、メールのヘッダにDKIM-Signature
というフィールドとして追加されます。
このフィールドには、いくつかのタグが含まれており、それぞれ異なる情報を持ちます。
以下に、主要なタグを示します。
署名に使われるタグ
- v
- DKIMのバージョン。現在の仕様では1のみであり、他の値は無効です。
- a
- 署名に使用されたアルゴリズム。一般的には、"rsa-sha256" が使用されます。
- d
- DKIM署名を行ったドメイン名。
- s
- セレクタ。署名に使用された公開鍵を特定するために使用されます。
- c
- ヘッダキャノニカライゼーションアルゴリズムとbodyキャノニカライゼーションアルゴリズム。"relaxed/relaxed" や "simple/simple" などの組み合わせがあります。
- q
- 公開鍵取得のクエリ方法。通常、"dns/txt" が使用されます。
- h
- 署名対象のヘッダフィールドのリスト。
- bh
- メールbodyのハッシュ値(Base64エンコード済み)。bodyの改竄検知に使用されます。
- b
- 署名データ。秘密鍵で署名されたハッシュ値です。
DNSに使われるタグ
DKIM では、メール送信者が自身のドメインに DNS TXT レコード を作成し、公開鍵などの情報を提供します。このレコードには、次のようなタグ(パラメータ)が含まれます。
- v
- DKIMのバージョン。現在の仕様では1のみであり、他の値は無効です。
- p
- DKIM署名の検証に使用する公開鍵。
p= の値が空の場合、そのセレクタ(selector)は無効化され、署名の検証は行われません。 p= を削除するのではなく、空にすることで DKIM の無効化を意図的に行えます。 - k
- 使用する暗号鍵の種類を指定します。
デフォルトではrsaです。
ed25519も使えますが、受信側MTAが対応している必要があるため、互換性を考慮してRSA署名とED25519署名の両方を併用する「二重署名アプローチ」を採用することが推奨されています。 - t
-
DKIMの動作を変更するためのフラグ。
- y
- 署名がテスト目的であり、本番運用ではないことを示す。
- s(セレクタ制限)
- 署名されたメールの d=(ドメイン)と、送信者の From:ヘッダーのドメインが完全一致する場合のみDKIM署名を有効とする。 t=y;s のように複数のフラグを組み合わせることも可能。
- h
- 署名に使用するハッシュ関数を指定します。
- n
- 管理者向けのメモや説明文を記載できますが、DKIM の動作には影響しません。
4. SMTPリレーで経由したMTA毎の署名について
メールは複数のMTAを経由して配信される場合があります。
通常、DKIM署名は送信元のMTAで付与され、受信側で検証されることで、メール内容の改竄が行われていないことを保証します。
しかし、各SMTPリレーに関与したMTAも独自のDKIM署名を追加することも可能です。
ここでは、1つのメールに複数のDKIM署名が付く理由とその注意点について説明します。
- 複数の組織が関与する場合
-
多くの企業は、Amazon SES、SendGrid、MailChimp、SalesForce、Zoho などのメール配信サービスやSaaSを利用しています。
これらのサービスは、独自のDKIM署名を付与することで、サービス経由で送信されたことを証明し、各組織のメール配信に対する責任と信頼性を明確にします。 - 複数の送信システムを経由する場合
-
同一ドメインから送信されるメールが、複数のシステム(例:Secure Mail Gateway、誤送信防止システム、PPAP対策ツール)を経由すると、各システムが独自にDKIM署名を追加することができます。
たとえば、古い送信元MTAがDKIMに未対応であっても、途中のリレーで適切な署名が追加されれば、メールの改竄検証は維持されます。
複数のDKIM署名を付与する際の注意点は以下の通りです。
- 署名の検証
-
受信側のメールサーバは、メール内の各DKIM署名を個別に検証します。
すべての署名が有効でなくても、少なくとも1つの署名が正しく検証されれば、DKIM検証は成功とみなされます。
ただし、DMARCでは自社ドメインの署名が検証に成功している必要があります。 - 受信システムの互換性
- 複数のDKIM署名を含むメールは、受信側のシステムやフィルタリングで異なる扱いを受ける場合があるため、事前に動作確認を行うことが推奨されます。
- DMARC運用時の署名
-
各サービス独自の秘密鍵ではなく、自社ドメインの秘密鍵で署名する必要があります。
多くの主要サービスは、カスタムドメイン向けの鍵生成や設定手続きを提供しており、これによりDMARCアライメントが実現できます。
受信側のシステムは、メールに含まれる複数のDKIM署名のうち、少なくとも1つが正しく検証されれば認証成功と判断します。
これにより、以下の効果が得られます。
- 認証の維持
- 異なる送信システムや組織が同じドメインを使用していても、各経路で適切に署名されていれば、メール認証が維持されます。
- 柔軟性の向上
- 複数のシステムが関与している場合でも、各システムが独自のDKIM署名を追加することで、柔軟かつ堅牢な認証プロセスを実現できます。
- スパム対策の強化
- 複数の署名により、メールが特定の経路を経由したことが証明され、不正な送信者が正当なシステムを模倣するリスクを低減できます。
なお、複数のDKIM署名を付与する場合は、それぞれ異なるセレクタ(署名に関連付けられた識別子)と鍵ペアを使用することが重要です。
これにより、各署名が正確に検証されることが保証されます。
5. DKIM運用上の注意点
DKIMのキーローテーション
DKIMのキーローテーションは、定期的に秘密鍵と公開鍵のペアを更新するプロセスで、セキュリティのベストプラクティスとして推奨されます。
キーローテーションが重要な理由は以下のとおりです。
- セキュリティ向上
- 万が一秘密鍵が漏洩しても、定期的に更新することでその鍵の有効期間が短縮され、悪用リスクを低減できます。
- 鍵の強度維持
-
暗号技術は日々進化しており、古い鍵では新しい攻撃手法に対抗できない可能性があります。
最新の技術に基づいた鍵に更新することで、セキュリティレベルを維持できます。 - 運用上の問題対処
- 鍵の管理や運用に問題が生じた場合でも、新しい鍵ペアへの切り替えが容易になります。
キーローテーションの一般的な手順は以下の通りです。
- 新しい秘密鍵と公開鍵のペアを生成する。
- 新しい公開鍵をDNSに登録する。
- メールサーバが新しい秘密鍵で署名を開始する。
- 古い鍵は一定期間(通常1~3か月)DNSに残し、過去のメール署名の検証をサポートする。その後、削除する。
具体例として、Google Workspaceでは、ユーザーが手動で鍵を生成しDNSに登録する必要があります。
一方、Microsoft 365では、固定のプリフィックスを用いたCNAME設定により、selector1
とselector2
を使った自動キーローテーションがサポートされ、運用効率が向上しています。
M3AAWG(Messaging, Malware and Mobile Anti-Abuse Working Group)は、DKIMのキーローテーションは6か月毎に実施することを推奨しています。
出典:M3AAWG DKIM Key Rotation Best Common Practices
DKIMはサブドメインに自動継承されない
DKIMレコードは設定されたドメインにのみ適用され、サブドメインには自動的に継承されません。したがって、サブドメインからメール送信する場合は、個別にDKIM設定を行う必要があります。
例えば、example.com
にDKIM設定があっても、subdomain.example.com
でメールを送信する場合は、以下の対応が必要です。
- サブドメイン用の公開鍵・秘密鍵ペアを生成する。
- DNSに対応するTXTレコードを登録する。
Type: TXT Host: default._domainkey.subdomain Value: v=DKIM1; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCQxcLY5Rg+AQq87XtdJA/n1GEU6ZFM4viEMgC18fjodbT3FrWRgqso17yBhDtT1AkkfaWmiDSBezmUNs1d3EEjWiowGB4yfNz/LwxzK04NgUmRd3Vj9ymCGq/5R4KyBscQ/y0B9GJbr38dTMA+xVP4fWHz0RwBiTa8cdN8fOIX6wIDAQAB
同一メールサーバから複数のドメインやサブドメインでメールを送信する場合、運用を簡略化するために同じセレクタと鍵ペアを再利用することも可能です。
ただし、以下の点に注意してください。
- 鍵の漏洩リスク
- 同一鍵を複数のドメインで共有すると、鍵が漏洩した場合の影響範囲が広がります。
- 管理の複雑化
-
セレクタ名が同じだと、管理が煩雑になる可能性があります。
問題が発生した際に、切り分けが難しくなります。
運用効率を高めるためには、必要に応じて各サブドメインに個別の鍵を設定するか、DKIM自動設定をサポートするツールやサービス(例:メール配信サービス、DNS管理ツール)の利用が推奨されます。
6. DKIMの限界
DKIMはメール認証システムとして広く利用されていますが、いくつかの制限事項があります。以下に、主要な制限事項とその対策について説明します。
- 転送やメーリングリストによる変更に弱い
-
DKIM署名は、メールのヘッダや本文が変更されるとハッシュ値が変化し、署名が無効となります。
転送やメーリングリストでメール内容が加工されると、DKIM検証に失敗する可能性があるため、この問題の軽減にはARC(Authenticated Received Chain)の導入が有効です。 - DNSの遅延に弱い
-
SPFはRFCで20秒のタイムアウトが規定されていますが、DKIMには標準化されたタイムアウト値が存在しません。
各MTAが独自にタイムアウト値を設定しており、例えば、Microsoft 365ではDKIMのタイムアウト値が500msと定められています。
グローバルなDNSを利用していない場合、公開鍵の取得に失敗し、Outlook 365などで数%〜10%程度のTemperror(タイムアウトエラー)が発生することがあります。
また、Gmailでは2024年11月頃からリゾルバの遅延により同様のエラーを共通事象として検出しています。 - 送信元のヘッダFromのアドレスの正当性は検証しない
-
攻撃者が専用のドメイン(例: ~.xyz)を取得し、SPFやDKIMを正規の送信者のように設定することで、検証に合格させる手法が見受けられます。
その結果、なりすましメールを完全に排除するのが難しくなっています。
この問題への対策としては、DMARCポリシーを「p=reject」に設定する、またはBIMI(Brand Indicators for Message Identification)の導入が有効です。
SPFやDKIMの限界を超えるためのDMARC
以上のように、SPFやDKIMだけの設定では、メールセキュリティの限界があります。
そこでDMARCが登場します。