DNS용 보안 전송

기존 DNS 쿼리 및 응답은 암호화 없이 UDP 또는 TCP를 통해 전송되므로 감시, 스푸핑, DNS 기반 인터넷 필터링의 대상이 됩니다. Google Public DNS와 같은 공개 리졸버의 클라이언트에 대한 응답은 특히 취약합니다. 메시지가 여러 네트워크를 통과할 수 있고 재귀 리졸버와 신뢰할 수 있는 네임서버 간의 메시지에는 추가적인 보호 기능이 포함된 경우가 많기 때문입니다.

이러한 문제를 해결하기 위해 Google은 2016년에 HTTPS 및 QUIC를 통한 암호화된 DNSSEC 검증 DNS 변환을 제공하는 HTTPS를 통한 DNS (현재 DoH)를 출시했습니다. 2019년에는 Android 비공개 DNS 기능에 사용되는 DNS over TLS (DoT) 표준에 관한 지원을 추가했습니다.

DoH와 DoT는 클라이언트와 리졸버 간의 개인 정보 보호와 보안을 강화하여 DNSSEC의 Google Public DNS 검증을 보완하여 DNSSEC 서명 도메인에 엔드 투 엔드 인증된 DNS를 제공합니다. Google은 Google Public DNS를 통해 DoH 및 DoT 클라이언트 모두에 빠르고 안전한 비공개 DNS 변환을 제공하기 위해 노력하고 있습니다.

지원되는 TLS 버전 및 암호화 묶음

Google Public DNS는 DoH와 DoT에 TLS 1.2와 TLS 1.3을 지원합니다. 그 이전 버전의 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 요청의 본문은 콘텐츠 유형이 application/dns-message인 바이너리 UDP DNS 페이로드입니다.
    • 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 1.3에 필요한 SNI를 전송하도록 +tls‑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 인코딩 문자열은 RFC 8484 섹션 4.1에서 권장하는 대로 DNS ID 필드가 0으로 설정된 dig +noedns example.test A에서 보낸 DNS 메시지입니다. 셸 명령어는 Content-Type application/dns-message을 사용하여 DNS 쿼리를 바이너리 데이터 본문 콘텐츠로 전송합니다.

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 ID 필드가 0으로 설정된 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 가져오기

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 주소 URL용 TLS 1.3 및 SNI

TLS 1.3에서는 클라이언트가 서버 이름 식별 (SNI)을 제공해야 합니다.

SNI 확장 프로그램은 SNI 정보가 IP 주소가 아닌 DNS 도메인임을 명시합니다.

'HostName'에는 클라이언트가 이해하는 서버의 정규화된 DNS 호스트 이름이 포함됩니다. 호스트 이름은 후행 점 없이 ASCII 인코딩을 사용하여 바이트 문자열로 표현됩니다. 따라서 RFC5890에 정의된 A 라벨을 사용하여 다국어 도메인 이름을 지원할 수 있습니다. DNS 호스트 이름은 대소문자를 구분하지 않습니다. 호스트 이름을 비교하는 알고리즘은 RFC5890, 섹션 2.3.2.4에 설명되어 있습니다.

리터럴 IPv4 및 IPv6 주소는 'HostName'에 허용되지 않습니다.

TLS 1.3의 보안 향상 기능을 활용하려는 DoH 또는 DoT 애플리케이션의 경우 이러한 요구사항을 충족하기 어려울 수 있습니다. Google Public DNS는 현재 SNI를 제공하지 않는 TLS 1.3 연결을 허용하지만 향후 운영 또는 보안상의 이유로 변경이 필요할 수 있습니다.

SNI와 관련하여 DoT 또는 DoH 신청을 위한 권장사항은 다음과 같습니다.

  1. Google 공개 DNS DoT 또는 DoH 서비스에 대한 연결에 대해 dns.google 호스트 이름을 SNI로 전송합니다.
  2. 사용할 수 있는 호스트 이름이 없는 경우 (예: 상황별 DoT를 실행하는 애플리케이션에서) IP 주소를 비워 두는 대신 SNI로 전송하는 것이 좋습니다.
  3. IPv6 주소는 Host 헤더에서 [2001:db8:1234::5678] 괄호 형식으로 표시되어야 하지만 SNI에서는 괄호가 없어야 합니다.

DNS 응답 잘림

Google Public DNS는 일반적으로 DoT 및 DoH 쿼리에 대한 응답을 자르지 않지만, 다음과 같은 두 가지 경우가 있습니다.

  1. Google Public DNS는 신뢰할 수 있는 네임서버로부터 완전하고 잘리지 않은 응답을 받을 수 없는 경우 응답에 TC 플래그를 설정합니다.

  2. DNS 응답 (바이너리 DNS 메시지 형식)이 TCP DNS 메시지의 64KiB 제한을 초과하는 경우 RFC 표준에서 요구하는 경우 Google Public DNS는 TC (자르기) 플래그를 설정할 수 있습니다.

하지만 이러한 경우 결과가 동일하므로 클라이언트가 일반 TCP나 다른 전송을 사용하여 재시도할 필요가 없습니다.