传统的 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。
- 对于 POST,网址只有
JSON API -
https://dns.google/resolve{?name}{&type,cd,do,…}
- 如需更多 GET 参数,请访问
JSON API 页面。
只有
name
参数是必需的。
- 如需更多 GET 参数,请访问
JSON API 页面。
只有
客户端
许多客户端应用都使用 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 应用建议如下:
- 针对与 Google Public 的任何连接,将 dns.google 主机名作为 SNI 发送 DNS DoT 或 DoH 服务。
- 如果没有可用的主机名(例如, 机会性 DoT),最好在 SNI 中发送 IP 地址, 而不是将其留空
- IPv6 地址应以
[2001:db8:1234::5678]
括号形式Host
标头,但在 SNI 中不含括号。
DNS 响应截断
尽管 Google 公共 DNS 通常不会截断对 DoT 和 DoH 的响应, 则会出现以下两种情况:
如果 Google 公共 DNS 无法从 权威域名服务器,则会在响应中设置 TC 标记。
如果 DNS 响应(以二进制 DNS 消息形式) 超过 64 KiB 限制,则 Google 公共 DNS 可能会将 TC(截断)标记(如果 RFC 标准要求这样做)。
不过,在这些情况下,客户端无需使用普通 TCP 重试 或任何其他传输方式,因为结果是一样的。