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

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

เพื่อแก้ไขปัญหาเหล่านี้ ในปี 2016 เราได้เปิดตัว DNS-over-HTTPS (ปัจจุบันเรียกว่า DoH) เสนอการแปลง DNS ในการตรวจสอบ DNSSEC ที่เข้ารหัสผ่าน HTTPS และ QUIC และในปี 2019 เราได้เพิ่มการรองรับสำหรับมาตรฐาน DNS ผ่าน TLS (DoT) ที่ คุณลักษณะ DNS ส่วนตัวของ Android

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

เวอร์ชัน TLS และชุดการเข้ารหัสที่รองรับ

DNS สาธารณะของ Google รองรับ TLS 1.2 และ TLS 1.3 สำหรับทั้ง DoH และ DoT ไม่ใช่ก่อนหน้านี้ สนับสนุนเวอร์ชันของ TLS หรือ SSL เฉพาะชุดการเข้ารหัสที่มีการรักษาความปลอดภัยส่งต่อเท่านั้น และการเข้ารหัสที่ตรวจสอบสิทธิ์ด้วยข้อมูลเพิ่มเติม (AEAD) แล้ว Qualys SSL Labs จะแสดงชุดการเข้ารหัสปัจจุบันที่รองรับ

ปลายทาง

DNS สาธารณะของ Google ใช้ปลายทางต่อไปนี้สำหรับ 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 คือเพย์โหลด UDP DNS แบบไบนารีที่มีประเภทเนื้อหา application/dns-message.
    • คำขอนี้คือ 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

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

การตัดการตอบกลับ DNS

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

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

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

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