DNS 安全传输

传统的 DNS 查询和回复在未加密的情况下通过 UDP 或 TCP 发送, 使它们容易受到监视、欺骗和基于 DNS 的互联网过滤的攻击。 Google 公共 DNS 等公共解析器对客户端的响应尤其 因为邮件可能会经过多个网络,而邮件 递归解析器和权威域名服务器之间通常包含 额外保护措施

为了解决这些问题,我们于 2016 年推出了 DNS-over-HTTPS(现在称为 DoH), 通过 HTTPS 和 QUIC 提供加密的 DNSSEC 验证 DNS 解析。 2019 年,我们增加了对 Android 专用 DNS 功能。

DoH 和 DoT 可增强客户端与解析器之间的隐私性和安全性, 是对 DNSSEC 的 Google 公共 DNS 验证的补充,旨在提供端到端 用于由 DNSSEC 签名的网域的经过身份验证的 DNS。有了 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)“Private Browsing”功能 - DoT
  • Intra(Android 应用)- DoH

dnsprivacy.org 网站列出了 DoT 和 DoH 的其他几个客户端,但 这些配置通常需要适度的技术配置。

命令行示例

以下命令行示例不适合在实际客户端中使用 只是示例,使用常用的诊断工具。

DoT

以下命令需要 Knot DNS kdig 2.3.0 或更高版本;为 2.7.4 或 稍后,根据 TLS 1.3 的要求,取消注释 +tls‑sni 以发送 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 编码字符串就是 Google Cloud 服务器发送的 DNS 消息, dig +noedns example.test A(建议将 DNS ID 字段设置为零) (请参阅 RFC 8484 第 4.1 节)。shell 命令会将该 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 编码字符串就是 Google Cloud 服务器发送的 DNS 消息, 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 地址):

“HostName”包含服务器的完全限定 DNS 主机名 以体现客户的理解主机名以字节字符串的形式表示 使用不含句点的 ASCII 编码。这使得支持 国际化域名。 RFC5890。DNS 主机名不区分大小写。要比较的算法 RFC5890 第 2.3.2.4 节中对主机名进行了介绍。

“HostName”中不允许使用纯 IPv4 和 IPv6 地址。

对于希望 充分利用 TLS 1.3 中的安全改进功能。目前,Google 公共 DNS 接受不提供 SNI 的 TLS 1.3 连接,但我们可能需要将 。

关于 SNI 的 DoT 或 DoH 应用建议如下:

  1. 针对与 Google Public 的任何连接,将 dns.google 主机名作为 SNI 发送 DNS DoT 或 DoH 服务。
  2. 如果没有可用的主机名(例如, 机会性 DoT),最好在 SNI 中发送 IP 地址, 而不是将其留空
  3. IPv6 地址应以[2001:db8:1234::5678]括号形式 Host 标头,但在 SNI 中不含括号。

DNS 响应截断

尽管 Google 公共 DNS 通常不会截断对 DoT 和 DoH 的响应, 则会出现以下两种情况:

  1. 如果 Google 公共 DNS 无法从 权威域名服务器,则会在响应中设置 TC 标记。

  2. 如果 DNS 响应(以二进制 DNS 消息形式) 超过 64 KiB 限制,则 Google 公共 DNS 可能会将 TC(截断)标记(如果 RFC 标准要求这样做)。

不过,在这些情况下,客户端无需使用普通 TCP 重试 或任何其他传输方式,因为结果是一样的。