0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【AWS SES メール認証・なりすまし対策③】Route 53で未使用サブドメインのメールなりすまし対策 ~Wildcard SPF・Null MX・Hosted Zone分離~

0
Posted at

はじめに

これまでの記事では、Amazon SESを利用したメール送信について、

  • 第1回:DMARCの p / sp / np
  • 第2回:SPF / DKIM / Custom MAIL FROM

を整理しました。

今回の構成では、本番・STGから次のドメインを使ってメールを送信します。

本番:sample.com
STG :stg.sample.com

正規のメール送信については、SES・SPF・DKIM・DMARCを設定することで対策できます。

しかし、まだ気になるケースがあります。

例えば、

dummy.sample.com
test.sample.com
hoge.sample.com

のような、実際にはメール送信に使用していないサブドメインです。

攻撃者が、

From: attacker@dummy.sample.com

のようなメールを送信することも考えられます。

そこで今回は、Route 53上で、

*.sample.com TXT "v=spf1 -all"
*.sample.com MX  0 .

といったWildcard DNSレコードを利用し、未使用サブドメインのメール利用を明示的に制限する方法を整理します。

さらに、

sample.com
└─ stg.sample.com

を別のRoute 53 Hosted Zoneに分離している場合についても確認します。

Wildcard SPFやNull MXだけでHeader Fromのなりすましを防げるわけではありません。

第1回で設定したDMARCと組み合わせることが重要です。

今回の構成

まず、Hosted Zoneを1つだけ使用している場合を考えます。

今回の基本的なDMARC設定は次のとおりです。

_dmarc.sample.com
TXT "v=DMARC1; p=none; sp=reject; np=reject;"

つまり、

sample.com
→ p=none

存在するサブドメイン
→ sp=reject

存在しないサブドメイン
→ np=reject

という設計です。

さらにDNS側でも、メール送信に使用しないサブドメインについて明示的に制限していきます。

Wildcard SPFを設定する

まずSPFです。

今回、未使用サブドメインについて、

*.sample.com
TXT "v=spf1 -all"

を設定します。

-all は、

このドメインからメールを送信することを許可された送信元は存在しない

というポリシーです。

例えば、

dummy.sample.com

に個別のDNSレコードが存在しない場合、Wildcardによって、

dummy.sample.com
TXT "v=spf1 -all"

相当の応答を返せます。

SPFの仕様でも、メールを送信しないドメインに、

v=spf1 -all

を公開することはベストプラクティスとして示されています。

~all と -all の違い

第2回でAmazon SESのCustom MAIL FROMには、

v=spf1 include:amazonses.com ~all

を設定しました。

一方、未使用サブドメインには、

v=spf1 -all

を設定します。

違いを整理すると、

設定 意味
~all SPF SoftFail
-all SPF Fail

例えば、

mail.sample.com

はAmazon SESから正規にメールを送信するため、

v=spf1 include:amazonses.com ~all

とします。

一方、

dummy.sample.com

などは一切メールを送信しないので、

v=spf1 -all

です。

イメージとしては、

sample.com
│
├─ mail.sample.com
│    └─ SESから送信する
│       v=spf1 include:amazonses.com ~all
│
└─ その他の未使用サブドメイン
     └─ メール送信しない
        v=spf1 -all

となります。

Wildcardより個別レコードが優先される

ここで気になるのが、

*.sample.com
TXT "v=spf1 -all"

を設定すると、

mail.sample.com

まで -all になってしまわないか、という点です。

Route 53では、具体的なドメイン名のレコードが存在する場合、Wildcardより具体的な名前が優先されます。

そのため、

*.sample.com
TXT "v=spf1 -all"

があっても、

mail.sample.com
TXT "v=spf1 include:amazonses.com ~all"

を明示的に設定していれば、mail.sample.com はこちらが使用されます。

つまり、

原則
*.sample.com
→ SPF -all

例外
mail.sample.com
→ SESを許可

という構成が可能です。

Null MXとは?

続いてMXレコードです。

未使用サブドメインには、

*.sample.com
MX 0 .

を設定します。

これを Null MX と呼びます。

Null MXは、

このドメインではメールを受信しない

ことを明示するための仕組みです。

RFC 7505で正式に定義されています。

通常のMXレコードは、

sample.com
MX 10 mail.example.com

のように、メールを受信するサーバーを指定します。

Null MXでは、

MX 0 .

とします。

. はメールサーバーが存在しないことを表します。

なぜMXがないだけではダメなのか

ここはNull MXを理解するうえで重要です。

例えば、

api.sample.com
A 192.0.2.10

が存在しているとします。

しかしMXレコードはありません。

一見すると、

MXがないからメールを受信しない

ように見えます。

ところがSMTPでは、MXレコードが存在しない場合、A / AAAAレコードのホストへ配送を試みる動作があります。

RFC 7505がNull MXを定義した理由の一つも、この挙動を明確にするためです。

そこで、

api.sample.com
MX 0 .

と明示すれば、

api.sample.com ではメールを受信しない

と宣言できます。

SPFとNull MXは役割が違う

ここも混同しやすいポイントです。

v=spf1 -all

と、

MX 0 .

では役割が違います。

設定 主な役割
SPF -all そのドメインをMAIL FROMとして送信するサーバーを許可しない
Null MX そのドメインではメールを受信しない
DMARC sp / np Header Fromを使ったDMARC失敗メールの処理方針

つまり、

それぞれ別の役割を持っています。

今回の構成では、これらを組み合わせます。


Wildcard SPF / MXをRoute 53へ設定する

Route 53では次の2レコードを作成します。

SPF

Record name:
*.sample.com

Record type:
TXT

Value:
"v=spf1 -all"

Null MX

Record name:
*.sample.com

Record type:
MX

Value:
0 .

整理すると、

*.sample.com
├─ TXT
│   └─ "v=spf1 -all"
│
└─ MX
    └─ 0 .

です。

MXとTXTは別々のDNSレコードです。

「MX/TXT」という1つのレコードを登録するわけではありません。

重要:Wildcardは「すべて」に必ず適用されるわけではない

今回、特に注意したいポイントです。

*.sample.com
TXT "v=spf1 -all"

を作れば、

sample.com配下すべてにSPF -all が付く

ように見えます。

しかし、DNSのWildcardはそれほど単純ではありません。

例えば、

api.sample.com
A 192.0.2.10

がすでに存在しているとします。

この場合、

api.sample.com

というDNS上の名前そのものが存在します。

そのため、

*.sample.com TXT

を使って、

api.sample.com TXT

を補完することはできません。

DNS Wildcardの仕様では、問い合わせ対象の名前自体が存在する場合、その名前に問い合わせ対象のレコードタイプがなくてもWildcardから合成されません。

SPFのRFCでも、Wildcard SPFを使用する場合、すでに何らかのDNSレコードを持っているホストにはSPF宣言を繰り返し設定する必要があると注意されています。

例えば api.sample.com はどうなる?

次の構成を考えます。

*.sample.com
TXT "v=spf1 -all"

api.sample.com
A 192.0.2.10

ここで、

api.sample.com TXT

を問い合わせても、

*.sample.com
TXT "v=spf1 -all"

が適用されるとは限りません。

api.sample.com 自体が存在するからです。

そのため、api.sample.com が絶対にメールを送信しないのであれば、

api.sample.com
TXT "v=spf1 -all"

を明示的に設定するのが確実です。

同じ考え方で、メールを受信しないのであれば、

api.sample.com
MX 0 .

も明示します。

api.sample.com
├─ A
│   └─ Web/API用途
│
├─ TXT
│   └─ v=spf1 -all
│
└─ MX
    └─ 0 .

Wildcardは「未定義の名前」をまとめてカバーする仕組みと考えた方が分かりやすいです。

Web/API用途などでDNS上すでに存在するサブドメインについては、必要に応じてSPF -all やNull MXを個別に設定します。

Wildcardを設定すると np はどうなる?

第1回では、DMARCを、

v=DMARC1; p=none; sp=reject; np=reject;

としました。

ここで、

dummy.sample.com

がDNS上存在しない場合、

np=reject

の対象になります。

RFC 9989では、DMARC上の「存在しないドメイン」は、DNS問い合わせで NXDOMAIN が返るものとして定義されています。

しかし、

*.sample.com
TXT "v=spf1 -all"

*.sample.com
MX 0 .

というWildcardを設定すると、

dummy.sample.com

への問い合わせにWildcardからDNSレコードが合成されます。

すると、DNS上は NXDOMAIN ではなくなります。

つまり、

Wildcardなし

dummy.sample.com
        ↓
NXDOMAIN
        ↓
np

だったものが、

Wildcardあり

dummy.sample.com
        ↓
WildcardからDNS応答
        ↓
DNS上存在する扱い
        ↓
sp

となるケースがあります。

DMARCでは、MXやAがなくても、何らかのRRが存在すれば「存在する」と判断します。

これが今回、

sp=reject
np=reject

を両方設定している理由の一つです。


今回の親Hosted Zoneの構成

ここまでを整理すると、sample.com Hosted Zoneには概ね次のような設定があります。

sample.com Hosted Zone
│
├─ _dmarc.sample.com
│   └─ TXT
│      v=DMARC1; p=none; sp=reject; np=reject;
│
├─ mail.sample.com
│   ├─ MX
│   │   10 feedback-smtp.ap-northeast-1.amazonses.com
│   │
│   └─ TXT
│       v=spf1 include:amazonses.com ~all
│
├─ SES DKIM
│   └─ CNAME × 3
│
└─ *.sample.com
    ├─ TXT
    │   v=spf1 -all
    │
    └─ MX
        0 .

さらに、Web/APIなどで既に存在するサブドメインについては、必要に応じて、

api.sample.com
TXT "v=spf1 -all"

api.sample.com
MX 0 .

を個別に設定します。

STGを別Hosted Zoneに分離する

次に、今回実際に確認したかったケースです。

現在は、

sample.com Hosted Zone

の中ですべて管理しているとしても、

将来的に、

stg.sample.com

を別Hosted Zoneへ分離する場合があります。

Route 53では、サブドメイン用に別Hosted Zoneを作成し、親Hosted ZoneからNSレコードで権限委譲できます。

構成は次のようになります。

親Hosted ZoneからNSを向ける

まず、

stg.sample.com

のHosted Zoneを作成します。

Route 53から4つのName Serverが割り当てられます。

例えば、

ns-xxx.awsdns-xx.com
ns-xxx.awsdns-xx.net
ns-xxx.awsdns-xx.org
ns-xxx.awsdns-xx.co.uk

です。

そして親側の、

sample.com Hosted Zone

に、

stg.sample.com
NS

レコードを作成し、子Hosted ZoneのName Serverを指定します。

これによって、

sample.com
        ↓
stg.sample.comは別DNSへ問い合わせ
        ↓
stg.sample.com Hosted Zone

という権限委譲が行われます。

STG配下のレコードは子Hosted Zoneで管理する

ここが最重要ポイントです。

stg.sample.com を別Hosted Zoneへ委譲した場合、

_dmarc.stg.sample.com
mail.stg.sample.com
xxxxx._domainkey.stg.sample.com
*.stg.sample.com

などのSTG配下のレコードは、

stg.sample.com Hosted Zone側で管理します。

AWSも、サブドメインを別Hosted Zoneへ分離した場合、そのサブドメイン以下のレコードを子Hosted Zoneで作成するよう案内しています。

つまり、

sample.com Hosted Zone
│
└─ stg.sample.com NS
        │
        ↓
stg.sample.com Hosted Zone
│
├─ _dmarc.stg.sample.com
├─ mail.stg.sample.com
├─ DKIM
└─ *.stg.sample.com

となります。

親のWildcardはSTG配下まで使える?

ここは注意が必要です。

親側に、

*.sample.com
TXT "v=spf1 -all"

*.sample.com
MX 0 .

が存在していても、

stg.sample.com

を別Hosted Zoneへ委譲すると、STG配下の問い合わせは子Hosted Zoneが権威を持ちます。

そのため、

dummy.stg.sample.com

をカバーしたいのであれば、STG Hosted Zone側にも、

*.stg.sample.com
TXT "v=spf1 -all"

*.stg.sample.com
MX 0 .

を設定します。

Route 53では、親から子Hosted ZoneへNSで委譲すると、リゾルバは子Hosted ZoneのName Serverへ問い合わせを行います。

つまり、

親
*.sample.com

だけに頼らず、

子
*.stg.sample.com

も用意する、という考え方です。

STG側の最終構成

STG Hosted Zoneは次のようになります。

stg.sample.com Hosted Zone
│
├─ _dmarc.stg.sample.com
│   └─ TXT
│      v=DMARC1; p=none;
│
├─ mail.stg.sample.com
│   ├─ MX
│   │   10 feedback-smtp.ap-northeast-1.amazonses.com
│   │
│   └─ TXT
│       v=spf1 include:amazonses.com ~all
│
├─ SES DKIM
│   └─ CNAME × 3
│
└─ *.stg.sample.com
    ├─ TXT
    │   v=spf1 -all
    │
    └─ MX
        0 .

これで、

mail.stg.sample.com
→ SESから正規送信

dummy.stg.sample.com
→ 原則SPF Fail / メール受信なし

という構成にできます。

親と子の両方に同じレコードを置かない

Hosted Zone分離でハマりやすいポイントです。

例えば、

sample.com Hosted Zone

と、

stg.sample.com Hosted Zone

の両方に、

mail.stg.sample.com

を残すような構成は避けます。

AWSも、親Hosted Zoneと子Hosted Zoneの両方に同一サブドメインのレコードが残っていると、DNSリゾルバがキャッシュしているName Serverによって挙動が不整合になる可能性があると注意しています。

基本的には、

親Hosted Zone
→ stg.sample.com のNSだけ持つ

子Hosted Zone
→ stg.sample.com配下の実レコードを持つ

という役割分担にします。

1つのHosted Zoneの場合と分離した場合

整理すると次のようになります。

Hosted Zoneを分けない

sample.com Hosted Zone
│
├─ sample.com
├─ mail.sample.com
├─ *.sample.com
├─ stg.sample.com
├─ mail.stg.sample.com
└─ *.stg.sample.com

すべて1つのHosted Zoneで管理します。


STG Hosted Zoneを分離

sample.com Hosted Zone
│
├─ sample.com
├─ mail.sample.com
├─ *.sample.com
│
└─ stg.sample.com NS
          │
          ↓
stg.sample.com Hosted Zone
│
├─ stg.sample.com
├─ mail.stg.sample.com
├─ _dmarc.stg.sample.com
├─ DKIM
└─ *.stg.sample.com

DMARCの考え方はどちらも同じです。

変わるのは、

どのDNSサーバーがそのレコードに対して権威を持つか

です。

今回の最終構成

本番とSTGを別Hosted Zoneにした場合、全体としては次のようになります。

設計方針としては、

正規メール送信用ドメイン
→ SES / SPF / DKIM / DMARCを明示

未使用サブドメイン
→ SPF -all
→ Null MX
→ DMARC sp / np=reject

別Hosted Zone
→ そのZone側で同じポリシーを設定

となります。

よくある勘違い

*.sample.com を設定すれば、存在するすべてのサブドメインにも適用される?

必ずしもそうではありません。

例えば、

api.sample.com A ...

が存在すると、api.sample.com 自体がDNS上存在するためWildcard TXT/MXが期待どおり使われないケースがあります。

必要なら、

api.sample.com TXT "v=spf1 -all"
api.sample.com MX 0 .

を明示します。

SPF -all を設定すればメールを受信しなくなる?

違います。

SPFは送信側の認証です。

メールを受信しないことを宣言するのはNull MXです。

Null MXを設定すればなりすましを防げる?

Null MXだけではHeader Fromのなりすまし対策にはなりません。

Header FromについてはDMARCが重要です。

np=reject があるならWildcard SPFはいらない?

役割が違います。

np はDMARC Policyです。

Wildcard SPFはMAIL FROMに対するSPF Policyです。

またWildcardを設定するとDNS上存在する名前として扱われ、DMARCでは np ではなく sp 側のポリシーになるケースもあります。

親に *.sample.com があれば *.stg.sample.com は不要?

stg.sample.com を別Hosted Zoneへ委譲している場合は、子Hosted Zone側にも設定します。

親Hosted ZoneにもSTGのレコードを残しておいた方が安全?

逆です。

委譲後はSTG配下のレコードを子Hosted Zoneへ集約した方が安全です。

親と子の両方に同じレコードを残すと、DNSの挙動が不整合になる可能性があります。

ここまでのポイント

今回のポイントを整理します。

  • メールを送信しないドメインには v=spf1 -all を設定できる
  • Null MX 0 . はメールを受信しないことを宣言する
  • SPF -all とNull MXは役割が違う
  • Header Fromのなりすまし対策にはDMARCも必要
  • Route 53ではWildcardより具体的な名前が優先される
  • DNS上すでに存在する名前にはWildcard SPFが効かないケースがある
  • 既存のWeb/APIサブドメインには必要に応じてSPF -all / Null MXを個別設定する
  • Wildcard DNSによってNXDOMAINでなくなると、DMARCの np ではなく sp の対象になる場合がある
  • sp=reject / np=reject の両方を設定しておく意味がある
  • stg.sample.com は別Hosted Zoneへ分離できる
  • 親Hosted ZoneからNSレコードで子Hosted Zoneへ委譲する
  • 委譲後はSTG配下のレコードを子Hosted Zoneで管理する
  • 親のWildcardに頼らず、子Hosted Zoneにも *.stg.sample.com を設定する
  • 親・子Hosted Zoneに同じSTGレコードを残さない

今回の検討を通して、

Wildcardを1つ設定すれば全部解決

というわけではない点が特に重要だと感じました。

DNS上すでに存在するサブドメインや、別Hosted Zoneへ委譲されたサブドメインについては、それぞれのDNS構成を理解したうえで設定する必要があります。

連載まとめ

今回の3回で、Amazon SESを利用したメール送信となりすまし対策について、

第1回
DMARC
p / sp / np
        ↓
第2回
Amazon SES
SPF / DKIM / Custom MAIL FROM
        ↓
第3回
Route 53
Wildcard SPF / Null MX / Hosted Zone分離

まで整理できました。

最終的には、

正規にメールを送信するドメインを明示的に認証し、それ以外のドメインについては送受信しないことをDNS・DMARC双方で明確にする

という設計になります。

SPF / DKIM / DMARCはそれぞれ役割が異なるため、一つの設定だけでなりすまし対策を完成させるのではなく、複数の仕組みを組み合わせて設計することが重要です。


参考資料

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?