การส่งที่ปลอดภัยสำหรับ DNS

คำขอและการตอบกลับ DNS แบบดั้งเดิมจะส่งผ่าน UDP หรือ TCP โดยไม่มีการเข้ารหัส ทำให้อยู่ภายใต้การเฝ้าระวัง การปลอมแปลง และการกรองอินเทอร์เน็ตโดยใช้ DNS การตอบกลับไคลเอ็นต์จากรีโซลเวอร์สาธารณะ เช่น Google Public DNS มีความเสี่ยงมากสำหรับเรื่องนี้ เนื่องจากข้อความอาจผ่านเครือข่ายจำนวนมาก ในขณะที่ข้อความระหว่างรีโซลเวอร์แบบทำซ้ำและเนมเซิร์ฟเวอร์ที่เชื่อถือได้มักจะรวมการป้องกันเพิ่มเติมไว้ด้วย

ในปี 2016 เราได้เปิดตัว DNS ผ่าน HTTPS (ปัจจุบันเรียกว่า DoH) โดยนำเสนอการแปลง DNS สำหรับการตรวจสอบ DNS ที่เข้ารหัสผ่าน HTTPS และ QUIC และในปี 2019 เราได้เพิ่มการรองรับมาตรฐาน DNS ผ่าน TLS (DoT) ที่ฟีเจอร์ Private DNS ของ Android ใช้

DoH และ DoT เพิ่มประสิทธิภาพความเป็นส่วนตัวและความปลอดภัยระหว่างไคลเอ็นต์และรีโซลเวอร์ โดยเสริมการตรวจสอบ DNS สาธารณะของ Google ของ DNSSEC เพื่อระบุ DNS ที่ตรวจสอบสิทธิ์จากต้นทางถึงปลายทางสำหรับโดเมนที่ลงชื่อ DNSSEC Google Public DNS มุ่งมั่นที่จะให้บริการการแปลง DNS อย่างรวดเร็ว เป็นส่วนตัว และปลอดภัยสำหรับทั้งไคลเอ็นต์ DoH และ DoT

เวอร์ชัน TLS และชุดคริปโตที่รองรับ

Google Public DNS รองรับ TLS 1.2 และ TLS 1.3 สำหรับทั้ง DoH และ DoT โดยไม่รองรับ 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 จะเป็นเพย์โหลด DNS ของ UDP แบบไบนารีที่มี content type/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 เพื่อส่ง SNI ตามที่ TLS 1.3 กำหนด

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

สตริงที่เข้ารหัส Base64Url ในคำสั่งนี้คือข้อความ DNS ที่ส่งโดย dig +noedns example.test A โดยตั้งค่าช่องรหัส DNS เป็น 0 ตามที่ 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 ในคำสั่งนี้คือข้อความ DNS ที่ส่งโดย dig +noedns example.com A โดยมีการตั้งค่าช่องรหัส DNS เป็น 0 ในกรณีนี้ ระบบจะส่งผ่าน ใน 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

การดำเนินการนี้ใช้ JSON API สำหรับ DoH

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":[]}

TLS 1.3 และ SNI สำหรับ URL ที่อยู่ IP

TLS 1.3 กำหนดให้ไคลเอ็นต์ต้อง ระบุ Server Nameร่วม (SNI)

ส่วนขยาย SNI จะระบุว่าข้อมูล SNI เป็นโดเมน DNS (ไม่ใช่ที่อยู่ IP) ดังนี้

"HostName" มีชื่อโฮสต์ DNS แบบเต็มของเซิร์ฟเวอร์ตามที่ไคลเอ็นต์เข้าใจ ชื่อโฮสต์จะแสดงเป็นสตริงไบต์ที่ใช้การเข้ารหัส ASCII โดยไม่มีจุดต่อท้าย การดำเนินการนี้ช่วยให้รองรับชื่อโดเมนระหว่างประเทศผ่านการใช้ป้ายกำกับ A ที่กำหนดไว้ใน RFC5890 ชื่อโฮสต์ DNS ไม่คำนึงถึงตัวพิมพ์เล็กและตัวพิมพ์ใหญ่ อัลกอริทึมสำหรับเปรียบเทียบชื่อโฮสต์มีอธิบายอยู่ใน RFC5890 ส่วนที่ 2.3.2.4

ไม่อนุญาตให้ใช้ที่อยู่ IPv4 และ IPv6 แบบพื้นฐานใน "HostName"

ข้อกำหนดเหล่านี้อาจทำตามได้ยากสำหรับแอปพลิเคชัน DoH หรือ DoT ที่ต้องการใช้ประโยชน์จากการปรับปรุงความปลอดภัยใน TLS 1.3 ปัจจุบัน DNS สาธารณะของ Google ยอมรับการเชื่อมต่อ TLS 1.3 ที่ไม่มี SNI แต่เราอาจต้องเปลี่ยนการตั้งค่านี้เพื่อเหตุผลด้านการดำเนินการหรือความปลอดภัยในอนาคต

คำแนะนำสำหรับการสมัคร DoT หรือ DoH ที่เกี่ยวข้องกับ SNI มีดังต่อไปนี้

  1. ส่งชื่อโฮสต์ dns.google เป็น SNI สำหรับการเชื่อมต่อกับบริการ DNS DoT ของ Google Public DNS DoH หรือ DoH
  2. หากไม่มีชื่อโฮสต์ (เช่น ในแอปพลิเคชันที่ใช้ DoT ตามโอกาส) ขอแนะนำให้ส่งที่อยู่ IP ใน SNI แทนที่จะปล่อยว่างไว้
  3. ที่อยู่ IPv6 ควรปรากฏในรูปแบบวงเล็บ [2001:db8:1234::5678] ในส่วนหัว Host แต่ไม่มีวงเล็บใน SNI

การตัดการตอบสนอง DNS

แม้ว่าโดยทั่วไป DNS สาธารณะของ Google จะไม่ตัดการตอบสนองต่อคำค้นหา DoT และ DoH ให้สั้นลง แต่กรณีนี้มี 2 กรณีดังนี้

  1. หาก DNS สาธารณะของ Google ไม่สามารถรับคำตอบที่สมบูรณ์และไม่มีการตัดข้อมูลจากเนมเซิร์ฟเวอร์ที่เชื่อถือได้ จะมีการตั้งค่าแฟล็ก TC ในการตอบสนอง

  2. ในกรณีที่การตอบสนอง DNS (ในรูปแบบข้อความ DNS แบบไบนารี) เกินขีดจำกัด 64 KiB สำหรับข้อความ DNS ของ TCP DNS สาธารณะของ Google อาจตั้งค่าแฟล็ก TC (การตัด) หากมาตรฐาน RFC กำหนดให้ทำเช่นนั้น

แต่ในกรณีเหล่านี้ ไคลเอ็นต์ไม่จำเป็นต้องลองใช้ TCP แบบธรรมดาหรือการส่งแบบอื่นๆ เนื่องจากผลลัพธ์จะเหมือนกัน