De verschillende aspecten van DNS-exploitatie zijn door de auteur al meerdere keren besproken in het kader van het blog. Bij dit alles lag de belangrijkste focus altijd op het verhogen van de beveiliging van deze sleutelservice voor het hele internet.

Tot voor kort, ondanks de duidelijkheid over de kwetsbaarheid van DNS-verkeer, dat voor het grootste deel nog steeds onversleuteld wordt verzonden, was er een proces voor kwaadaardige acties van providers die hun inkomsten wilden verhogen door advertenties in content te integreren, overheidsinstanties en censuur, evenals gewoon criminelen. ondanks het bestaan van verschillende technologieën zoals DNSSEC/DANE, DNScrypt, DNS-over-TLS en DNS-over-HTTPS, was traag. En terwijl serveroplossingen, waarvan sommige al geruime tijd bestaan, algemeen bekend en toegankelijk zijn, laat de ondersteuning vanuit de clientsoftware veel te wensen over.
Gelukkig verandert de situatie. In het bijzonder hebben de ontwikkelaars van de populaire browser Firefox aangekondigd dat ze van plan zijn om binnenkort standaard ondersteuning voor (DoH) in te schakelen. Dit zou moeten helpen om het DNS-verkeer van gebruikers op het WWW te beschermen tegen de eerder genoemde bedreigingen, maar kan ook nieuwe problemen oproepen.
1. Problemen met DNS-over-HTTPS
Op het eerste gezicht roept de grootschalige introductie van DNS-over-HTTPS in internetsoftware alleen maar een positieve reactie op. Maar, zoals het gezegde gaat, ligt de duivel in de details.
Het eerste probleem dat de brede toepassing van DoH beperkt, is dat het zich uitsluitend richt op webverkeer. Inderdaad, het HTTP-protocol en de huidige versie HTTP/2, waarop DoH is gebaseerd, vormen de basis van het WWW. Maar het internet is niet alleen het web. Er zijn veel populaire diensten, zoals e-mail, verschillende berichtenapps, bestandsoverdrachtssystemen, multimedia streaming, enzovoort, die geen gebruik maken van HTTP. Zo blijkt dat, ondanks dat veel mensen DoH als een panacee beschouwen, het niet toepasbaar is zonder aanvullende (toch niet noodzakelijke) inspanningen voor andere technologieën dan browsertechnologieën. Trouwens, DNS-over-TLS lijkt een veel geschiktere kandidaat voor deze rol, omdat het standaard DNS-verkeer insluit in het beveiligde standaardprotocol TLS.
Een tweede probleem, dat potentieel veel significanter is dan het eerste, is de feitelijke afschaffing van de inherente decentralisatie van DNS by design ten gunste van het gebruik van een enkele DoH-server die in de browserinstellingen is opgegeven. In het bijzonder stelt Mozilla voor om de service van Cloudflare te gebruiken. Een dergelijke service is ook gelanceerd door andere prominente spelers op het internet, waaronder Google. Het resultaat is dat de implementatie van DNS-over-HTTPS in de huidige vorm alleen maar de afhankelijkheid van eindgebruikers van de grootste diensten vergroot. Het is geen geheim dat informatie die kan worden verkregen door het analyseren van DNS-verzoeken, nog meer gegevens over hen kan verzamelen en de nauwkeurigheid en relevantie daarvan kan verhogen.
In dit verband was de auteur een voorstander van de massale invoering van niet DNS-over-HTTPS, maar DNS-over-TLS in combinatie met DNSSEC/DANE als een universeel, veilig en niet-centraliserend middel voor het waarborgen van de veiligheid van DNS-verkeer. Helaas hoeven we om begrijpelijke redenen niet snel massale ondersteuning voor alternatieven voor DoH in clientsoftware te verwachten en blijven deze voor nu voorbehouden aan enthousiastelingen van veilige technologieën.
Maar nu we DoH hebben, waarom zouden we het dan niet gebruiken, terwijl we de potentiële surveillance van bedrijven via hun servers vermijden door een eigen DNS-over-HTTPS-server op te zetten?
2. Het DNS-over-HTTPS-protocol
Als we naar de standaard kijken die het DNS-over-HTTPS-protocol beschrijft, zien we dat het in wezen een web-API is die de standaard DNS-pakketencapsuleert in het HTTP/2-protocol. Dit gebeurt door middel van speciale HTTP-headers, evenals de conversie van het binaire formaat van de verzonden DNS-gegevens (zie en de volgende documenten) naar een vorm die het mogelijk maakt om ze te verzenden en te ontvangen, evenals om met de vereiste metadata te werken.
Volgens de standaard wordt alleen HTTP/2 en een beveiligde TLS-verbinding ondersteund.
Een DNS-verzoek kan worden verzonden met de standaardmethoden GET en POST. In het eerste geval wordt het verzoek omgevormd tot een base64URL-gecodeerde string, en in de tweede via de body van het POST-verzoek in binaire vorm. Hierbij wordt een speciale MIME-gegevenssoort gebruikt voor zowel het verzoek als het antwoord van DNS. application/dns-message.
root@eprove:~ # curl -H 'accept: application/dns-message' 'https://my.domaint/dns-query?dns=q80BAAABAAAAAAAAB2V4YW1wbGUDY29tAAABAAE' -v
* Trying 2001:100:200:300::400:443...
* TCP_NODELAY set
* Connected to eprove.net (2001:100:200:300::400) port 443 (#0)
* ALPN, offering h2
* ALPN, offering http/1.1
* successfully set certificate verify locations:
* CAfile: /usr/local/share/certs/ca-root-nss.crt
CApath: none
* TLSv1.3 (OUT), TLS handshake, Client hello (1):
* TLSv1.3 (IN), TLS handshake, Server hello (2):
* TLSv1.3 (IN), TLS handshake, Encrypted Extensions (8):
* TLSv1.3 (IN), TLS handshake, Certificate (11):
* TLSv1.3 (IN), TLS handshake, CERT verify (15):
* TLSv1.3 (IN), TLS handshake, Finished (20):
* TLSv1.3 (OUT), TLS change cipher, Change cipher spec (1):
* TLSv1.3 (OUT), TLS handshake, Finished (20):
* SSL connection using TLSv1.3 / TLS_AES_256_GCM_SHA384
* ALPN, server accepted to use h2
* Server certificate:
* subject: CN=my.domain
* start date: Jul 22 00:07:13 2019 GMT
* expire date: Oct 20 00:07:13 2019 GMT
* subjectAltName: host "my.domain" matched cert's "my.domain"
* issuer: C=US; O=Let's Encrypt; CN=Let's Encrypt Authority X3
* SSL certificate verify ok.
* Using HTTP2, server supports multi-use
* Connection state changed (HTTP/2 confirmed)
* Copying HTTP/2 data in stream buffer to connection buffer after upgrade: len=0
* Using Stream ID: 1 (easy handle 0x801441000)
> GET /dns-query?dns=q80BAAABAAAAAAAAB2V4YW1wbGUDY29tAAABAAE HTTP/2
> Host: eprove.net
> User-Agent: curl/7.65.3
> accept: application/dns-message
>
* TLSv1.3 (IN), TLS handshake, Newsession Ticket (4):
* Connection state changed (MAX_CONCURRENT_STREAMS == 100)!
< HTTP/2 200
< server: h2o/2.3.0-beta2
< content-type: application/dns-message
< cache-control: max-age=86274
< date: Thu, 12 Sep 2019 13:07:25 GMT
< strict-transport-security: max-age=15768000; includeSubDomains; preload
< content-length: 45
<
Warning: Binary output can mess up your terminal. Use "--output -" to tell
Warning: curl to output it to your terminal anyway, or consider "--output
Warning: " to save to a file.
* Failed writing body (0 != 45)
* stopped the pause stream!
* Connection #0 to host eprove.net left intactLet ook op de header cache-control: in het antwoord van de webserver. In de parameter max-age staat de TTL-waarde voor het geretourneerde DNS-record (of de minimale waarde als er meerdere worden geretourneerd).
Op basis van het bovenstaande bestaat de werking van de DoH-server uit verschillende stappen.
- Ontvang de HTTP-aanroep. Als het een GET-verzoek is, decodeer het pakket van base64URL-codering.
- Verstuur dit pakket naar de DNS-server.
- Ontvang een antwoord van de DNS-server.
- Vind de minimale TTL-waarde in de ontvangen records.
- Stuur het antwoord terug naar de client via HTTP.
3. Je eigen DNS-over-HTTPS server
De eenvoudigste, snelste en meest efficiënte manier om je eigen DNS-over-HTTPS server te starten, is door gebruik te maken van een HTTP/2 webserver , waarover de auteur al kort heeft geschreven (zie "«).
Het voordeel van deze keuze is dat de volledige code van de eigen DoH-server volledig kan worden geïmplementeerd met de ingebouwde interpreter van H2O . Naast de standaardbibliotheken is er een bibliotheek (mrbgem) Socket nodig voor het communiceren met de DNS-server, die gelukkig al is opgenomen in de huidige ontwikkelversie H2O 2.3.0-beta2. in de FreeBSD-poorten. Het is echter niet moeilijk om deze toe te voegen in elke eerdere versie door de repository te klonen. in de map /deps voor de compilatie.
root@beta:~ # uname -v
FreeBSD 12.0-RELEASE-p10 GENERIC
root@beta:~ # cd /usr/ports/www/h2o
root@beta:/usr/ports/www/h2o # make extract
=== License MIT BSD2CLAUSE aanvaard door de gebruiker
=== h2o-2.2.6 is afhankelijk van bestand: /usr/local/sbin/pkg - gevonden
=== Alle vereiste distfiles voor h2o-2.2.6 worden gedownload
=== Extractie voor h2o-2.2.6.
=> SHA256 Checksum OK voor h2o-h2o-v2.2.6_GH0.tar.gz.
=== h2o-2.2.6 is afhankelijk van bestand: /usr/local/bin/ruby26 - gevonden
root@beta:/usr/ports/www/h2o # cd work/h2o-2.2.6/deps/
root@beta:/usr/ports/www/h2o/work/h2o-2.2.6/deps # git clone https://github.com/iij/mruby-socket.git
Klonen in ‘mruby-socket’…
remote: Bezig met het opsommen van objecten: 385, gedaan.
remote: Totaal 385 (delta 0), hergebruikt 0 (delta 0), pack-reused 385
Download van objecten: 100% (385/385), 98.02 KiB | 647.00 KiB/s, klaar.
Bepalen van wijzigingen: 100% (208/208), klaar.
root@beta:/usr/ports/www/h2o/work/h2o-2.2.6/deps # ll
totaal 181
drwxr-xr-x 9 root wheel 18 12 aug. 16:09 brotli/
drwxr-xr-x 2 root wheel 4 12 aug. 16:09 cloexec/
drwxr-xr-x 2 root wheel 5 12 aug. 16:09 golombset/
drwxr-xr-x 4 root wheel 35 12 aug. 16:09 klib/
drwxr-xr-x 2 root wheel 5 12 aug. 16:09 libgkc/
drwxr-xr-x 4 root wheel 26 12 aug. 16:09 libyrmcds/
drwxr-xr-x 13 root wheel 32 12 aug. 16:09 mruby/
drwxr-xr-x 5 root wheel 11 12 aug. 16:09 mruby-digest/
drwxr-xr-x 5 root wheel 10 12 aug. 16:09 mruby-dir/
drwxr-xr-x 5 root wheel 10 12 aug. 16:09 mruby-env/
drwxr-xr-x 4 root wheel 9 12 aug. 16:09 mruby-errno/
drwxr-xr-x 5 root wheel 14 12 aug. 16:09 mruby-file-stat/
drwxr-xr-x 5 root wheel 10 12 aug. 16:09 mruby-iijson/
drwxr-xr-x 5 root wheel 11 12 aug. 16:09 mruby-input-stream/
drwxr-xr-x 6 root wheel 11 12 aug. 16:09 mruby-io/
drwxr-xr-x 5 root wheel 10 12 aug. 16:09 mruby-onig-regexp/
drwxr-xr-x 4 root wheel 10 12 aug. 16:09 mruby-pack/
drwxr-xr-x 5 root wheel 10 12 aug. 16:09 mruby-require/
drwxr-xr-x 6 root wheel 10 12 sept. 16:10 mruby-socket/
drwxr-xr-x 2 root wheel 9 12 aug. 16:09 neverbleed/
drwxr-xr-x 2 root wheel 13 12 aug. 16:09 picohttpparser/
drwxr-xr-x 2 root wheel 4 12 aug. 16:09 picotest/
drwxr-xr-x 9 root wheel 16 12 aug. 16:09 picotls/
drwxr-xr-x 4 root wheel 8 12 aug. 16:09 ssl-conservatory/
drwxr-xr-x 8 root wheel 18 12 aug. 16:09 yaml/
drwxr-xr-x 2 root wheel 8 12 aug. 16:09 yoml/
root@beta:/usr/ports/www/h2o/work/h2o-2.2.6/deps # cd ../../..
root@beta:/usr/ports/www/h2o # make install clean
...De configuratie van de webserver is in het algemeen standaard.
root@beta:/usr/ports/www/h2o # cd /usr/local/etc/h2o/
root@beta:/usr/local/etc/h2o # cat h2o.conf
# Deze voorbeeldconfiguratie geeft je een idee van hoe h2o gebruikt kan worden
# en een hoge beveiliging configuratie voor TLS en HTTP headers
# zie https://h2o.examp1e.net/ voor gedetailleerde documentatie
# en h2o --help voor opdrachtregelopties en instellingen
# v.20180207 (c)2018 door Max Kostikov http://kostikov.co e-mail: max@kostikov.co
user: www
pid-file: /var/run/h2o.pid
access-log:
path: /var/log/h2o/h2o-access.log
format: "%h %v %l %u %t "%r" %s %b "%{Referer}i" "%{User-agent}i""
error-log: /var/log/h2o/h2o-error.log
expires: off
compress: on
file.dirlisting: off
file.send-compressed: on
file.index: [ 'index.html', 'index.php' ]
listen:
port: 80
listen:
port: 443
ssl:
cipher-suite: ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES256-SHA:ECDHE-ECDSA-DES-CBC3-SHA:ECDHE-RSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:DES-CBC3-SHA:!DSS
cipher-preference: server
dh-file: /etc/ssl/dhparams.pem
certificate-file: /usr/local/etc/letsencrypt/live/eprove.net/fullchain.pem
key-file: /usr/local/etc/letsencrypt/live/my.domain/privkey.pem
hosts:
"*.my.domain":
paths: &go_tls
"/":
redirect:
status: 301
url: https://my.domain/
"my.domain:80":
paths: *go_tls
"my.domain:443":
header.add: "Strict-Transport-Security: max-age=15768000; includeSubDomains; preload"
paths:
"/dns-query":
mruby.handler-file: /usr/local/etc/h2o/h2odoh.rbEen uitzondering vormt alleen de URL-handler /dns-query waarvoor onze DNS-over-HTTPS server verantwoordelijk is, geschreven in mruby en aangeroepen via de handleroptie mruby.handler-file.
root@beta:usrlocaletch2o # cat h2odoh.rb
# H2O HTTP2 web server als DNS-over-HTTP-dienst
# v.20190908 (c)2018-2019 Max Kostikov https://kostikov.co e-mail: max@kostikov.co
proc {|env|
if env['HTTP_ACCEPT'] == "applicationdns-message"
case env['REQUEST_METHOD']
when "GET"
req = env['QUERY_STRING'].gsub(/^[dns=]/,'')
# base64URL decoderen
req = req.tr("-_", "+/")
if !req.end_with?("=") && req.length % 4 != 0
req = req.ljust((req.length + 3) & ~3, "=")
end
req = req.unpack1("m")
when "POST"
req = env['rack.input'].read
else
req = ""
end
if req.empty?
[400, { 'content-type' => 'text/plain' }, [ "Ongeldig verzoek" ]]
else
# --- vraag de DNS-server
sock = UDPSocket.new
sock.connect("localhost", 53)
sock.send(req, 0)
str = sock.recv(4096)
sock.close
# --- zoek de laagste TTL in het antwoord
nans = str[6, 2].unpack1('n') # aantal antwoorden
if nans > 0 # geen DNS-fout
shift = 12
ttl = 0
while nans > 0
# verwerk domeinnaamcompressie
if str[shift].unpack1("C") curttl
ttl = curttl
end
nans -= 1
end
cc = 'max-age=' + ttl.to_s
else
cc = 'no-cache'
end
[200, { 'content-type' => 'application/dns-message', 'content-length' => str.size, 'cache-control' => cc }, [ str ] ]
end
else
[415, { 'content-type' => 'text/plain' }, [ "Niet ondersteunde media type" ]]
end
}Houd er rekening mee dat de verwerking van DNS-pakketten wordt afgehandeld door de lokale caching-server, in dit geval van de standaardlevering van FreeBSD. Wat betreft veiligheid is dit een optimale oplossing. Echter, er is niets dat voorkomt dat je localhost vervangt door het adres van een andere DNS die je van plan bent te gebruiken.
root@beta:usrlocaletch2o # local-unbound versie
usage: local-unbound [opties]
start unbound daemon DNS-resolver.
-h deze hulp
-c bestand configuratiebestand om te lezen in plaats van /var/unbound/unbound.conf
bestandsindeling is beschreven in unbound.conf(5).
-d niet op de achtergrond fork.
-p maak geen pidfile aan.
-v gedetailleerd (meer keren om de gedetailleerdheid te verhogen)
Versie 1.8.1
gelinkte libs: mini-event intern (het gebruikt select), OpenSSL 1.1.1a-freebsd 20 Nov 2018
gelinkte modules: dns64 respip validator iterator
BSD gelicenseerd, zie LICENSE in het bronpakket voor details.
Meld bugs aan unbound-bugs@nlnetlabs.nl
root@eprove:usrlocaletch2o # sockstat -46 | grep unbound
unbound local-unbo 69749 3 udp6 ::1:53 *:*
unbound local-unbo 69749 4 tcp6 ::1:53 *:*
unbound local-unbo 69749 5 udp4 127.0.0.1:53 *:*
unbound local-unbo 69749 6 tcp4 127.0.0.1:53 *:*Het is tijd om H2O opnieuw op te starten en te kijken wat hier uit voortgekomen is.
root@beta:/usr/local/etc/h2o # service h2o restart
Halt h2o.
Wachten op PIDs: 69871.
Starten h2o.
start_server (pid:70532) start nu...4. Testen
Laten we de resultaten controleren door opnieuw een testverzoek te versturen en het netwerkverkeer te bekijken met behulp van de tool. tcpdump.
root@beta/usr/local/etc/h2o # curl -H 'accept: application/dns-message' 'https://my.domain/dns-query?dns=q80BAAABAAAAAAAAB2V4YW1wbGUDY29tAAABAAE'
Waarschuwing: Binaire output kan je terminal verstoren. Gebruik "--output -" om
Waarschuwing: curl te vertellen het naar je terminal te outputten, of overweeg "--output
Waarschuwing: " om het naar een bestand te bewaren.
...
root@beta:~ # tcpdump -n -i lo0 udp port 53 -xx -XX -vv
tcpdump: luistert op lo0, link-type NULL (BSD loopback), capturegrootte 262144 bytes
16:32:40.420831 IP (tos 0x0, ttl 64, id 37575, offset 0, flags [none], proto UDP (17), lengte 57, slechte cksum 0 (->e9ea)!)
127.0.0.1.21070 > 127.0.0.1.53: [slechte udp cksum 0xfe38 -> 0x33e3!] 43981+ A? example.com. (29)
0x0000: 0200 0000 4500 0039 92c7 0000 4011 0000 ....E..9....@...
0x0010: 7f00 0001 7f00 0001 524e 0035 0025 fe38 ........RN.5.%.8
0x0020: abcd 0100 0001 0000 0000 0000 0765 7861 .............exa
0x0030: 6d70 6c65 0363 6f6d 0000 0100 01 mple.com.....
16:32:40.796507 IP (tos 0x0, ttl 64, id 37590, offset 0, flags [none], proto UDP (17), lengte 73, slechte cksum 0 (->e9cb)!)
127.0.0.1.53 > 127.0.0.1.21070: [slechte udp cksum 0xfe48 -> 0x43fa!] 43981 q: A? example.com. 1/0/0 example.com. A 93.184.216.34 (45)
0x0000: 0200 0000 4500 0049 92d6 0000 4011 0000 ....E..I....@...
0x0010: 7f00 0001 7f00 0001 0035 524e 0035 fe48 .........5RN.5.H
0x0020: abcd 8180 0001 0001 0000 0000 0765 7861 .............exa
0x0030: 6d70 6c65 0363 6f6d 0000 0100 01c0 0c00 mple.com........
0x0040: 0100 0100 0151 8000 045d b8d8 22 .....Q...].."
^C
2 pakketten gevangen
23 pakketten ontvangen door filter
0 pakketten droppen door de kernelIn de output is te zien hoe het verzoek voor adresresolutie example.com is ontvangen en succesvol verwerkt door de DNS-server.
Nu moet onze server geactiveerd worden in de Firefox-browser. Hiervoor moeten enkele instellingen op de configuratiepagina worden gewijzigd. about:config.

Ten eerste is dit het adres van onze API waar de browser DNS-informatie zal opvragen in network.trr.uri. Het wordt ook aanbevolen om het IP-adres van dit URL op te geven voor veilige resolutie naar IP door de browser zelf zonder DNS-queries in network.trr.bootstrapAddress. En tot slot, de parameter network.trr.mode die het gebruik van DoH inschakelt. Het instellen van de waarde op «3» dwingt de browser om uitsluitend DNS-over-HTTPS te gebruiken voor het oplossen van namen, terwijl een meer betrouwbare en veilige «2» prioriteit geeft aan DoH, met standaard DNS-oproepen als back-up.
5. PROFIT!
Was dit artikel nuttig? Aarzel dan niet om financiële steun te geven via het donatieformulier (hieronder).
Bron: habr.com
