2026年6月4日

2026年6月4日

DoH(DNS over HTTPS)の署名チェック手順:サーバー証明書と DNSSEC を検証する

DoH の「署名チェック」には、DoH サーバーの TLS 証明書を確かめることと、DoH 経由で受け取った DNS 応答が DNSSEC の署名で検証済みかを確かめることの2つがあります。この記事では、openssl・dig・curl を使ってこの2つを順に確認する手順と、結果の読み方、検証に失敗したときの切り分けを説明します。自前の DoH サーバーを運用している人にも、公開リゾルバの動作を確かめたい人にも使える内容です。

DoH で何が守られ、何が守られないか

DoH(RFC 8484)は DNS の問い合わせを HTTPS で運ぶ方式です。TLS によって、経路上での盗み見や改ざんを防ぎ、接続先が本物の DoH サーバーであることを証明書で確かめられます。

一方で、DoH が保証するのは「リゾルバとの間の通信」までです。リゾルバが権威サーバーから受け取った応答が正しいかどうかは、DoH とは別に DNSSEC の署名検証で確かめる必要があります。そのため、DoH を使っていても次の2点は分けて確認します。

  • 証明書の検証: 接続している DoH サーバーが意図したものか
  • DNSSEC の検証: リゾルバが応答の署名(RRSIG)を検証しているか

手順1: DoH サーバーの証明書を確認する

まず、DoH サーバーの証明書が有効で、ホスト名と一致し、信頼できる CA までの証明書チェーンがそろっているかを確認します。

openssl s_client -connect dns.example.com:443 -servername dns.example.com </dev/null 2>/dev/null \
  | openssl x509 -noout -subject -issuer -dates

続いて、検証結果そのものを確認します。

openssl s_client -connect dns.example.com:443 -servername dns.example.com -verify_return_error </dev/null

出力の終わりに Verify return code: 0 (ok) があれば、手元の信頼ストアで検証に成功しています。よくある失敗は次の3つです。

  • unable to get local issuer certificate: サーバーが中間証明書を送っていない。サーバー設定で fullchain(中間証明書を含むファイル)を指定する
  • certificate has expired: 証明書の期限切れ。自動更新が止まっていないか確認する
  • ホスト名の不一致: -servername に指定した名前が証明書の SAN に含まれているか確認する

自前の DoH サーバーで中間証明書が欠けている場合、ブラウザでは偶然つながっても、OS や他のクライアントでは失敗することがあります。openssl での確認は、そうした差を見つけるのに役立ちます。

手順2: DoH 経由で DNSSEC の検証結果を確認する

BIND 9.18 以降の dig は +https オプションで DoH の問い合わせができます。+dnssec を付けると、署名(RRSIG)も含めて応答を受け取れます。

dig @1.1.1.1 +https +dnssec example.com A

自前のサーバーなら @dns.example.com に置き換えます。パスが /dns-query 以外の場合は +https=/パス の形で指定します。

結果で見るのはヘッダーの flags 行です。

;; flags: qr rd ra ad; QUERY: 1, ANSWER: 2, AUTHORITY: 0, ADDITIONAL: 1

ad(Authenticated Data)が付いていれば、リゾルバが DNSSEC の署名を検証し、成功したことを示します。ANSWER セクションに RRSIG の行があれば、署名データも受け取れています。Knot DNS の kdig を使う場合も、kdig @1.1.1.1 +https +dnssec example.com A で同様に確認できます。

手順3: 検証失敗が正しく扱われるかを確かめる

検証しているかどうかは、「わざと署名を壊したドメイン」への問い合わせで確かめるのが確実性の高い方法です。テスト用に署名が不正な状態で公開されているドメイン(例: dnssec-failed.org)を問い合わせます。

dig @1.1.1.1 +https dnssec-failed.org A

DNSSEC を検証しているリゾルバなら status: SERVFAIL が返ります。対応しているリゾルバでは、拡張 DNS エラー(EDE、RFC 8914)として DNSSEC の検証失敗を示す情報が OPT PSEUDOSECTION に付くこともあります。ここで通常どおりアドレスが返ってくるなら、そのリゾルバは DNSSEC を検証していません。テスト用ドメインは運営者の都合で変わることがあるので、結果が想定と違う場合はドメインの現状も確認してください。

手順4: curl で HTTP レベルの応答を見る

dig が古くて +https が使えない環境では、curl で確かめる方法もあります。Cloudflare や Google の公開リゾルバは、RFC 8484 の形式に加えて JSON 形式の応答にも対応しています(2026年10月現在)。JSON 形式は各社独自の仕様なので、パラメーターは各社のドキュメントで確認してください。

curl -s -H 'accept: application/dns-json' \
  'https://cloudflare-dns.com/dns-query?name=example.com&type=A&do=1'

応答の "AD": true が DNSSEC 検証済みを示し、"Status": 0 が NOERROR に当たります。do=1 は署名データを要求するパラメーターです。

また、curl 自体の名前解決を DoH にする --doh-url オプションもあります。この場合も DoH サーバーの証明書は既定で検証されます。検証を無効にする --doh-insecure は、原因調査の一時的な比較以外では使わないでください。

curl --doh-url https://cloudflare-dns.com/dns-query -I https://example.com/

結果の読み方と切り分け

確認結果は、次のように解釈できます。

  1. **NOERROR かつ ad あり**: 署名の検証に成功している
  2. **NOERROR だが ad なし**: 対象ゾーンが DNSSEC で署名されていないか、リゾルバが検証していない。手順3のテストでどちらかを判断する
  3. SERVFAIL: 署名が不正、または DS と DNSKEY の不一致など、ゾーン側の DNSSEC 設定に問題がある可能性が高い。DNSViz などの診断サービスでゾーンの署名の連鎖を確認する
  4. 接続自体に失敗する: 手順1の証明書確認、ポート 443 の到達性、DoH のパス指定を順に確かめる

自分のドメインで3番目の結果が出た場合は、DNS の管理画面と、レジストラに登録した DS レコードを見比べます。鍵の更新後に DS の差し替えを忘れている、というのが典型的な原因です。

AD フラグを信頼する範囲

ad フラグは「リゾルバが検証した」という申告であり、手元で署名を検証したわけではありません。リゾルバとの通信は DoH の TLS で守られているため、信頼できるリゾルバを使っている限りは実用上この確認で足ります。より厳密に手元で検証したい場合は、Unbound などの検証機能を持つリゾルバをローカルで動かし、その上流として暗号化 DNS を使う構成を検討します。Unbound は上流への転送で DoT に対応しているので、DoH にこだわらなければ、Unbound 単体で暗号化と署名検証の両方をまかなえます。

まとめ

  • DoH の署名チェックは「サーバー証明書の検証」と「DNSSEC の検証」に分けて行う
  • 証明書は openssl s_client で Verify return code: 0 (ok) と中間証明書の有無を確認する
  • dig +https +dnssec で ad フラグと RRSIG を確認し、署名不正のテストドメインで SERVFAIL になるかを確かめる
  • dig が使えない環境では curl の JSON 形式("AD": true)で確認できる
  • SERVFAIL が出たら DS と DNSKEY の対応など、ゾーン側の DNSSEC 設定を確認する

お気軽にご相談ください

お見積りへ お問い合わせへ
▲