+ 作るログイン
図を読み込んでいます…
1 / 14
メールのしくみ ― DNS から SPF・DKIM・DMARC、Resend の運用まで / 全11章

メールのしくみ 6:DKIM ― メールに押す電子署名

発行
アニメモ公式
版
第1版
改訂
コマ
全14

DKIM を、秘密鍵と公開鍵の関係から説明します。要約(ハッシュ)と署名の作り方、DKIM-Signature ヘッダーの読み方、公開鍵を置く DNS の名前とセレクタ、受け取る側の確かめ方、署名で分かる2つのこと、改ざんと転送、そして DKIM に残る穴まで。

DKIM:メールそのものに、送り主の印を押す

5本目の SPF は、「どこから来たか」(送信元の番号)を確かめる仕組みでした。そのため、転送されて経路が変わると壊れてしまいます。

この作品で見る DKIM(DomainKeys Identified Mail)は、考え方がまったく違います。経路ではなく、メールそのものに印を押す方式です。

昔の手紙で、封筒に封蝋を押して「確かに私が出した」と示したのに近いものです。印はメールと一緒に運ばれるので、どんな経路を通っても、受け取った人はその印を確かめられます。

ただし、封蝋と違って、DKIM の印は真似できません。その仕組みの土台が、次のページで見る「2つ1組の鍵」です。

  • メールのしくみ 6 / 11 ― DKIM:電子署名
  • 1 / 14
  • DKIM:メールそのものに、送り主の印を押す
  • SPF
  • DKIM
  • 経路を見る(どの番号から来たか)
  • 手紙そのものを見る(印があるか)
  • Resend → 大学 → Gmail
  • 署名
  • 経路が変わると SPF は壊れる
  • SPF は「どこから来たか」。DKIM は「手紙そのものに本物の印があるか」。

鍵を2つ1組で作る:秘密鍵と公開鍵

DKIM の印(電子署名)は、公開鍵暗号という仕組みで作ります。難しそうな名前ですが、使い方は次の3つの性質だけ押さえれば十分です。

性質意味
鍵は2つ1組で作る秘密鍵と公開鍵のペア
秘密鍵で作った印は、対の公開鍵でしか確かめられない別の鍵で作った印は「正しくない」と判定される
公開鍵から秘密鍵は作れないだから公開鍵は誰に見せてもよい

使い方はこうなります。送る側は秘密鍵を自分だけで大切に持ち、それで印を作ります。公開鍵は世界中に公開します。受け取った人は、公開鍵で印を確かめます。

印が正しいと判定されれば、「この印を作ったのは、対の秘密鍵を持っている人だ」と分かります。秘密鍵を持っているのは本人だけなので、本人が作った印だと言えるわけです。

  • メールのしくみ 6 / 11 ― DKIM:電子署名
  • 2 / 14
  • 鍵を2つ1組で作る:秘密鍵と公開鍵
  • 秘密鍵
  • 対
  • 公開鍵
  • 印を作る。送る側だけが持つ
  • 印を確かめる。誰に見せてもよい
  • 秘密鍵 + 手紙 → 印(署名)
  • 公開鍵 + 手紙 + 印 → 正しい / 正しくない
  • 印を作れるのは秘密鍵を持つ人だけ = 本人の証明
  • 秘密鍵で作った印は、対の公開鍵でしか確かめられない。公開鍵から秘密鍵は作れない。

署名の作り方:まず要約を作り、それに印を押す

実際の署名は、メール全体に直接印を押すのではなく、2段階で作ります。

最初に、メールの本文と主要なヘッダーから、要約(ハッシュ)を作ります。ハッシュは、どんなに長いデータからでも、決まった長さの短い値を作る計算です。

ハッシュには、DKIM にとって都合のいい性質が2つあります。

性質DKIM にとっての意味
元のデータが1文字でも違えば、まったく別の値になる書き換えがあれば必ず分かる
ハッシュから元のデータを作り直すことはできない要約を見ても中身は分からない

次に、この要約に秘密鍵で印を押します。これが署名です。

要約に印を押すのは、長いメール全体に直接印を押すより計算が軽いからです。それでいて、ハッシュの性質のおかげで、メールのどこか1文字でも変われば署名が合わなくなります。

  • メールのしくみ 6 / 11 ― DKIM:電子署名
  • 3 / 14
  • 署名の作り方:まず要約を作り、それに印を押す
  • 手紙
  • 要約(ハッシュ)
  • 署名
  • ヘッダーの一部 + 本文
  • 3f9a…c21e
  • 秘密鍵で要約に印
  • 1文字でも違えば、要約はまったく別の値になる
  • 要約から元の手紙を作り直すことはできない
  • 本文をそのまま署名せず、短い要約(ハッシュ)を作ってから秘密鍵で署名する。

署名は DKIM-Signature というヘッダーに入れて送る

作った署名は、メールのヘッダーに `DKIM-Signature` という欄を追加して、メールと一緒に送ります。

DKIM-Signature: v=1; a=rsa-sha256;
  d=mail.animemo.app; s=resend;
  h=from:to:subject:date:message-id;
  bh=(本文の要約); b=(署名そのもの)

主な項目の意味は次のとおりです。

項目意味
d=署名したドメイン。「このドメインとして署名しました」
s=セレクタ。どの鍵で署名したかの名札
h=署名に含めたヘッダーの一覧。From は必ず含める決まり
a=計算の方式
bh=本文の要約
b=署名そのもの

受け取る側にとって大事なのは d= と s= です。この2つから、「公開鍵をどこに取りに行けばいいか」が分かります(次のページ)。

h= に From が必ず入るのもポイントです。署名の後で From: を書き換えると、署名が合わなくなります。

  • メールのしくみ 6 / 11 ― DKIM:電子署名
  • 4 / 14
  • 署名は DKIM-Signature というヘッダーに入れて送る
  • DKIM-Signature: v=1; a=rsa-sha256;
  • d=mail.animemo.app; s=resend;
  • h=from:to:subject:date:message-id;
  • bh=(本文の要約); b=(署名そのもの)
  • d= / s=
  • 署名したドメインと、鍵の名札(セレクタ)
  • h=
  • 署名に含めたヘッダーの一覧(From は必ず入る)
  • bh= / b=
  • 本文の要約と、署名そのもの
  • d= と s= で「どこに公開鍵があるか」、h= で「どこを署名したか」を書いておく。

公開鍵は DNS の決まった名前に置く

受け取る側は、DKIM-Signature の s= と d= を使って、公開鍵が置いてある場所の名前を組み立てます。

(s= の値)._domainkey.(d= の値)
→ resend._domainkey.mail.animemo.app

真ん中の _domainkey は、「ここは DKIM の公開鍵の欄です」という決まった目印です。2本目で見たとおり、_ で始まる名前は機械の名前とぶつからないので、宣言専用の欄として使えます。

その名前の TXT を DNS で引くと、公開鍵が書かれています。

resend._domainkey.mail.animemo.app  TXT  "p=MIGfMA0GCSqGSIb3DQEB…"

ここで、2本目の「DNS は持ち主しか書けない」が効いてきます。この場所に公開鍵を置けるのは mail.animemo.app の持ち主だけです。つまり、ここにある公開鍵は、持ち主が「この鍵で署名されたメールは、うちのメールです」と認めた鍵です。

  • メールのしくみ 6 / 11 ― DKIM:電子署名
  • 5 / 14
  • 公開鍵は DNS の決まった名前に置く
  • resend
  • .
  • _domainkey
  • .
  • mail.animemo.app
  • s=(セレクタ)
  • 決まった目印
  • d=(署名したドメイン)
  • resend._domainkey.mail.animemo.app TXT "p=MIGfMA0GCSqGSIb3DQEB…"
  • 持ち主しか書けない場所に公開鍵がある = 持ち主が認めた鍵
  • s=resend と d=mail.animemo.app から、resend._domainkey.mail.animemo.app を引く。

送る側(Resend)が、送るたびに署名を付ける

ここから、5本目と同じ舞台に戻って、実際の流れを追います。

送る側の Resend は、mail.animemo.app 用の秘密鍵を保管しています。Animemo からメールを頼まれるたびに、次のことをします。

1通ずつ、本文と主要なヘッダーから要約を作ります。その要約に秘密鍵で署名します。DKIM-Signature のヘッダーに d=mail.animemo.app; s=resend と署名を書いて、メールに追加します。そして送ります。

図の封筒に「署名: d=mail.animemo.app」の行が増えたのがこれです。この時点で、受け取る側の検査欄では、SPF はすでに合格しています(5本目)。DKIM はまだ確かめていません。

  • メールのしくみ 6 / 11 ― DKIM:電子署名
  • 6 / 14
  • 送る側(Resend)が、送るたびに署名を付ける
  • 送信サーバー
  • 受信サーバー
  • Resend(Amazon SES)
  • Gmail
  • 封筒: send.mail.animemo.app
  • 送信元IP: Amazon SES のもの
  • From: [email protected]
  • 秘密鍵で署名する
  • 署名: d=mail.animemo.app
  • SPF
  • DKIM
  • animemo.app の掲示板(TXT)
  • send.mail.animemo.app v=spf1 include:amazonses.com ~all
  • resend._domainkey.mail.animemo.app p=MIGfMA0GCSq…(公開鍵)
  • 秘密鍵は Resend だけが持つ。署名のドメインは d=mail.animemo.app。

受け取る側は、DNS の公開鍵で署名を確かめる

受け取った Gmail は、次の順で DKIM を確かめます。

順番やること
1DKIM-Signature から d=mail.animemo.app と s=resend を読む
2resend._domainkey.mail.animemo.app の TXT から公開鍵を取ってくる
3届いたメールから、自分で要約を作り直す
4公開鍵を使って、署名が「その要約に対して、対の秘密鍵で押されたものか」を確かめる

すべて合えば、DKIM は合格(pass)です。

作り直した要約が送る側の要約と一致するのは、途中でメールが1文字も変わっていないときだけです。そして署名を確かめられるのは、対の秘密鍵で押されたときだけです。この2つが同時に成り立ったことになります。

  • メールのしくみ 6 / 11 ― DKIM:電子署名
  • 7 / 14
  • 受け取る側は、DNS の公開鍵で署名を確かめる
  • 送信サーバー
  • 受信サーバー
  • Resend(Amazon SES)
  • Gmail
  • 封筒: send.mail.animemo.app
  • 送信元IP: Amazon SES のもの
  • From: [email protected]
  • 秘密鍵で署名する
  • 署名: d=mail.animemo.app
  • SPF
  • DKIM
  • animemo.app の掲示板(TXT)
  • send.mail.animemo.app v=spf1 include:amazonses.com ~all
  • resend._domainkey.mail.animemo.app p=MIGfMA0GCSq…(公開鍵)
  • 要約を自分で作り直し、公開鍵で署名と突き合わせる。合えば合格。

署名が合えば、2つのことが同時に分かる

DKIM が合格したとき、受け取る側が分かることを整理します。

1つ目:`mail.animemo.app` の持ち主が認めた送り手が送った。 公開鍵を DNS に置けるのは持ち主だけで、対の秘密鍵を持っているのは Resend だけです。だから、この署名を作れたのは「持ち主が鍵を預けた相手」だけです。

2つ目:途中で書き換えられていない。 1文字でも変われば要約が変わり、署名と合わなくなります。

一方で、分からないこともあります。画面に出る `From:` のドメインが、署名したドメイン(`d=`)と同じかどうかです。DKIM は「d= に書いたドメインとして、正しく署名されている」と言っているだけです。この点は後の「DKIM の穴」で見ます。

  • メールのしくみ 6 / 11 ― DKIM:電子署名
  • 8 / 14
  • 署名が合えば、2つのことが同時に分かる
  • mail.animemo.app の持ち主が認めた送り手が送った
  • (その公開鍵を DNS に置けるのは持ち主だけ。対の秘密鍵を持つのは Resend だけ)
  • 途中で書き換えられていない
  • (1文字でも変えれば要約が変わり、署名と合わなくなる)
  • 画面の From と同じドメインか ― は見ていない
  • 持ち主が認めた送り手が送ったこと。途中で書き換えられていないこと。

書き換えられたメールは、署名が合わない

途中で誰かがメールを書き換えたとします。たとえば、本文のリンクを偽のサイトへ差し替えた場合です。

受け取る側が要約を作り直すと、送る側が署名したときの要約とは別の値になります。署名は合わず、DKIM は不合格(fail)になります。SPF は経路の話なので合格したままでも、DKIM が改ざんを見つけてくれます。

ただし、書き換えが善意でも壊れる点には注意が必要です。メーリングリストのように、転送するときに件名に [お知らせ] を足したり、本文の末尾に案内文を足したりする仕組みを通ると、DKIM は合わなくなります。

「DKIM が fail = 必ず偽物」とは限らないのはこのためです。受け取る側は、DKIM だけで決めずに、ほかの結果(7本目の DMARC や、8本目の評判)と合わせて判断しています。

  • メールのしくみ 6 / 11 ― DKIM:電子署名
  • 9 / 14
  • 書き換えられたメールは、署名が合わない
  • 送信サーバー
  • 受信サーバー
  • Resend(Amazon SES)
  • Gmail
  • 封筒: send.mail.animemo.app
  • 送信元IP: Amazon SES のもの
  • From: [email protected]
  • 本文が途中で書き換えられた
  • SPF
  • 例: メーリングリストが末尾に案内文を足す
  • DKIM
  • animemo.app の掲示板(TXT)
  • send.mail.animemo.app v=spf1 include:amazonses.com ~all
  • resend._domainkey.mail.animemo.app p=MIGfMA0GCSq…(公開鍵)
  • リンクを差し替えるような改ざんを見つけられる。ただし善意の書き換えでも壊れる。

署名はメールと一緒に運ばれるので、転送に強い

では、単純な転送ではどうでしょうか。5本目で、大学のメールから Gmail へ自動転送されると SPF が落ちる、という例を見ました。

普通の自動転送は、メールの中身を書き換えずにそのまま次へ渡します。DKIM の署名はメールそのものに付いているので、経路が変わっても署名はそのまま残ります。受け取った Gmail が確かめれば、DKIM は合格します。

図の検査欄では、SPF は不合格、DKIM は合格になっています。これで、SPF の穴②(転送に弱い)は DKIM が補えるようになりました。

  • メールのしくみ 6 / 11 ― DKIM:電子署名
  • 10 / 14
  • 署名はメールと一緒に運ばれるので、転送に強い
  • 転送サーバー
  • 受信サーバー
  • 大学のメール
  • Gmail
  • 封筒: send.mail.animemo.app
  • 送信元IP: 大学のサーバー
  • From: [email protected]
  • Resend → 大学 → Gmail
  • 署名: d=mail.animemo.app
  • SPF
  • DKIM
  • animemo.app の掲示板(TXT)
  • send.mail.animemo.app v=spf1 include:amazonses.com ~all
  • resend._domainkey.mail.animemo.app p=MIGfMA0GCSq…(公開鍵)
  • 転送で SPF が落ちても、DKIM は残る。これが SPF の穴②を埋める。

DKIM の穴:署名のドメインと From が別でも合格する

ここまでで、DKIM はかなり頼もしく見えます。ところが、DKIM にも穴があります。

DKIM の署名に書かれるドメイン(d=)は、手紙の From: のドメインと同じである必要がありません。

図のなりすましは、自分のドメイン evil.example 用に鍵を作り、公開鍵を自分の掲示板に置き、本物の署名を付けています。自分のドメインなので、正しい手順で作れてしまいます。DKIM は合格します。SPF も、5本目で見たとおり合格します。

それでいて、手紙の From: には 〇〇銀行 <[email protected]> と書いてあります。

SPF も DKIM も、「何かのドメインの身元」は確かめてくれます。でも、それが画面に出ている差出人と同じドメインかどうかは、どちらも見ていません。これが最後に残った穴で、7本目の DMARC がこれを塞ぎます。

  • メールのしくみ 6 / 11 ― DKIM:電子署名
  • 11 / 14
  • DKIM の穴:署名のドメインと From が別でも合格する
  • なりすまし
  • 受信サーバー
  • evil.example
  • Gmail
  • 封筒: evil.example
  • 送信元IP: evil.example の機械
  • From: 〇〇銀行 <[email protected]>
  • 署名: d=evil.example
  • SPF
  • 署名は本物。From とは別のドメイン
  • DKIM
  • evil.example の掲示板(TXT)
  • (セレクタ)._domainkey.evil.example p=…(自分の公開鍵)
  • evil.example の本物の署名を付けたまま、From に銀行と書ける。

セレクタがあるから、鍵を複数持てる・入れ替えられる

最後に、セレクタ(s=)がなぜあるのかを見ておきます。

1つ目の理由は、1つのドメインで複数のサービスから送るためです。mail.animemo.app から Resend でも Google Workspace でも送る場合、それぞれのサービスが自分の秘密鍵で署名します。鍵が別なので、公開鍵も別々に置く必要があります。セレクタで名前を分ければ、resend._domainkey と google._domainkey のように並べて置けます。

2つ目の理由は、鍵の入れ替えです。同じ鍵を何年も使い続けると、漏れたときの被害が大きくなります。そこで定期的に新しい鍵に替えます。このとき、新しいセレクタで公開鍵を先に追加し、署名を新しい鍵に切り替えてから、古いセレクタの公開鍵を消します。こうすれば、切り替えの途中でも、どちらの鍵で署名されたメールも確かめられます。

受け取る側は、署名の s= を見るだけで、どの鍵で確かめればよいかが分かります。

  • メールのしくみ 6 / 11 ― DKIM:電子署名
  • 12 / 14
  • セレクタがあるから、鍵を複数持てる・入れ替えられる
  • mail.animemo.app の掲示板(DKIM の公開鍵)
  • resend._domainkey  TXT p=…(Resend の鍵)
  • google._domainkey  TXT p=…(Google Workspace の鍵)
  • s2._domainkey    TXT p=…(入れ替え用の新しい鍵)
  • 署名の s= を見れば、どの鍵で確かめればよいかが分かる
  • サービスごとに別の名札。鍵を替えるときは新しい名札を足してから古いほうを消す。

Resend では、秘密鍵を見ることすらない

ここまで読むと、「秘密鍵の管理が大変そう」と感じるかもしれません。Resend を使う場合、その心配はほとんどありません。

Resend にドメインを登録すると、Resend が鍵のペアを作り、秘密鍵は Resend の中に保管されます。こちらの画面には公開鍵だけが表示され、「この値を resend._domainkey.mail という名前の TXT に入れてください」と案内されます(10本目)。

こちらがやるのは、その公開鍵を DNS に写すことだけです。一度入れれば、あとは送るたびに Resend が自動で署名を付けます。

秘密鍵が自分の手元に無いということは、自分のサーバーから秘密鍵が漏れる心配もないということです。DKIM の仕組みのうち、いちばん繊細な部分を丸ごと任せられるのは、送信サービスを借りる大きな利点の1つです(9本目)。

  • メールのしくみ 6 / 11 ― DKIM:電子署名
  • 13 / 14
  • Resend では、秘密鍵を見ることすらない
  • Resend
  • p=…
  • あなた
  • 秘密鍵を保管し、送るたびに署名
  • 公開鍵を DNS に写す(1回だけ)
  • 秘密鍵が自分の手元に無い = 漏らす心配もない
  • やるのは、画面に出た公開鍵を DNS に写すことだけ。署名は Resend が毎回付ける。

まとめ:DKIM

この作品で見たことをまとめます。

項目内容
何をするかメールそのものに電子署名を付ける
仕組み秘密鍵で要約に印を押し、DNS の公開鍵で確かめる
公開鍵の場所セレクタ._domainkey.署名したドメイン の TXT
分かること持ち主が認めた送り手が送った。途中で書き換えられていない
強み経路が変わっても残る(SPF の穴②を補う)
弱みメーリングリストなどの書き換えで壊れる
穴署名のドメイン(d=)と画面の From: が別でも合格する
Resend では秘密鍵は Resend が持つ。こちらは公開鍵を DNS に写すだけ

SPF と DKIM は、どちらも「何かのドメインの身元」を確かめます。残った穴は、「それが画面の差出人と同じか」です。次の作品で、その穴を塞ぐ DMARC を見ていきます。

  • メールのしくみ 6 / 11 ― DKIM:電子署名
  • 14 / 14
  • まとめ:DKIM
  • 見るもの
  • メールに付いた電子署名
  • 公開鍵の場所
  • セレクタ._domainkey.署名したドメイン
  • 分かること
  • 持ち主が認めた送り手・改ざんなし
  • 強み
  • 転送されても残る(SPF の穴②を補う)
  • 穴
  • 署名のドメインと From が別でもよい
  • DKIM は転送に強いが、From との一致は見ない。その最後の穴を DMARC が塞ぐ。

0 件のコメント

読み込み中…

権利侵害・不適切な内容の連絡: [email protected]