2026年6月8日

2026年6月8日

DoH (DNS over HTTPS) の検証手順|自前の DoH サーバーを公開する前に TLS・HTTP・DNS の動作を curl と dig で確かめる

自前で立てた DoH(DNS over HTTPS)サーバーは、「ブラウザで名前解決できた」だけでは検証が足りません。証明書の検証が通るか、RFC 8484 の作法どおりに GET と POST の両方へ応答するか、DNS のエラーやDNSSEC の結果を正しく返すか、想定外の相手に使われないか、を順に確かめておく必要があります。この記事では、利用者に URL を配る前に行う検証の手順を、TLS・HTTP・DNS・アクセス制御・クライアントの5つの層に分けて、curl と dig を使って説明します。

動かないときの原因調査はトラブルシューティングの記事で扱っています。ここでは「動いているように見えるサーバーが、本当に正しく動いているか」を確かめる受け入れ検証を対象にします。

検証の前に用意するもの

  • 検証用の端末を2か所。 許可したネットワークの中の端末と、許可していない外部の端末です。アクセス制御を確かめるのに両方が要ります。
  • ツール。 curl(DoH の URL を指定できる 7.62 以降)、dig(DoH に対応した BIND 9.18 以降)、openssl。DNS のバイナリ応答を読むために、Python の dnspython があると便利です。
  • 期待値の一覧。 URL(例: https://dns.example.com/dns-query)、許可する送信元、DNSSEC 検証の有無、フィルタリングの有無を書き出しておきます。期待値がないと、結果が正しいのか判断できません。

以下の dns.example.com は自分のサーバーのホスト名に置き換えてください。

1. TLS の層を確かめる

最初に、証明書が一般的なクライアントの検証を通るかを確かめます。DoH のクライアントは、ブラウザと同じように証明書のホスト名とチェーンを厳しく検証します。

openssl s_client -connect dns.example.com:443 -servername dns.example.com \
  -alpn h2 </dev/null 2>/dev/null \
  | grep -E 'Verify return code|ALPN protocol|Protocol'

見るのは次の3点です。

  • Verify return code: 0 (ok) になっているか。0 以外なら、中間証明書が抜けている(fullchain ではなくサーバー証明書単体を指定している)か、ホスト名が合っていない可能性が高いです。
  • ALPN protocol: h2 になっているか。DoH は HTTP/2 以降の利用が推奨されており、HTTP/2 にしか対応しないクライアントや実装もあります。
  • TLS のバージョンが 1.2 以上か。1.0 や 1.1 を受け付ける設定が残っていれば無効にします。

2. HTTP の層(RFC 8484 の作法)を確かめる

RFC 8484 では、DNS メッセージをそのままバイナリで送る application/dns-message 形式が定められています。GET では Base64url で符号化して dns パラメータに入れ、POST では本文にそのまま入れます。どちらにも応答できるかを確かめます。

# GET:RFC 8484 の例にある www.example.com の A レコードの問い合わせ
curl -sS -D - -o get.bin -H 'accept: application/dns-message' \
  'https://dns.example.com/dns-query?dns=AAABAAABAAAAAAAAA3d3dwdleGFtcGxlA2NvbQAAAQAB'

# POST:同じ問い合わせをバイナリで送る
echo 'AAABAAABAAAAAAAAA3d3dwdleGFtcGxlA2NvbQAAAQAB' | base64 -d > q.bin
curl -sS -D - -o post.bin -H 'content-type: application/dns-message' \
  --data-binary @q.bin https://dns.example.com/dns-query

# 応答の中身を読む
python3 -c "import dns.message,sys; print(dns.message.from_wire(open(sys.argv[1],'rb').read()))" get.bin

確かめる点は次のとおりです。

  • ステータスと Content-Type。 どちらも 200 で、content-type: application/dns-message が返ること。
  • キャッシュの指示。 cache-control: max-age= の値が、応答に含まれるレコードの TTL 以下になっていること。RFC 8484 では HTTP のキャッシュの有効期間を DNS の TTL を超えないようにすることが求められています。途中にキャッシュする CDN やプロキシを置いている場合は特に重要です。
  • HTTP のバージョン。 curl -sS -o /dev/null -w '%{http_version}\n' --http2 ... で 2 が返るか。

続けて、壊れた要求に対する反応も見ます。パスを変える、content-type を text/plain にする、dns パラメータを壊す、といった要求を送り、4xx 系のエラーが返ることを確かめます。返すコード(400・404・415 など)は実装で異なりますが、200 で空の応答を返したり 5xx でサーバーが落ちたりしないことが大切です。

3. DNS の層を確かめる

dig の DoH 対応を使うと、DNS としての応答を読みやすい形で確かめられます。

# 通常の名前(status: NOERROR と応答が返るか)
dig @dns.example.com +https example.com A

# 存在しない名前(HTTP は 200 のまま、DNS の status が NXDOMAIN になるか)
dig @dns.example.com +https no-such-name.example.com A

# DNSSEC 検証(署名付きの名前で flags に ad が付くか)
dig @dns.example.com +https +dnssec isc.org A

# 署名が壊れているテスト用ドメイン(検証するなら SERVFAIL になるか)
dig @dns.example.com +https dnssec-failed.org A

ここで押さえておきたいのは、DNS の失敗は HTTP のエラーにはならないという点です。NXDOMAIN や SERVFAIL も、HTTP としては 200 で返り、DNS メッセージの中の RCODE で失敗が伝えられます。HTTP の 200 だけを見て「正常」と判断する監視は、DNS 側の障害に気づけません。

DNSSEC 検証を有効にしているなら、署名付きの名前で ad フラグが付き、署名が壊れた名前で SERVFAIL になることを確かめます。どちらの結果も変わらない場合は、後段のリゾルバーで検証が無効になっている可能性があります。テスト用ドメインは運営側の都合で使えなくなることもあるため、結果がおかしいときは別の名前でも試してください。

なお、dig の DoH 対応は、版によっては既定で証明書を検証しません。証明書の確認は手順1の openssl や curl で行い、dig は DNS の応答を読むために使うと割り切ると混乱しません。

4. アクセス制御を確かめる

自分たちだけで使うつもりのサーバーが、誰でも使える公開リゾルバーになっていないかを確かめます。許可していない外部の端末から、手順3と同じ問い合わせを送ります。

  • 期待どおりなら、HTTP の 403 や接続拒否、または DNS の REFUSED が返ります。どれが返るかは、どの層で制限しているかによります。
  • 正常な応答が返ってきたら、アクセス制御が効いていません。リバースプロキシを挟んでいる場合、後段のリゾルバーから見た送信元がプロキシのアドレスになり、リゾルバー側の制限が意味をなさなくなっていることがよくあります。

あわせて、平文の 53 番が外部に開いていないかも見ます。

# 外部の端末から実行。応答が返らない、または REFUSED なら想定どおり
dig @dns.example.com example.com A +time=3 +tries=1

DoH だけを公開するつもりでも、後段のリゾルバーが 53 番を全インターフェースで待ち受けていると、DNS の増幅攻撃に悪用されるおそれがあります。

5. 実際のクライアントで確かめる

最後に、利用者が使う環境で動くかを確かめます。

  • curl。 curl -v --doh-url https://dns.example.com/dns-query https://example.com/ -o /dev/null で、名前解決を DoH に任せた通信が通るかを見られます。
  • Firefox。 設定のプライバシー関連の項目で DNS over HTTPS のプロバイダーにカスタムの URL を指定し、about:networking#dns で名前解決の一覧を開くと、DoH(TRR)で解決したかどうかを確かめられます。
  • Windows 11。 IP アドレスと URL の組み合わせを登録すると、OS の DoH を使えます。PowerShell では Add-DnsClientDohServerAddress で登録できます。

画面の項目名はブラウザや OS のバージョンで変わります(2026年10月現在)。項目が見つからない場合は、各製品のヘルプで DoH の設定方法を確認してください。

負荷とログを確かめる

利用者が多くなる見込みなら、負荷試験も行います。dnsperf の新しい版には DoH で問い合わせるモードがあります。いきなり本番相当の負荷をかけず、少ない量から上げていき、応答時間とエラー率、サーバーの CPU やメモリ、HTTP/2 の同時ストリーム数の上限に達していないかを見ます。

ログも確認します。検証中に増やした問い合わせログが、そのまま残っていないかを見てください。DoH は利用者のプライバシーを守る目的で使われることが多いため、問い合わせた名前と送信元をどこまで、どれだけの期間残すかを決めて、利用者に説明できる状態にしておきます。

まとめ

  • DoH の検証は TLS・HTTP・DNS・アクセス制御・クライアントの順に、層を分けて行います。
  • TLS では証明書の検証結果と、ALPN で HTTP/2 が選ばれているかを確かめます。
  • HTTP では GET と POST の両方、application/dns-message、TTL を超えない cache-control、壊れた要求への 4xx 応答を確かめます。
  • DNS の失敗は HTTP では 200 で返るため、RCODE と DNSSEC の ad フラグまで見ます。
  • 外部の端末から、DoH と平文の 53 番の両方が想定どおり拒否されることを確かめてから公開します。

お気軽にご相談ください

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