DoH - DNS over HTTPS

Jahrzehntelang haben Client per DNS einen Namen auf eine IP-Adresse aufgelöst und die Verbindung aufgebaut. Genauso lange was DNS unzuverlässig, da Provider und Staaten diese Anfragen im Klartext per UDP/TCP mitlesen und sogar fälschen und damit den Client umleiten konnten. Andere Verfahren wie DNSSEC sind verfügbar aber setzen sich nicht schnell genug durch. Die am meisten genutzte Applikation im Internet ist aber der Browser und die Hersteller (Google, Mozilla, Microsoft) entwickeln hier kontinuierlich weiter.

DoH sicher?

Es ist nur eine Frage der Zeit, bis Browser sich nicht mehr auf die DNS-Anfrage des Netzwerks verlassen, sondern per HTTPS sich die Daten besorgen. Das ist aber nicht ganz problemlos, da die Auflösung nur an eine andere Stelle erfolgt. Der DoH-Server liefert nun die Adressen und der Betreiber ist natürlich dann im Bilde, welche URLs sie ansprechen. Überwachungsstaaten könnten auch die DoH-Abfrage unterbinden und damit dem Anwender auf "abhörbares" DNS zu zwingen, wenn er surfen möchte. Insofern ist auch DoH nur ein Baustein mehr aber nicht die Lösung gegen totalitäre Staaten oder neugierige Betreiber.

Technisch braucht der Anwender natürlich einen DoH-Service, der vom Browser oder der Anwendung genutzt wird. Auch hier werden Google, Mozilla etc. erst ein paar Default-Server vorgeben, denn noch gibt es hier keine "Autokonfiguration" per DHCP o.ä. Wobei auch dies dann wieder ein Kritikpunkt zur Sicherheit wäre, Wenn ein WLAN-Betreiber so die Client auf einen DoH-Server lenken kann, dann kann dieser doch wieder mitlesen.

Interessant wird es, wenn DoH nicht durch das Betriebssystem bedient wird sondern in einer Applikation ein DoH-Server mitgegeben wird und diese App damit jegliche lokale DNS-Auflösung umgeht. Das könnten z.B. "Rich Clients" wie OneDrive, Outlook, Word etc.

DoH mit PowerShell "dns="

Um nicht auf einen Browser angewiesen zu sein, habe ich mir die Specs zu DoH aus der RFC 8484 gezogen und mit einfach schnell selbst einen DoH-Resolver per PowerShell geschrieben. Laut RFC 8484 kann ich eine DNS-Anfrage per HTTPS über einen GET oder einen POST auslösen. In der RFC steht dazu:

   :method = GET
   :scheme = https
   :authority = dnsserver.example.net
   :path = /dns-query?dns=AAABAAABAAAAAAAAA3d3dwdleGFtcGxlA2NvbQAAAQAB
   accept = application/dns-message

Ein DoH-Server muss laut RFC8484 sowohl die GET- als auch POST-Methode anbieten. Interessanter finde ich aber alternative Parameter, die mir das BASE64-codieren einer DNS-Binärabfrage ersparen. Sie sehen, dass der DNS-Name "Base64" encodiert ist. Auch das ist in der RFC vorgegeben.

When the HTTP method is GET, the single variable "dns" is defined as the content of the DNS request (as described in Section 6), encoded with base64url [RFC4648].
Quelle: https://datatracker.ietf.org/doc/html/rfc8484#section-4.1

Allerdings ist damit nicht einfach der Hostname gefragt, denn per DNS gibt es ja durchaus weitere Typen. In der RFC steht "DNS Wire" drin, d.h. wie DNS-Anfragen auf dem Kabel über UDP/TCP übertragen würde. Ds fällt auch auf, wenn man den Beispielstring "AAABAAABAAAAAAAAA3d3dwdleGFtcGxlA2NvbQAAAQAB" mal Base64 decodiert.

[Convert]::FromBase64String("AAABAAABAAAAAAAAA3d3dwdleGFtcGxlA2NvbQAAAQAB")

00 00                                Transaction ID 0000
01 00                                Query Flags  Standard
00 01                                Type = Question
00 00                                Answer RRs 
00 00                                Authority RR
00 00                                Additional RRs
03                                   3 Zeichen folgen
119 119 119                          "www"
07                                   7 Zeichen folgen
101 120 97 109 112 108 101           "example"
03                                   3 Zeichen folgen 
99 111 109 00                        "com"
00 01                                Type = A 
00 01                                Class = IN

Der Hostname wird aufgeteilt und die Länge davor gestellt. Hier der decodierte Mitschnitt einer DNS-Abfrage im WireShark:

Ich beschränke mich für meine Beispiele auf die Abfrage der A-Records:

Irgendwo ist in dem Code noch etwas falsch, denn die Antworten passen noch nicht oder ich bekomme einen Fehler

param (
   [string]$hostname = "outlook.office365.com"
)

[byte[]]$dnswire= @(00,00,01,00,00,01,00,00,00,00,00,00,03)
foreach ($namepart in $hostname.split(".")){
   $dnswire += $namepart.length
   $dnswire += [System.Text.Encoding]::ascii.GetBytes($namepart)
}
$dnswire += @(00,00,01,00,01)
$dnswireb64 = [Convert]::ToBase64String($dnswire)
$result = Invoke-Webrequest `
   -Uri "https://dns.google.com/dns-query?dns=$($dnswireb64)" `
   -Headers @{"accept" = "application/dns-message"}

$result = Invoke-Webrequest `
   -Uri "https://cloudflare-dns.com/dns-query?dns=$($dnswireb64)" `
   -Headers @{"accept" = "application/dns-message"}

$result

Ich vermute, dass die DoH-RFC einfach die DNS-Pakete, die sonst per UDP zum DNS-Server gehen, nun als BASE64-codierte Payload im HTTP-Request übertragen, damit auf der Serverseite der Webservice den Request einfach 1:1 zum DNS-Server weitergeben kann. Bislang ist mir das noch nicht gelungen.

DoH mit PowerShell "name="

Aber anscheinend ist auch einigen anderen Entwicklern das "codieren" einer DNS-Anfrage in ein Binärarray zu aufwendig, so dass sich ein zweiter Weg etabliert hat. Anstatt mit "?dns=xxxxxx" kann auch einfach die Anfrage als Parameter übergeben werden. In der RFC8484 habe ich keine Beschreibung dazu gefunden aber anscheinend unterstützen verschiedene Dienste diese alternative Methode.

# Quad9 nutzt 5053 als Port und liefert Binärdaten
$result= Invoke-RestMethod `
            -Uri "https://dns.quad9.net:5053/dns-query?name=msxfaq.net&type=A" `
            -Headers @{"accept" = "application/dns-message"}


Der String sieht stark nach einer nativen DNS-Antwort aus, die aber nicht Base64 codiert ist. Ich habe mir nicht die Mühe gemacht, hier die Chars in Bytes zu drehen und dann die Antwort zu decodieren. Wenn ich den Header "accept" = "application/dns-message"" weglasse, dann liefert Quad9 eine JSON-Struktur:

# Quad9:5053 ohne accept-Header
Invoke-RestMethod `
   -Uri "https://dns.quad9.net:5053/dns-query?name=msxfaq.net&type=A"

Status     : 0
TC         : False
RD         : True
RA         : True
AD         : False
CD         : False
Question   : {@{name=msxfaq.net.; type=1}}
Answer     : {@{name=msxfaq.net.; type=1; TTL=541; data=178.77.117.98}}
Additional : {@{name=.; type=41; TTL=0; data=
             ;; OPT PSEUDOSECTION:
             ; EDNS: version 0; flags: ; udp: 4096}}

Auch Google nutzt 443 und liefert direkt eine JSON-Struktur, die einfach zu lesen ist.

Invoke-RestMethod `
   -Uri "https://dns.google.com/resolve?name=msxfaq.net&type=A" `
   -Headers @{"accept" = "application/dns-message"}

Status   : 0
TC       : False
RD       : True
RA       : True
AD       : False
CD       : False
Question : {@{name=msxfaq.net.; type=1}}
Answer   : {@{name=msxfaq.net.; type=1; TTL=599; data=178.77.117.98}}
Comment  : Response from 2603:5:2194::2e.

Es ist also ganz einfach, mal schnell per HTTPS eine DNS-Anfrage über einen DoH-Server abzusetzen. Schon das kann interessant sein, um die externe Auflösung von innen zu prüfen.

DoH und Cloud-Dienste

Schon mit den klassischen Public DNS-Providern gibt es aber Probleme mit der Cloud, wenn die Anbieter aufgrund der DNS-Anfrage den besten Zugangspunkt bestimmt. Das klappt natürlich nicht mehr, wenn ich über Provider-1 angeschlossen bin aber dann einen fremden DoH-Server bei einem anderen Provider frage. Die angefragte Cloud wird dann einen Zugangspunkt nennen, welche in der Nähe des DoH-Servers steht. Das muss aber nicht der beste Zugang für meinen Client sein.

Es gibt nämlich schon jede DoH-Services, die aber sicher nicht alle verteilte Server betreiben. Einige Server haben sogar eine Inhaltsblockade mit eingebaut, um gefährliche URLs zu blockieren.

Wenn Sie aber einen "falschen "DoH-Server prüfen, dann erhalten Sie vielleicht auch den falschen Wert. Das habe ich mit "outlook.office365.com" einfach mal getestet, in dem ich mehrere der genannten Server am 19.7. gefragt habe:

DoH-Serve

Antwort

https://dns.google.com/resolve

(Invoke-RestMethod `
   -Uri "https://dns.google.com/resolve?name=outlook.office365.com&type=A" `
   -Headers @{"accept" = "application/dns-message"}).answer
name                        type TTL data
----                        ---- --- ----
outlook.office365.com.         5 170 outlook.ha.office365.com.
outlook.ha.office365.com.      5  58 outlook.ms-acdc.office.com.
outlook.ms-acdc.office.com.    5  58 AMS-efz.ms-acdc.office.com.
AMS-efz.ms-acdc.office.com.    1   8 52.97.200.130
AMS-efz.ms-acdc.office.com.    1   8 52.97.163.2
AMS-efz.ms-acdc.office.com.    1   8 40.101.80.194
AMS-efz.ms-acdc.office.com.    1   8 52.97.201.82

https://dns.digitale-gesellschaft.ch/dns-query

((Invoke-WebRequest `
   -Uri "https://dns.digitale-gesellschaft.ch/dns-query?name=outlook.office365.com&type=A").content `
| convertfrom-json).answer `
| ft
name                        type TTL data
----                        ---- --- ----
outlook.office365.com.         5 141 outlook.ha.office365.com.
outlook.ha.office365.com.      5  41 outlook.ms-acdc.office.com.
outlook.ms-acdc.office.com.    5  41 ZRH-efz.ms-acdc.office.com.
ZRH-efz.ms-acdc.office.com.    1   2 52.97.232.210
ZRH-efz.ms-acdc.office.com.    1   2 52.97.201.226
ZRH-efz.ms-acdc.office.com.    1   2 52.98.163.18
ZRH-efz.ms-acdc.office.com.    1   2 52.97.186.146

 

https://dns.quad9.net:5053/dns-query

(Invoke-RestMethod `
   -Uri "https://dns.quad9.net:5053/dns-query?name=outlook.office365.com&type=A").answer `
| ft

Quad9
https://www.quad9.net/de/news/blog/doh-with-quad9-dns-servers/

name                        type TTL data
----                        ---- --- ----
outlook.office365.com.         5 182 outlook.ha.office365.com.
outlook.ha.office365.com.      5  22 outlook.ms-acdc.office.com.
outlook.ms-acdc.office.com.    5  22 SXF-efz.ms-acdc.office.com.
SXF-efz.ms-acdc.office.com.    1  10 52.97.151.114
SXF-efz.ms-acdc.office.com.    1  10 52.97.151.34
SXF-efz.ms-acdc.office.com.    1  10 40.101.60.18

Das Beispiel zeigt, dass je nach angefragtem DoH-Server eine Antwort aus Amsterdam (AMS), Zürich (ZRH) oder Berlin Schönefeld (SXF) kommt. Wenn wir uns in Europa bewegen, dürfte der Umweg nur wenig Auswirkungen haben, da Microsoft die IP-Adressen per BGB ja auch zum Provider des Clients veröffentlicht und der Client selbst schon den kürzesten Weg zur Cloud nutzt. Aber Microsoft routet dann intern die Zugriffe erst zu dem ausgewählten Zielstandort. Siehe auch Outlook Assessment Test. Nur andere Dienste wie Teams und SharePoint, die schon heute mit Anycast-DNS arbeiten, kommen besser damit zurecht. Aber prüfen Sie zukünftig, dass Sie auch den richtigen Cloud-Standort zu ihrem Firmenstandort auflösen.

Anders wird es aber, wenn die Applikation eines Anbieters nicht mehr per klassischem DNS den Zugang zur Cloud sucht sondern seinerseits per DoH individuell den Weg sucht. Der darunterliegende Betriebssystem wird dann nur genutzt, um die Verbindung per HTTPS zum DoH-Server des Applikations-Anbieters aufzubauen aber dann direkt den DoH-Server zu fragen. In der Regel sieht der DoH-Server dann die IP-Adresse des Clients oder des Proxy-Service und kann eine optimierte Antwort liefern.

Ich habe noch keine Informationen, dass Microsoft Office, Teams, OneDrive oder andere Clients schon DoH nutzen.

Weitere Links