# DNSスプーフィング・キャッシュポイズニングの仕組みと防御【2026】— RFC 5452 と DNSSEC で名前解決を守る

> 名前解決を乗っ取る DNS スプーフィング／キャッシュポイズニングを、Kaminsky 攻撃の原理から RFC 5452・DNSSEC（RFC 4033-4035）の防御まで体系的に解説。なぜ UDP の DNS は偽答を信じてしまうのか、送信元ポートランダム化・トランザクションIDがどう推測困難性を作るのか、そして DNSSEC の署名検証・DoH/DoT による暗号化までを、型安全なコードと設定例で示します。すべて自分のリゾルバに閉じた合法手順です。

- 公開日: 2026-06-28
- 著者: 友田 陽大
- タグ: セキュリティ, ネットワーク, TCP/IP, 脆弱性診断, ホワイトハッカー, 倫理的ハッキング
- URL: https://tomodahinata.com/blog/dns-spoofing-cache-poisoning-dnssec-defense-guide
- カテゴリ: 実践ネットワーク攻撃と防御
- 総合ガイド: https://tomodahinata.com/blog/network-penetration-testing-methodology-attack-defense-guide

## 要点

- DNSスプーフィングは名前解決を乗っ取り、正しいドメイン（bank.example）を攻撃者のIPへ向ける。キャッシュポイズニングはリゾルバのキャッシュに偽答を注入し、多数の利用者を一度に毒する
- 成立条件は『正規の応答より速く、正しい偽答を返す』こと。鍵は16ビットのトランザクションIDと送信元ポート。2008年の Kaminsky 攻撃はこの推測を現実的にし、DNS の作り直しを迫った
- RFC 5452 の防御は『推測を困難にする』——送信元ポートのランダム化(16ビット)とトランザクションIDの組み合わせでエントロピーを32ビット級に引き上げ、総当たりを非現実的にする
- 本質的な防御は DNSSEC（RFC 4033-4035）。権威サーバーが応答にデジタル署名し、リゾルバが署名を検証する。偽答は署名が合わず弾かれる＝『言った者勝ち』を暗号で終わらせる
- 通信路の防御は DoH/DoT（DNS over HTTPS/TLS, RFC 8484/7858）。リゾルバまでの経路を暗号化し盗聴・改ざんを防ぐ。DNSSEC（真正性）と DoH/DoT（機密性）は補完関係で両方要る

---

あなたがブラウザに `bank.example` と打ち込んだその瞬間、最初に起きるのは**名前解決**——ドメイン名をIPアドレスに変換する DNS の問い合わせです。もしこの一手を攻撃者に乗っ取られたら？ URL バーには正しいドメインが表示されたまま、**接続先だけが攻撃者のサーバーにすり替わります**。これが **DNSスプーフィング**であり、リゾルバのキャッシュごと毒する**キャッシュポイズニング**は、一度の成功で多数の利用者を巻き込む、極めて影響範囲の広い攻撃です。

この記事は、[ネットワークペンテストの全体像](/blog/network-penetration-testing-methodology-attack-defense-guide)に続き、DNS 攻撃の原理を歴史的な Kaminsky 攻撃から解き、**RFC 5452 と DNSSEC による防御**を設定とコードで示します。根本にあるのは、初期DNSが [UDP](/blog/tcp-vs-udp-quic-http3-difference-when-to-use-guide)上の「認証なき応答」を信じてしまうという、[TCP/IP の信頼の前提](/blog/tcp-ip-protocol-suite-fundamentals-complete-guide)です。

> **安全地帯の徹底**：本記事の検証は、すべて[隔離ラボ](/blog/ethical-hacking-home-lab-kali-juice-shop-ctf-self-study-roadmap-guide)の**自分が立てたDNSリゾルバ（例 BIND/Unbound のローカル実験機）**に対してのみ行います。**公開リゾルバや他者のDNSへ偽答を注入する行為は、不正アクセス禁止法違反であり、社会インフラへの攻撃**です。検証してよいのは自分の資産だけ——[法律の記事](/blog/ethical-hacker-law-japan-unauthorized-access-act-active-cyber-defense-disclosure-guide)を必ず先に。

---

## 1. DNS が騙される仕組み — 「速く・それらしい偽答」

キャッシュDNSリゾルバが `bank.example` の問い合わせを受け、まだキャッシュにない場合、上位の権威サーバーへ問い合わせます。攻撃者の狙いは、**正規の権威サーバーの応答より先に、偽の応答をリゾルバに信じさせる**ことです。

リゾルバが偽答を受け入れてしまうには、偽答が次を**すべて満たす**必要があります。

```text
正規応答とマッチさせるべき要素：
  1. トランザクションID（16ビット）が問い合わせと一致
  2. 送信元/宛先ポートが一致
  3. 質問セクション（QNAME/QTYPE）が一致
  4. 正規応答より「速く」届く（レース）
```

かつてリゾルバは**送信元ポートを固定**し、トランザクションIDも予測しやすい実装がありました。すると攻撃者が当てるべきは実質**16ビットのID（65,536通り）**だけ。さらにキャッシュ済みなら次のTTLまで待つ必要がありますが——

### 1.1 Kaminsky 攻撃（2008）— DNS を作り直させた一撃

2008年、Dan Kaminsky は決定的な手法を公表しました。**存在しないサブドメイン（`random123.bank.example`）を大量に問い合わせ**、それぞれに対して「`bank.example` の権威サーバーは攻撃者のIPだ」という**委任（NS/glue）を含む偽答**を撃ち込む。存在しない名前なのでキャッシュのTTL待ちを回避でき、何度でも高速に試行できる。一度当たれば、ドメイン全体の権威がキャッシュに毒として刻まれます。

これは「16ビットIDの推測は現実的に破れる」ことを示し、**DNS の防御を根本から見直させました**。その答えが次の RFC 5452 と DNSSEC です。

---

## 2. 防御①：RFC 5452 — 推測を「非現実的」にする

[RFC 5452](https://www.rfc-editor.org/rfc/rfc5452.html)（Measures for Making DNS More Resilient against Forged Answers, 2009）は、**偽答を受け入れにくくする**実装ルールを標準化しました。中心は**エントロピーの追加**です。

- **送信元ポートのランダム化**：問い合わせごとに送信元UDPポートをランダムに選ぶ。攻撃者はIDに加えて**ポート（最大16ビット）も当てねばならず**、組み合わせのエントロピーが実質**約32ビット**に跳ね上がる。総当たりは非現実的になる。
- **トランザクションIDのランダム化**：予測可能なIDを避け、暗号的に乱数化する。
- **0x20 エンコーディング**（補助）：QNAME の英字の大小をランダム化し、応答でそれが保たれるかを追加の検証材料にする。

```bash
# 自分のリゾルバが送信元ポートをランダム化しているかを確認（自分の資産で）
# 良い例：問い合わせごとに source port がばらける（高エントロピー）
dig +short porttest.dns-oarc.net TXT @127.0.0.1
#   → "GREAT" 等（リゾルバのポートランダム性の評価が返る）
```

> **重要な限界**：RFC 5452 は「**推測を困難にする**」確率的防御であって、「**不可能にする**」ものではありません。経路上にいる（MITM 済みの）攻撃者にはエントロピーが意味をなさない。だから次の DNSSEC が要ります。

---

## 3. 防御②：DNSSEC — 「言った者勝ち」を暗号で終わらせる

[DNSSEC](https://www.rfc-editor.org/rfc/rfc4033)（RFC 4033/4034/4035）は、DNS 攻撃への**本質的な答え**です。発想は明快——**権威サーバーが応答にデジタル署名し、リゾルバがその署名を検証する**。偽答は正しい署名を作れないため、検証で弾かれます。

```text
DNSSEC の信頼の連鎖（chain of trust）：
  ルート(.) の鍵 ──署名──► .example の鍵 ──署名──► bank.example のレコード
       ▲                                                    │
       └──── リゾルバはルートの鍵(トラストアンカー)から ◄────┘
              署名を辿って検証。1つでも署名が合わなければ SERVFAIL（拒否）
```

- **RRSIG**：各レコードセットへの署名。
- **DNSKEY**：検証に使う公開鍵。
- **DS**：親ゾーンに置かれ、子ゾーンの鍵を保証する（連鎖の輪）。

検証が成功すると、応答に **AD（Authenticated Data）ビット**が立ちます。偽答は署名検証に失敗し、リゾルバは結果を返しません。

```bash
# DNSSEC 検証が効いているかを確認（AD フラグが立つか）
dig +dnssec bank.example @127.0.0.1
#   ヘッダの flags に "ad" があれば、署名検証済みの真正な応答
#   RRSIG レコードが応答に含まれる
```

### 3.1 アプリ/リゾルバ側で検証を「要求」する

権威ゾーンに署名してあっても、リゾルバが検証しなければ意味がありません。**検証するリゾルバを使う**ことが利用者側の責務です。

```ts
import { Resolver } from "node:dns/promises";

/**
 * DNSSEC 検証を行うリゾルバ（例：ローカルの validating resolver）を明示的に指定する。
 * OS のデフォルトに任せず「検証するリゾルバ」へ向けることで、毒入りキャッシュを避ける。
 * 失敗（SERVFAIL）は握りつぶさず例外として扱い、安全側（接続しない）に倒す。
 */
export async function resolveValidated(hostname: string): Promise<readonly string[]> {
  const resolver = new Resolver();
  resolver.setServers(["127.0.0.1"]); // 検証する自前/信頼リゾルバ（Unbound 等）
  try {
    return await resolver.resolve4(hostname);
  } catch (err) {
    // SERVFAIL は「署名検証に失敗した可能性」を含む。曖昧なまま接続しない。
    throw new Error(`DNS resolution failed (possible DNSSEC failure) for ${hostname}: ${(err as Error).message}`);
  }
}
```

---

## 4. 防御③：DoH / DoT — 経路を暗号化する

DNSSEC は応答の**真正性（改ざんされていないか）**を守りますが、**機密性（誰が何を引いたかを盗み見られない）**は守りません。また、利用者から**リゾルバまで**の経路はなお平文です。ここを埋めるのが通信路の暗号化です。

- **DoT（DNS over TLS, [RFC 7858](https://www.rfc-editor.org/rfc/rfc7858)）**：DNS を TLS（853番）で運ぶ。
- **DoH（DNS over HTTPS, [RFC 8484](https://www.rfc-editor.org/rfc/rfc8484)）**：DNS を HTTPS（443）で運ぶ。検閲・盗聴に強い。

```text
役割分担（両方が要る）：
  DNSSEC  … 応答の真正性（偽答を弾く）        ← 権威〜リゾルバの「中身」を守る
  DoH/DoT … 経路の機密性・完全性（盗聴/改ざん） ← 利用者〜リゾルバの「経路」を守る
```

**DNSSEC と DoH/DoT は競合ではなく補完**です。前者は「答えが本物か」、後者は「経路が覗かれないか」。本番では両方を組み合わせます。

---

## 5. 設計者のためのチェックリスト

自社ドメインと名前解決を守るために、設計・運用で確認すべき点です。

- [ ] **自社の権威ゾーンを DNSSEC 署名**しているか（ドメインレジストラ/DNSサービスで DS を親に登録）。
- [ ] アプリが向く**リゾルバが DNSSEC 検証を行う**か（マネージドリゾルバなら検証ポリシーを確認）。
- [ ] リゾルバが**送信元ポートをランダム化**しているか（RFC 5452 準拠）。
- [ ] クライアント〜リゾルバ間で **DoH/DoT** を使えているか。
- [ ] **DNS 解決失敗（SERVFAIL）を握りつぶさず**、安全側（接続中止）に倒しているか。
- [ ] そもそも**最終防壁は TLS の証明書検証**——名前解決が毒されても、正規証明書を持たない攻撃者サーバーには TLS が繋がらない（[MITM 記事](/blog/arp-spoofing-mitm-attack-detection-defense-guide)参照）。

> **多層で考える**：DNS が毒されても TLS で守られ、TLS を狙う MITM は mTLS とゼロトラストで守られる。**単一の防御に依存しない**のがネットワークセキュリティの一貫した姿勢です。

---

## 6. まとめ

- **DNSスプーフィング/キャッシュポイズニング**は名前解決を乗っ取る。Kaminsky 攻撃が16ビットID推測の危険を現実化し、DNS の防御を作り直させた。
- **RFC 5452**：送信元ポート＋IDのランダム化でエントロピーを約32ビット級へ。推測を非現実的にする確率的防御（経路上の攻撃者には無力）。
- **DNSSEC（RFC 4033-4035）**：署名と信頼の連鎖で偽答を弾く本質的防御。AD ビットが真正性の証。
- **DoH/DoT（RFC 7858/8484）**：経路の暗号化。DNSSEC（真正性）と補完関係で両方要る。
- **最後はやはり TLS**：名前解決が毒されても、証明書検証が攻撃者サーバーを拒む。多層防御。

次は、確立済みのTCP接続そのものを奪う**[TCPセッションハイジャック / RSTインジェクション / IPスプーフィング](/blog/tcp-session-hijacking-rst-injection-ip-spoofing-defense-guide)**を、RFC 5961 の防御まで扱います。

---

私（友田 陽大）は、本番システムの DNS 設計（DNSSEC・プライベートDNS・解決失敗時のフェイルセーフ）と、TLS/証明書運用を含む“名前解決を信頼しきらない”設計を実装してきました。「自社ドメインを DNSSEC 署名したい」「DNS 解決の失敗が障害につながっている」「DoH/DoT を導入したい」——こうした名前解決の堅牢化を、攻撃者の視点で診断し、真正性と機密性の両輪で実装します。お気軽にご相談ください。
