SPF、DKIM、DMARCに立ち向かう(送信側)

掲載日
更新日

はじめに

自分も数年前にサーバー構築して初めて知りましたが、メールの送信はかなり緩いです。
例えば、以下のコマンドを使用するとgmailのメールサーバーじゃないのに「virus@gmail.com」というメールアドレスで任意のアドレス宛にメールを送れてしまいます。

echo 'Test' | sendmail example@example.com -f virus@gmail.com

そういう訳で、セキュリティを気にする場合受信サーバー側でいろいろと確認する必要があり、そのために必要なのがSPF、DKIM、DMARCになります。
Gmailに送ろうと思ったら少なくともSPFとDKIMどちらかは必須(両方必須?試したらspfだけで迷惑メールに入らず受信できることも、DKIMがないとダメなこともあり。本文の内容なども見ていると思うので、明確な基準は不明です。)なようです。

今回はサーバーから送るメールを、迷惑メールボックスに入れられないようにするための、SPF、DKIM、DMARCの詳細と対策の備忘録です。

postfix install

まずはサーバーでメールを送れるようにします。(※AlmaLinux9環境)

yum install postfix
vi /etc/postfix/main.cf
  # 以下の箇所を変更 
  myhostname = awatana.com # 任意のホスト名
  mydomain = awatana.com # 任意のドメイン名
  myorigin = $mydomain

systemctl start postfix

SPF(Sender Policy Framework)

DNSの設定のみです。
以下のレコードを追加します。(XXX.XXX.XXX.XXXはメール送信するサーバーのIP)

awatana.com. IN TXT "v=spf1 +ip4:XXX.XXX.XXX.XXX -all"

セキュリティがちゃんとしている受信サーバーでは、メール送信元のドメインとIPを検証します。
送信元アドレスのドメインに対して、「このIPからメール来てるけど、本当にこのドメインとIPの対応あってるの?」という確認を行います。
その際に見るのがこのspfレコードで、ここに記載がない場合、なりすましの可能性ありとして迷惑メールに入れる…という流れだと思います(間違ってるかも)。

IP偽装で突破できるという問題もあるようです。
※なお、spfレコードの書き方・書式は色々あるみたいなので、用途に合わせて別途書き換えが必要です。

レコードが追加出来たら、こちらのサイトにドメインを入力して記述に問題がないかチェックができます。

DKIM(DomainKeys Identified Mail)

みんな大好き公開鍵を使います。
こちらはDNSの設定だけではなくサーバー側で認証用の鍵を作成する必要があり、

  1. まずDNSに登録する公開鍵と秘密鍵を作成します。
  2. DNS に1で作成した公開鍵を登録します。
  3. メールを出すときに1で作成した秘密鍵で署名します。
  4. 受信メールサーバー側で2に登録されている公開鍵で認証を行います。
    認証NGならなりすましという判定。

 

これならIP偽装しても秘密鍵を持ってないのでなりすましが出来ないので安心という仕組み。

公開鍵と秘密鍵を作成

公開鍵と秘密鍵を作成します。そのためにまずopendkimをインストールします。

yum install -y epel-release
yum install -y opendkim opendkim-tools

なお、ここでコンフリクトエラーが出ることがあります。
その場合almalinux-crb.repoのenabledを1に変更して、再度yum installします。

vi /etc/yum.repos.d/almalinux-crb.repo
→
[crb]
name=AlmaLinux $releasever - CRB
mirrorlist=https://mirrors.almalinux.org/mirrorlist/$releasever/crb
# baseurl=https://repo.almalinux.org/almalinux/$releasever/CRB/$basearch/os/
enabled=1 # 0 -> 1
gpgcheck=1
countme=1
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-AlmaLinux-9
metadata_expire=86400
enabled_metadata=0

設定・インストールが出来たら鍵を配置するためにディレクトリを作成。
(keys配下に直接配置しても問題ないと思います。複数管理する可能性があるのでドメイン名でディレクトリ作成しています。)

mkdir /etc/opendkim/keys/awatana.com

鍵を作成します。

opendkim-genkey -D /etc/opendkim/keys/awatana.com/ -d awatana.com -b 2048
# -D 鍵を出力する先のディレクトリ
# -d ドメイン
# -b ビット 生成されるキーのサイズ(デフォルトだと1024bitだが、暗号強度が高いのは2048bit)

chown -R opendkim:opendkim /etc/opendkim/keys/

そうするとdefault.txtファイルと、default.privateファイルが指定ディレクトリ配下に出力されます。
(言うまでもないですが、private拡張子の方は秘密鍵なので扱い注意。)

default.txtの中身をDNSに登録します。
ホスト名はdefault._domainkey.[任意のドメイン名]とし、"v=DKIM1 ... AQAB" までをVALUEに登録します。

cat /etc/opendkim/keys/awatana.com/default.txt
default._domainkey IN TXT ( "v=DKIM1; k=rsa; "          "p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAy9qfhh+9ngAdCpTVmxy9KHNkgZwSjZsp4NfMV+0zZ0+K8vVWDpo8/MhfVoemYjpLCASwX7yyufXWMbdRNs3rhiulNpEFhopT2AJyhe9BdcyvR/MEQoa+HMeEE+SCqQ0Z8cgkXdEQdGhrw807KjAjTlxoQ+gCsvRn1okXJ6OproJrzvfD/ol/RuIcyaGiQl/OG5ZSKpM4SBPyFC"
"DH73T9l9apZ45Vlo6uyoj9tOOAwx9VFn5U98rqMPWoVKPuV+EgrR0DhmVmDKVHMlM/Sc/vHY8JzM5CJLHCsYPm3Rb4AWR4bMcDGNrKnc2IUcf+0NWPCQkax9S2iNkmCo0AM43PAwIDAQAB" )  ; ----- DKIM key default for awatana.com

 DNSレコードには文字数の制限があり、公開鍵は2048bitで作成するので超過します。
複数レコードを登録する必要があるためダブルコーテーション(")で区切ってあるみたいですが、自分はお名前.comを使っているので、ダブルコートを削除して一行にして以下の状態にして登録しました。

v=DKIM1; k=rsa; p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAy9qfhh+9ngAdCpTVmxy9KHNkgZwSjZsp4NfMV+0zZ0+K8vVWDpo8/MhfVoemYjpLCASwX7yyufXWMbdRNs3rhiulNpEFhopT2AJyhe9BdcyvR/MEQoa+HMeEE+SCqQ0Z8cgkXdEQdGhrw807KjAjTlxoQ+gCsvRn1okXJ6OproJrzvfD/ol/RuIcyaGiQl/OG5ZSKpM4SBPyFCDH73T9l9apZ45Vlo6uyoj9tOOAwx9VFn5U98rqMPWoVKPuV+EgrR0DhmVmDKVHMlM/Sc/vHY8JzM5CJLHCsYPm3Rb4AWR4bMcDGNrKnc2IUcf+0NWPCQkax9S2iNkmCo0AM43PAwIDAQAB

※登録後はチェックツールで問題無いかチェックできます。

実際に署名できるようにする

DNSの設定と鍵の作成が出来たので、今度は実際にメールを送る際に署名するようにします。
こちらのサイトを参考に、まずopendkimの設定を変更します。

vi /etc/opendkim.conf
# -> 以下をそれぞれ修正 
 # s (sign) : 署名、v (verify): 検証 でデフォルトだとv(検証)のみ
 Mode v -> Mode s
 # コメント解除
 KeyTable        /etc/opendkim/KeyTable
 SigningTable    refile:/etc/opendkim/SigningTable 
 # 追加
 Socket  inet:8891@localhost # *1
vi /etc/opendkim/SigningTable
 # *@[ドメイン名] default._domainkey.[ドメイン名] のフォーマットで追記
 *@awatana.com default._domainkey.awatana.com
vi /etc/opendkim/KeyTable
 # [セレクタ名]._domainkey.[ドメイン名] [ドメイン名]:[セレクタ名]:[秘密鍵へのパス]のフォーマットで追記
 default._domainkey.awatana.com awatana.com:default:/etc/opendkim/keys/awatana.com/default.private

編集出来たら以下のコマンドでサービス開始(既に開始してる場合はrestartで設定リロード)

systemctl start opendkim

続いてpostfix側の設定を追記します。

vi /etc/postfix/main.cf
# 以下を追記
smtpd_milters = inet:127.0.0.1:8891 # *1と合わせる
non_smtpd_milters = $smtpd_milters
milter_default_action = accept

postfixをstartもしくはrestartします。

systemctl restart postfix

ここで記事トップのsendmailコマンドを送ると、署名付きで送れます。

DMARC(Domain based Message Authentication, Reporting&Conformance)

SPF、DKIMチェックしてその後どうするかの宣言になります。
宣言なので、大変なのは受信側の処理で、送信側はDNSレコードを追加するのみ。
以下を追加します。

_dmarc.awatana.com. 360 IN TXT "v=DMARC1; p=quarantine; rua=mailto:dmarc-rua-report@awatana.com; ruf=mailto:dmarc-ruf-report@awatana.com; ri=86400; adkim=s; aspf=s;"

各パラメータの説明はGoogleの「DMARCを設定する」ページが詳しくて分かりやすいです。
必須なのは「v=DMARC1」(バージョン)と「p=none(何もしない) or quarantine(迷惑メールに入れる)  or reject(受信を拒否)」の設定のみ。

このpの設定を見て、受信側が(そういう処理を実装していれば)指定の通りに対応してくれる、ということだと思います。(受信側もいつかはちゃんと整備したい。)
pはnoneにして動作確認を行い、問題なければquarantineもしくはrejectに変更するのが良いようです。

レコードに問題あるかのチェックサイトもあります。

動作確認(Gmailで受信する場合)

最後にメールを送って動作確認します。

# XXXXには任意の自分のメールアドレス
echo 'Test' | sendmail XXXX@gmail.com -f root@awatana.com

上記のコマンドでメールを送信し以下の操作を行います。

  • メール右上のハンバーがメニューをクリック
  • 以下の画像のように「原文を表示」をクリック
  • メールのヘッダー等詳細が見られる画面が開くので、
    SPF、DKIM、DMARCがそれぞれ「PASS」になっていることを確認します。
    (failになっている場合、何か設定が誤っている可能性があるので見直しましょう。)

 

GmailでSPF,DKIM,DMARCチェックするスクリーンショット

おわりに

これでサーバーからなりすましの対策をして安全にメールが送れるようになりました。
このCMSでは、定期的にサイトを巡回してリンクの404チェックを行い、管理者にメールで通知するようにしたいと思っているのでその準備がようやく出来たという感じです。

メール本文は生成AIの発達でどんどん不自然さが無くなっているので、特にDKIMのようなセキュリティを維持する仕組みはこれから大事になりそうです。

参考リンク

  • ベアメール
    ほとんどこちらのサイトの設定方法を参考にしています。多謝。
  • mxToolBox
    タブを切り替えてSPF、DKIM、DMARC全部チェックできます。
    設定が出来ているか、記述が正しいかだけでなく、セキュリティの強度もチェックしてくれます
    (DMARCのpの値をnoneにしていたらエラーを出してくれました。)
    その他にもメール関係の色々をチェックできます。
    (自分のアドレスがブラックリストに入っているか等も見れます。)
記事の作成者のA.W.のアイコン

この記事を書いた人

A.W.
茨城県在住Webエンジニアです。 PHPなどを業務で使用しています。 趣味ではGoやNuxt、Flutterをやってます。

Comment