העברות מאובטחות ל-DNS

התשובות והשאילתות המסורתיות ב-DNS נשלחות באמצעות UDP או TCP ללא הצפנה, ולכן הן חשופות למעקב, לזיוף ולסינון אינטרנט המבוסס על DNS. תגובות ללקוחות ממקודדים ציבוריים, כמו Google Public DNS, פגיעות במיוחד: ההודעות עשויות לעבור ברשתות רבות, בעוד שהודעות בין מקודדים רקורסיביים לבין שרתי שמות מהימנים כוללות בדרך כלל הגנות נוספות.

כדי לפתור את הבעיות האלה, בשנת 2016 השקנו את DNS באמצעות HTTPS (שנקרא עכשיו DoH), עם רזולוציית DNS מוצפנת לאימות DNSSEC ב-HTTPS וב-QUIC. וב-2019 הוספנו תמיכה בתקן DNS over TLS (DoT) שמשמש את הפיצ'ר שרת DNS פרטי ב-Android.

ה-DoH ו-DoT משפרות את הפרטיות והאבטחה בין הלקוחות והמקודדים, וכך הן משלימים את אימות ה-DNSSEC של ה-DNS הציבורי של Google, וכך מספקות DNS מאומת מקצה לקצה לדומיינים שנחתמו באמצעות DNSSEC. עם Google Public DNS, אנחנו מחויבים לספק פענוח DNS מהיר, פרטי ומאובטח גם ללקוחות DoH וגם ללקוחות DoT.

גרסאות TLS נתמכות וחבילות קריפטו

ב-DNS הציבורי של Google יש תמיכה ב-TLS 1.2 וב-TLS 1.3 גם ל-DoH וגם ל-DoT, אין תמיכה בגרסאות קודמות של TLS (אבטחת שכבת התעבורה) או SSL. יש תמיכה רק בסט אלגוריתמים להצפנה (cipher suite) עם אבטחת העברה והצפנה מאומתת עם נתונים נוספים (AEAD). ב-Qualys SSL Labs מוצגת הקבוצה הנוכחית של חבילות הצפנה הנתמכות.

נקודות קצה

ב-Google Public DNS נעשה שימוש בנקודות הקצה הבאות עבור DoH ו-DoT:

DoT (יציאה 853) dns.google

תבניות URI של DoH (יציאה 443)

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

    • כשמשתמשים ב-POST, כתובת ה-URL היא רק https://dns.google/dns-query והגוף של בקשת ה-HTTP הוא המטען הייעודי (payload) הבינארי של ה-UDP מסוג DNS עם סוג התוכן application/dns-message.
    • עבור GET, הערך הוא https://dns.google/dns-query?dns=BASE64URL_OF_QUERY.
  • API מסוג JSON – https://dns.google/resolve{?name}{&type,cd,do,…}

    • בדף JSON API מתוארים פרמטרים נוספים של GET. רק הפרמטר name נדרש.

לקוחות

יש כמה אפליקציות לקוח שמשתמשות ב-DoT או ב-DoH

  • תכונת הגלישה הפרטית ב-Android 9 (Pie) – נקודה
  • 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 POST

המחרוזת המקודדת ב-Base64Url בפקודה הזו היא הודעת ה-DNS שנשלחה על ידי dig +noedns example.test A, כאשר שדה מזהה ה-DNS מוגדר לאפס, לפי ההמלצה של 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 בפקודה הזו היא הודעת ה-DNS שנשלחה על ידי dig +noedns example.com A, ובשדה מזהה ה-DNS מוגדר הערך אפס. במקרה כזה, הוא מועבר במפורש בכתובת ה-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, הלקוחות נדרשים לספק זיהוי של שם השרת (SNI).

סיומת SNI מציינת שפרטי SNI הם דומיין DNS (ולא כתובת IP):

'HostName' מכיל את שם המארח המלא של ה-DNS של השרת, כפי שהלקוח מבין. שם המארח מיוצג כמחרוזת בייטים באמצעות קידוד ASCII ללא נקודה בסוף. כך אפשר לתמוך בשמות דומיינים בינלאומיים באמצעות תוויות A שמוגדרות ב-RFC5890. שמות מארחים של DNS אינם תלויי-רישיות. האלגוריתם להשוואת שמות מארחים מתואר ב-RFC5890, סעיף 2.3.2.4.

לא ניתן להשתמש בכתובות IPv4 ו-IPv6 ליטרליות ב-"HostName".

קשה לעמוד בדרישות האלה לאפליקציות DoH או DoT שרוצות לנצל שיפורי אבטחה ב-TLS 1.3. כרגע, אפשר להשתמש ב-Google Public DNS באמצעות חיבורי TLS 1.3 שלא מספקים SNI, אבל יכול להיות שנצטרך לשנות את ההגדרה הזו בעתיד מטעמי תפעול או אבטחה.

אלו ההמלצות שלנו לגבי אפליקציות DoT או DoH שקשורות ל-SNI:

  1. צריך לשלוח את שם המארח של dns.google כ-SNI לכל החיבורים לשירותי Google Public DNS DoT או DoH.
  2. אם אין שם מארח זמין (לדוגמה, באפליקציה שמבצעת DoT יחסי), עדיף לשלוח את כתובת ה-IP ב-SNI ולא להשאיר אותה ריקה.
  3. כתובות IPv6 צריכות להופיע בצורת סוגריים מסוג [2001:db8:1234::5678] בכותרת Host, אבל בלי סוגריים ב-SNI.

קיצור של תגובת DNS

על אף ש-Google Public DNS בדרך כלל לא מקצר את התשובות לשאילתות DoT ו-DoH, יש שתי נסיבות שבהן הוא כן:

  1. אם ל-DNS הציבורי של Google אין אפשרות לקבל תגובות מלאות ולא קטועות משרתי שמות מוסמכים, הוא מגדיר את דגל השקיפות וההסכמה בתגובה.

  2. במקרים שבהם תגובת ה-DNS (בטופס של הודעת DNS בינארית) תחרוג ממגבלת 64 KiB להודעות DNS מסוג TCP, ייתכן ש-Google Public DNS יגדיר את הסימון 'TC (חיתוך)' אם תקני RFC נדרשים לעשות זאת.

עם זאת, במקרים כאלה הלקוחות לא צריכים לנסות שוב להשתמש ב-TCP פשוט או בכל העברה אחרת, כי התוצאה תהיה זהה.