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 番の両方が想定どおり拒否されることを確かめてから公開します。