DNS のセキュアなトランスポート

従来の DNS クエリと応答は、暗号化されずに UDP または TCP 経由で送信されるため、監視、なりすまし、DNS ベースのインターネット フィルタリングの対象になります。この問題に対する Google Public DNS などのパブリック リゾルバからのクライアントへのレスポンスは、特に脆弱です。メッセージが多くのネットワークを通過する一方で、再帰リゾルバと権威ネームサーバー間のメッセージには追加の保護機能が組み込まれることがよくあります。

これらの問題に対処するために、Google は 2016 年に DNS over HTTPS(現在は DoH)をリリースしました。これは、HTTPS と QUIC を介した暗号化された DNSSEC 検証 DNS 解決を提供するものです。2019 年には、Android のプライベート DNS 機能で使用される DNS over TLS(DoT)標準のサポートを追加しました。

DoH と DoT は、クライアントとリゾルバ間のプライバシーとセキュリティを強化し、DNSSEC の Google Public DNS 検証を補完して、DNSSEC 署名付きドメインにエンドツーエンドの認証済み DNS を提供します。Google Public DNS では、DoH と DoT の両方のクライアントに対して、高速で非公開の安全な DNS 解決を提供することに取り組んでいます。

サポートされている TLS のバージョンと暗号スイート

Google Public DNS は、DoH と DoT の両方で TLS 1.2 と TLS 1.3 をサポートしています。以前のバージョンの TLS または SSL はサポートされていません。フォワード セキュリティと追加データによる認証付き暗号化(AEAD)を備えた暗号スイートのみがサポートされています。Qualys SSL Labs には、現在サポートされている暗号スイートのセットが表示されます。

エンドポイント

Google Public DNS は、DoH と DoT に次のエンドポイントを使用します。

DoT(ポート 853)dns.google

DoH(ポート 443)URI テンプレート

  • RFC 8484 - https://dns.google/dns-query{?dns}

    • POST の場合、URL は単に https://dns.google/dns-query で、HTTP リクエストの本文はコンテンツ タイプが application/dns-message のバイナリ UDP DNS ペイロードになります。
    • GET の場合は https://dns.google/dns-query?dns=BASE64URL_OF_QUERY です。
  • JSON API - https://dns.google/resolve{?name}{&type,cd,do,…}

    • その他の GET パラメータについては、JSON API ページをご覧ください。name パラメータのみ必須です。

クライアント

DoT や DoH を使用するクライアント アプリケーションは数多くあります。

  • Android 9(Pie)の「プライベート ブラウジング」機能 - DoT
  • イントラ(Android アプリ)- DoH

dnsprivacy.org ウェブサイトには DoT と DoH に対応した他のクライアントがいくつか掲載されていますが、通常は、やや技術的な構成が必要です。

コマンドラインの例

次のコマンドラインの例は、実際のクライアントで使用することを意図したものではなく、一般的に利用可能な診断ツールを使用した説明にすぎません。

DoT

次のコマンドには、Knot DNS kdig 2.3.0 以降が必要です。2.7.4 以降では、+tls‑sni のコメント化を解除して、TLS 1.3 で必要とされる SNI を送信します。

kdig -d +noall +answer @dns.google example.com \
  +tls-ca +tls-hostname=dns.google # +tls-sni=dns.google
;; DEBUG: Querying for owner(example.com.), class(1), type(1), server(dns.google), port(853), protocol(TCP)
;; DEBUG: TLS, imported 312 system certificates
;; DEBUG: TLS, received certificate hierarchy:
;; DEBUG:  #1, C=US,ST=California,L=Mountain View,O=Google LLC,CN=dns.google
;; DEBUG:      SHA-256 PIN: lQXSLnWzUdueQ4+YCezIcLa8L6RPr8Wgeqtxmw1ti+M=
;; DEBUG:  #2, C=US,O=Google Trust Services,CN=Google Internet Authority G3
;; DEBUG:      SHA-256 PIN: f8NnEFZxQ4ExFOhSN7EiFWtiudZQVD2oY60uauV/n78=
;; DEBUG: TLS, skipping certificate PIN check
;; DEBUG: TLS, The certificate is trusted.

;; ANSWER SECTION:
example.com.            2046    IN      A       93.184.216.34
kdig -d +noall +answer @dns.google example.com \
  +tls-pin=f8NnEFZxQ4ExFOhSN7EiFWtiudZQVD2oY60uauV/n78= \
  # +tls-sni=dns.google
;; DEBUG: Querying for owner(example.com.), class(1), type(1), server(dns.google), port(853), protocol(TCP)
;; DEBUG: TLS, received certificate hierarchy:
;; DEBUG:  #1, C=US,ST=California,L=Mountain View,O=Google LLC,CN=dns.google
;; DEBUG:      SHA-256 PIN: lQXSLnWzUdueQ4+YCezIcLa8L6RPr8Wgeqtxmw1ti+M=
;; DEBUG:  #2, C=US,O=Google Trust Services,CN=Google Internet Authority G3
;; DEBUG:      SHA-256 PIN: f8NnEFZxQ4ExFOhSN7EiFWtiudZQVD2oY60uauV/n78=, MATCH
;; DEBUG: TLS, skipping certificate verification

;; ANSWER SECTION:
example.com.            5494    IN      A       93.184.216.34

DoH

RFC 8484 の POST

このコマンドの Base64Url でエンコードされた文字列は、RFC 8484 セクション 4.1 で推奨されているように、DNS ID フィールドをゼロに設定して dig +noedns example.test A によって送信される DNS メッセージです。シェルコマンドは、Content-Type application/dns-message を使用して、その DNS クエリをバイナリデータ本文のコンテンツとして送信します。

echo AAABAAABAAAAAAAAB2V4YW1wbGUEdGVzdAAAAQAB | base64 --decode |
 curl -is --data-binary @- -H 'content-type: application/dns-message' \
   https://dns.google/dns-query
HTTP/2 200
strict-transport-security: max-age=31536000; includeSubDomains; preload
access-control-allow-origin: *
date: Wed, 29 May 2019 19:37:16 GMT
expires: Wed, 29 May 2019 19:37:16 GMT
cache-control: private, max-age=19174
content-type: application/dns-message
server: HTTP server (unknown)
content-length: 45
x-xss-protection: 0
x-frame-options: SAMEORIGIN
alt-svc: quic=":443"; ma=2592000; v="46,44,43,39"

RFC 8484 GET

このコマンドの Base64Url でエンコードされた文字列は、DNS ID フィールドをゼロに設定して dig +noedns example.com A から送信された DNS メッセージです。この場合、URL で明示的に渡されます。

curl -i https://dns.google/dns-query?dns=AAABAAABAAAAAAAAB2V4YW1wbGUDY29tAAABAAE
HTTP/2 200
strict-transport-security: max-age=31536000; includeSubDomains; preload
access-control-allow-origin: *
date: Wed, 29 May 2019 19:37:16 GMT
expires: Wed, 29 May 2019 19:37:16 GMT
cache-control: private, max-age=19174
content-type: application/dns-message
server: HTTP server (unknown)
content-length: 45
x-xss-protection: 0
x-frame-options: SAMEORIGIN
alt-svc: quic=":443"; ma=2592000; v="46,44,43,39"

JSON GET

これには、DoH 用の JSON API を使用します。

curl -i 'https://dns.google/resolve?name=example.com&type=a&do=1'
HTTP/2 200
strict-transport-security: max-age=31536000; includeSubDomains; preload
access-control-allow-origin: *
date: Thu, 30 May 2019 02:46:46 GMT
expires: Thu, 30 May 2019 02:46:46 GMT
cache-control: private, max-age=10443
content-type: application/x-javascript; charset=UTF-8
server: HTTP server (unknown)
x-xss-protection: 0
x-frame-options: SAMEORIGIN
alt-svc: quic=":443"; ma=2592000; v="46,44,43,39"
accept-ranges: none
vary: Accept-Encoding

{"Status": 0,"TC": false,"RD": true,"RA": true,"AD": true,"CD": false,"Question":[ {"name": "example.com.","type": 1}],"Answer":[ {"name": "example.com.","type": 1,"TTL": 10443,"data": "93.184.216.34"},{"name": "example.com.","type": 46,"TTL": 10443,"data": "a 8 2 86400 1559899303 1558087103 23689 example.com. IfelQcO5NqQIX7ZNKI245KLfdRCKBaj2gKhZkJawtJbo/do+A0aUvoDM5A7EZKcF/j8SdtyfYWj/8g91B2/m/WOo7KyZxIC918R1/jvBRYQGreDL+yutb1ReGc6eUHX+NKJIYqzfal+PY7tGotS1Srn9WhBspXq8/0rNsEnsSoA="}],"Additional":[]}

IP アドレス URL に対する TLS 1.3 と SNI

TLS 1.3 では、クライアントが Server Name Identification(SNI)を提供する必要があります。

SNI 拡張機能は、SNI 情報が(IP アドレスではなく)DNS ドメインであることを指定します。

「HostName」には、クライアントが認識しているサーバーの完全修飾 DNS ホスト名が含まれます。ホスト名は、ASCII エンコードを使用したバイト文字列として、末尾にドットを付けません。これにより、RFC5890 で定義された A ラベルを使用して、国際化ドメイン名をサポートできます。DNS ホスト名では、大文字と小文字は区別されません。ホスト名を比較するアルゴリズムについては、RFC5890 のセクション 2.3.2.4 をご覧ください。

リテラルの IPv4 アドレスと IPv6 アドレスは「HostName」では許可されません。

TLS 1.3 のセキュリティ改善を利用する DoH または DoT アプリケーションでは、これらの要件を満たすことが難しい場合があります。Google Public DNS は現在、SNI を提供しない TLS 1.3 接続を受け入れていますが、今後、運用上またはセキュリティ上の理由で変更が必要になる可能性があります。

SNI に関する DoT または DoH のアプリケーションでは、次のことをおすすめします。

  1. Google Public DNS DoT サービスまたは DoH サービスへの接続に対して、dns.google ホスト名を SNI として送信します。
  2. ホスト名が利用できない場合(日和見 DoT を実行しているアプリなど)、空白のままにするよりも、SNI の IP アドレスを送信することをおすすめします。
  3. IPv6 アドレスは、Host ヘッダーでは [2001:db8:1234::5678](角かっこ付き)形式で表示されますが、SNI では角かっこなしで指定する必要があります。

DNS レスポンスの切り捨て

Google Public DNS は通常、DoT クエリと DoH クエリに対するレスポンスを切り捨てませんが、次の 2 つの状況が考えられます。

  1. Google Public DNS は、正式なネームサーバーから短縮されていない完全なレスポンスを取得できない場合、レスポンスに TC フラグを設定します。

  2. DNS レスポンス(バイナリ DNS メッセージ形式)が TCP DNS メッセージの 64 KiB の上限を超える場合、RFC 標準で義務付けられている場合、Google Public DNS は TC(切り捨て)フラグを設定できます。

ただし、このような場合、結果は同じになるため、クライアントがプレーン TCP や他のトランスポートを使用して再試行する必要はありません。