DNS 的安全傳輸

傳統 DNS 查詢和回覆會在未加密的情況下透過 UDP 或 TCP 傳送, 因此能夠受到監視、假冒以及 DNS 型網際網路篩選。 更特別地回應來自公開解析器 (例如 Google 公用 DNS) 的用戶端回應 訊息功能可能會透過許多網路傳送,但 遞迴解析器和權威名稱伺服器之間經常會整合 額外的保護措施

為解決這些問題,我們在 2016 年推出 DNS over HTTPS (現稱 DoH) 提供透過 HTTPS 和 QUIC 加密的 DNSSEC 驗證 DNS 解析。 我們在 2019 年開始支援適用於多種用途的 DNS over TLS (DoT) 標準, Android 的私人 DNS 功能。

DoH 和 DoT 可強化用戶端和解析器之間的隱私與安全性, 補充 Google 公用 DNS 驗證的 DNSSEC 功能,以便提供端對端 且具備 DNSSEC 簽署的網域藉由 Google 公用 DNS 致力於為 DoH 和 DoT 用戶端。

支援的 TLS 版本和加密套件

Google 公用 DNS 支援 DoH 和 DoT 的 TLS 1.2 和 TLS 1.3;不早 支援的 TLS 或 SSL 版本。只有具前瞻性的加密套件 和「以額外資料進行驗證加密」(AEAD) 的系統支援。 Qualys SSL Labs 會顯示目前支援的加密套件組合。

端點

Google 公用 DNS 針對 DoH 和 DoT 使用下列端點:

DoT (通訊埠 853) dns.google

DoH (通訊埠 443) URI 範本

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

    • 如果是 POST,則網址為 https://dns.google/dns-query,且 HTTP 要求是含有內容類型的二進位 UDP DNS 酬載 application/dns-message.
    • 如果是 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
  • Intra (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 編碼字串是 dig +noedns example.test A,並將 DNS ID 欄位設為零 (按照建議做法) RFC 8484 第 4.1 節。殼層指令會將 DNS 查詢當做 二進位資料主體內容,使用 Content-Type application/dns-message

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 編碼字串是 dig +noedns example.com A,將 DNS ID 欄位設為零。在本例中 明確透過網址傳遞

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 位址網址適用的 TLS 1.3 和 SNI

TLS 1.3 要求用戶端 提供伺服器名稱識別 (SNI)。

SNI 擴充功能會指定 SNI 資訊為 DNS 網域 (而不是 IP 位址):

「主機名稱」包含伺服器的完整 DNS 主機名稱 。主機名稱以位元組字串表示 使用 ASCII 編碼,而不再以點結尾。如此一來 國際化的網域名稱,方法是使用 RFC5890。DNS 主機名稱不區分大小寫。要比較的演算法 主機名稱請參閱 RFC5890 的 2.3.2.4 節

「HostName」中不得使用常值 IPv4 和 IPv6 位址。

無法滿足 DoH 或 DoT 應用程式的需求 享有傳輸層安全標準 (TLS) 1.3 的安全性改善項目。Google 公用 DNS 目前 接受未提供 SNI 的 TLS 1.3 連線,但我們可能需要變更連線 這會造成未來的營運或安全性原因

以下是我們針對 SNI 所推薦的 DoT 或 DoH 應用程式:

  1. 傳送 dns.google 主機名稱做為 SNI 與 Google 公開伺服器的任何連線 DNS DoT 或 DoH 服務。
  2. 如果沒有主機名稱 (例如,在 這種情況下,最好在 SNI 中傳送 IP 位址,而不是 不要將這個欄位留空
  3. IPv6 位址應以 [2001:db8:1234::5678] 的括號形式顯示,且 Host 標頭,但在 SNI 中不含括號。

DNS 回應截斷

雖然 Google 公用 DNS 通常不會截斷對 DoT 和 DoH 的回應 有兩種情況執行:

  1. 如果 Google 公用 DNS 無法從 取得完整且未經截斷的回應 權威名稱伺服器,就會在回應中設定 TC 標記。

  2. 若是 DNS 回應 (採用二進位 DNS 訊息格式) 超過 TCP DNS 訊息的 64 KiB 限制,Google 公用 DNS 可能會將 TC (截斷) 標記。

不過在這類情況下,用戶端不需要使用純 TCP 或任何其他傳輸方式,因為結果都是一樣的