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?

DMARCのサブドメインポリシーはspで決まる: gmail.comのサブドメインをp=noneと誤表示した話

0
Posted at

自作のDMARCチェッカーにnews.gmail.comを入れたら、結果は「p=none」でした。gmail.comのレコードにはsp=quarantineがはっきり書いてあるのに、です。原因は、DMARCのsp、つまりサブドメインポリシーの継承を読み違えていたことでした。

何が問題だったのか

DMARCチェッカーを使う人が知りたいのは「このドメインを名乗るなりすましメールを、受信側にどう扱ってほしいと宣言しているか」です。noneなら受信側に処置を求めない。quarantineなら疑わしいメールとして扱う(迷惑メールフォルダに入れるなど)よう求める。表示がnoneなら、読み手は「このドメインは保護されていない」と判断してしまいます。

サブドメインに専用のDMARCレコードがなければ、答えは継承で決まります。組織ドメインのspがpと違う場合、継承を間違えたツールはそのサブドメインすべてで違う答えを出します。gmail.comはまさにそのケースでした。

考えられる原因を順に消す

p=noneと出たとき、考えられる原因は3つあります。

  1. リゾルバのキャッシュが古い
  2. _dmarc.news.gmail.comに別のレコードがあり、それを読んでいる
  3. google.comなど、別の組織ドメインのレコードを読んでいる

②と③はDNSを直接引けば確かめられます。2026年11月3日にdns.googleのJSON APIで確認した値がこちらです。

名前 TXT / 結果
_dmarc.gmail.com v=DMARC1; p=none; sp=quarantine; rua=mailto:mailauth-reports@google.com
_dmarc.google.com v=DMARC1; p=reject; rua=mailto:mailauth-reports@google.com
_dmarc.news.gmail.com Status 3(NXDOMAIN)
news.gmail.com(A) Status 3(名前が存在しない)
mail.gmail.com(A) Status 3(名前が存在しない)

少なくとも、サブドメイン側にレコードはありません。news.gmail.comという名前自体がDNS上に存在しないからです。google.comはp=rejectなので、③ならrejectと出るはずです。p=noneという値を持つのは_dmarc.gmail.comだけなので、読む場所は合っていて、読んだあとの処理が間違っていたことになります。

原因: pだけを見ていた

原因は、継承の際に組織ドメインのpをそのまま返していたことです。考え方としてはこうなっていました。

// 誤った継承(簡略化した例)
function inheritedPolicy(orgRecord) {
  return orgRecord.p;
}

gmail.comはp=noneなので、結果はnone。組織ドメイン自身に対するポリシーとしては正しい値ですが、サブドメインに効くのはspのほうです。

サブドメインポリシーはspとnpで決まる

DMARCの仕様は2026年5月にRFC 9989として改訂され、RFC 7489とRFC 9091を置き換えました。4.7節のタグ定義を要約すると、こうなります。

  • sp: 組織ドメインのサブドメインに対するポリシー。spがなく、npもない(または該当しない)場合はpを使う
  • np: 「存在しない」サブドメインに対するポリシー(定義は3.2.13節)。npがなければsp、それもなければp

どの組織ドメインのレコードを見るかは、4.10節のDNS Tree Walkで決まります。継承の順番は、名前が存在するかどうかで分岐します。正しい順番をコードにすると、次のようになります。これも説明用に簡略化した例で、ツールに入っているのはsp→pの部分までです。

// RFC 9989 4.7節に沿った継承(npの分岐はツールには未実装)
function inheritedPolicy(orgRecord, nameExists) {
  if (!nameExists && orgRecord.np) {
    return { policy: orgRecord.np, from: 'np' };
  }
  if (orgRecord.sp) {
    return { policy: orgRecord.sp, from: 'sp' };
  }
  return { policy: orgRecord.p, from: 'p' };
}

fromを一緒に返しているのは、画面に「どのタグから来た値か」を出すためです。これがあれば、今回のようなずれに利用者自身が気づけます。

news.gmail.comは厳密にはnpのケース

news.gmail.comはDNS上に存在しないので、RFC 9989の言葉では「存在しないサブドメイン」、つまりnpの対象です。

gmail.comのレコードにはnpがありません。そのため、次のsp=quarantineが使われます。存在するサブドメインなら最初からspです。どちらの道を通っても答えはquarantineで、noneではありません。

直したことと確かめ方

修正後は、同じく存在しないサブドメインのmail.gmail.comで確認しました。説明文はこう表示されます。

No DMARC record at _dmarc.mail.gmail.com, so receivers use the organizational domain's record at _dmarc.gmail.com: its sp= (subdomain policy), or p= when there is no sp= (RFC 7489).

適用ポリシーの欄は「inherited from gmail.com, sp=quarantine」です。

ただし、修正はまだ途中です。説明文は置き換え前のRFC 7489を参照したままで、npの分岐も入っていません。gmail.comのようにnpを置いていないドメインでは結果は同じですが、npを設定しているドメインでは、存在しない名前に対して違う答えを出す可能性があります。このDMARCチェッカーはMyIPScanで公開しています(MyIPScanは私が作ったサイトです)。

手元で同じ確認をしたい場合は、digで十分です。

dig +short TXT _dmarc.news.gmail.com   # 何も返らない
dig news.gmail.com A                   # status: NXDOMAIN
dig +short TXT _dmarc.gmail.com
# "v=DMARC1; p=none; sp=quarantine; rua=mailto:mailauth-reports@google.com"

1行目でサブドメインにレコードがないこと、2行目で名前自体があるかないかを確かめ、3行目で組織ドメインのタグを読みます。この3つで、どのタグが効くかは手で決められます。

まとめ: 継承するときはpを最後に見る

サブドメインのDMARCポリシーを継承するときは、存在する名前ならsp→p、存在しない名前ならnp→sp→pの順に見る。そして、どのタグから取った値かを必ず表示する。

pは組織ドメイン自身のためのタグです。サブドメインに対しては、npもspもないときの最後の候補です。

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?