Diverse aspetti dell'uso del DNS sono già stati trattati più volte dall'autore in una serie di articoli pubblicati nel blog. In particolare, l'accento è sempre stato posto sull'aumento della sicurezza di questo servizio chiave per l'intero Internet.

Fino a poco tempo fa, nonostante l'evidenza della vulnerabilità del traffico DNS, che, per la maggior parte, viene ancora trasmesso in chiaro, a causa di azioni malevole da parte di provider che cercano di aumentare i propri guadagni attraverso l'inserimento di pubblicità nei contenuti, di enti governativi e di censura, così come di semplici criminali, il processo , nonostante l'esistenza di varie tecnologie come DNSSEC/DANE, DNScrypt, DNS-over-TLS e DNS-over-HTTPS, ha stentato a decollare. E sebbene le soluzioni servitoriali, di alcune delle quali esistono da tempo, siano ampiamente conosciute e disponibili, il supporto da parte del software client lascia molto a desiderare.
Fortunatamente, la situazione sta cambiando. In particolare, gli sviluppatori del popolare browser Firefox hanno annunciato piani per l'inclusione predefinita del supporto per (DoH) a breve. Questo dovrebbe aiutare a proteggere il traffico DNS degli utenti WWW dalle minacce menzionate in precedenza, ma potenzialmente potrebbe anche generare nuovi problemi.
1. Problemi di DNS-over-HTTPS
A prima vista, l'imminente adozione di massa di DNS-over-HTTPS nel software operativo su Internet provoca solo reazioni positive. Tuttavia, come si dice, il diavolo è nei dettagli.
Il primo problema che limita l'adozione di massa di DoH è la sua orientazione esclusivamente verso il traffico web. Infatti, il protocollo HTTP e la sua attuale versione HTTP/2, su cui si basa DoH, costituiscono le fondamenta del WWW. Ma Internet non è solo web. Esistono molti servizi popolari, come la posta elettronica, vari messaggeri, sistemi di trasferimento file, streaming multimediale e altro, che non utilizzano HTTP. Pertanto, nonostante la percezione di molti che DoH sia una panacea, esso risulta inapplicabile senza sforzi aggiuntivi (e non necessari) per niente al di fuori delle tecnologie browser. A dire il vero, DNS-over-TLS si presenta come un candidato molto più valido per questo ruolo, dal momento che incapsula il traffico DNS standard in un protocollo standard protetto TLS.
Un secondo problema, che è potenzialmente molto più significativo del primo, è il rifiuto effettivo della decentramento intrinseco del DNS by design a favore dell'uso di un singolo server DoH indicato nelle impostazioni del browser. In particolare, Mozilla propone di utilizzare il servizio di Cloudflare. Servizi simili sono stati lanciati anche da altre figure di spicco di Internet, in particolare Google. Di conseguenza, l'implementazione del DNS-over-HTTPS così come viene proposta attualmente aumenta soltanto la dipendenza degli utenti finali dai più grandi servizi. Non è un segreto che le informazioni ottenibili dall'analisi delle richieste DNS possano raccogliere ulteriori dati su di essi, oltre a migliorarne la precisione e la praticità.
In questo contesto, l'autore è e rimane un sostenitore dell'adozione di massa non del DNS-over-HTTPS, ma del DNS-over-TLS insieme a DNSSEC/DANE come soluzione universale, sicura e non favorevole a ulteriore centralizzazione della rete per garantire la sicurezza del traffico DNS. Sfortunatamente, non si può sperare in un'implementazione rapida del supporto di massa per alternative a DoH nel software client, per ovvi motivi, e attualmente è nelle mani di appassionati di tecnologie sicure.
Ma, dato che ora abbiamo il DoH, perché non sfruttarlo, allontanandoci dalla potenziale sorveglianza da parte delle corporation tramite i loro server a favore di un proprio server DNS-over-HTTPS?
2. Protocollo DNS-over-HTTPS
Se si guarda allo standard che descrive il protocollo DNS-over-HTTPS, si può vedere che, sostanzialmente, rappresenta un'API web che permette di incapsulare un pacchetto DNS standard nel protocollo HTTP/2. Questo viene realizzato tramite intestazioni HTTP speciali, nonché la conversione del formato binario dei dati DNS trasmessi (vedi e i documenti successivi) in una forma che consente di trasmetterli e riceverli, nonché di lavorare con i metadati necessari.
Secondo lo standard, è supportato solo HTTP/2 e connessioni sicure TLS.
L'invio di una richiesta DNS può avvenire tramite i metodi standard GET e POST. Nel primo caso, la richiesta viene trasformata in una stringa base64URL-encoded, mentre nel secondo attraverso il corpo della richiesta POST in forma binaria. In questo caso, durante la richiesta e la risposta DNS viene utilizzato un MIME-type speciale 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 intactSi noti anche l'intestazione cache-control: nella risposta del server web. Nel parametro max-age è presente il valore TTL per il record DNS restituito (o il valore minimo se ne viene restituito un insieme).
Pertanto, il funzionamento del server DoH avviene in diversi passaggi.
- Ricevere la richiesta HTTP. Se è una richiesta GET, decodificare il pacchetto da base64URL.
- Inviare questo pacchetto al server DNS.
- Ricevere la risposta dal server DNS
- Trovare il valore minimo TTL nei record ricevuti.
- Restituire la risposta al client via HTTP.
3. Il proprio server DNS-over-HTTPS
Il modo più semplice, veloce ed efficace per avviare il proprio server DNS-over-HTTPS è utilizzare un web server HTTP/2 , di cui l'autore ha parlato brevemente in precedenza (vedi "«).
A favore di questa scelta, c'è il fatto che tutto il codice del proprio server DoH può essere completamente implementato attraverso l'interprete integrato in H2O stesso, . Oltre alle librerie standard, è necessaria la libreria (mrbgem) Socket per scambiare dati con il server DNS, che, fortunatamente, è già inclusa nella versione attuale di sviluppo H2O 2.3.0-beta2 nelle porte di FreeBSD. Tuttavia, non è difficile aggiungerla anche in una qualsiasi versione precedente clonando il repository nella cartella /deps prima della compilazione.
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
===> Licenza MIT BSD2CLAUSE accettata dall'utente
===> h2o-2.2.6 dipende dal file: /usr/local/sbin/pkg - trovato
===> Recuperando tutti i file di distribuzione necessari per h2o-2.2.6 per la compilazione
===> Estraendo per h2o-2.2.6.
=> Controllo SHA256 OK per h2o-h2o-v2.2.6_GH0.tar.gz.
===> h2o-2.2.6 dipende dal file: /usr/local/bin/ruby26 - trovato
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
Cloning into 'mruby-socket'…
remote: Enumerating objects: 385, done.
remote: Totale 385 (delta 0), riutilizzati 0 (delta 0), pack-reused 385
Ricezione oggetti: 100% (385/385), 98.02 KiB | 647.00 KiB/s, fatto.
Determinazione delle modifiche: 100% (208/208), fatto.
root@beta:/usr/ports/www/h2o/work/h2o-2.2.6/deps # ll
total 181
drwxr-xr-x 9 root wheel 18 12 ago. 16:09 brotli/
drwxr-xr-x 2 root wheel 4 12 ago. 16:09 cloexec/
drwxr-xr-x 2 root wheel 5 12 ago. 16:09 golombset/
drwxr-xr-x 4 root wheel 35 12 ago. 16:09 klib/
drwxr-xr-x 2 root wheel 5 12 ago. 16:09 libgkc/
drwxr-xr-x 4 root wheel 26 12 ago. 16:09 libyrmcds/
drwxr-xr-x 13 root wheel 32 12 ago. 16:09 mruby/
drwxr-xr-x 5 root wheel 11 12 ago. 16:09 mruby-digest/
drwxr-xr-x 5 root wheel 10 12 ago. 16:09 mruby-dir/
drwxr-xr-x 5 root wheel 10 12 ago. 16:09 mruby-env/
drwxr-xr-x 4 root wheel 9 12 ago. 16:09 mruby-errno/
drwxr-xr-x 5 root wheel 14 12 ago. 16:09 mruby-file-stat/
drwxr-xr-x 5 root wheel 10 12 ago. 16:09 mruby-iijson/
drwxr-xr-x 5 root wheel 11 12 ago. 16:09 mruby-input-stream/
drwxr-xr-x 6 root wheel 11 12 ago. 16:09 mruby-io/
drwxr-xr-x 5 root wheel 10 12 ago. 16:09 mruby-onig-regexp/
drwxr-xr-x 4 root wheel 10 12 ago. 16:09 mruby-pack/
drwxr-xr-x 5 root wheel 10 12 ago. 16:09 mruby-require/
drwxr-xr-x 6 root wheel 10 12 set. 16:10 mruby-socket/
drwxr-xr-x 2 root wheel 9 12 ago. 16:09 neverbleed/
drwxr-xr-x 2 root wheel 13 12 ago. 16:09 picohttpparser/
drwxr-xr-x 2 root wheel 4 12 ago. 16:09 picotest/
drwxr-xr-x 9 root wheel 16 12 ago. 16:09 picotls/
drwxr-xr-x 4 root wheel 8 12 ago. 16:09 ssl-conservatory/
drwxr-xr-x 8 root wheel 18 12 ago. 16:09 yaml/
drwxr-xr-x 2 root wheel 8 12 ago. 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
...La configurazione del server web è, in generale, standard.
root@beta:\/usr\/ports\/www\/h2o # cd \/usr\/local\/etc\/h2o\/\nroot@beta:\/usr\/local\/etc\/h2o # cat h2o.conf\n# questo esempio di configurazione ti dà un'idea di come h2o può essere utilizzato\n# e una configurazione ad alta sicurezza per TLS e intestazioni HTTP\n# consulta https:\/\/h2o.examp1e.net\/ per la documentazione dettagliata\n# e h2o --help per le opzioni e le impostazioni della riga di comando\n\n# v.20180207 (c)2018 di Max Kostikov http:\/\/kostikov.co e-mail: max@kostikov.co\n\nuser: www\npid-file: \/var\/run\/h2o.pid\naccess-log:\n path: \/var\/log\/h2o\/h2o-access.log\n format: "%h %v %l %u %t "%r" %s %b "%{Referer}i" "%{User-agent}i""\nerror-log: \/var\/log\/h2o\/h2o-error.log\n\nexpires: off\ncompress: on\nfile.dirlisting: off\nfile.send-compressed: on\n\nfile.index: [ 'index.html', 'index.php' ]\n\nlisten:\n port: 80\nlisten:\n port: 443\n ssl:\n 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\n cipher-preference: server\n dh-file: \/etc\/ssl\/dhparams.pem\n certificate-file: \/usr\/local\/etc\/letsencrypt\/live\/eprove.net\/fullchain.pem\n key-file: \/usr\/local\/etc\/letsencrypt\/live\/my.domain\/privkey.pem\n\nhosts:\n "*.my.domain":\n paths: &go_tls\n "\/":\n redirect:\n status: 301\n url: https:\/\/my.domain\/\n "my.domain:80":\n paths: *go_tls\n "my.domain:443":\n header.add: "Strict-Transport-Security: max-age=15768000; includeSubDomains; preload"\n paths:\n "\/dns-query":\n mruby.handler-file: \/usr\/local\/etc\/h2o\/h2odoh.rbL'unica eccezione è il gestore URL /dns-query di cui è responsabile il nostro server DNS-over-HTTPS, scritto in mruby e invocato tramite l'opzione del gestore mruby.handler-file.
root@beta: /usr/local/etc/h2o # cat h2odoh.rb
# H2O HTTP/2 web server come servizio DNS-over-HTTP
# v.20190908 (c)2018-2019 Max Kostikov https://kostikov.co e-mail: max@kostikov.co
proc {|env|
if env['HTTP_ACCEPT'] == "application/dns-message"
case env['REQUEST_METHOD']
when "GET"
req = env['QUERY_STRING'].gsub(/^dns=/,'')
# decodifica base64URL
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' }, [ "Richiesta non valida" ]]
else
# --- richiesta al server DNS
sock = UDPSocket.new
sock.connect("localhost", 53)
sock.send(req, 0)
str = sock.recv(4096)
sock.close
# --- trova il TTL più basso nella risposta
nans = str[6, 2].unpack1('n') # numero di risposte
if nans > 0 # nessun errore DNS
shift = 12
ttl = 0
while nans > 0
# elabora la compressione del nome di dominio
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' }, [ "Tipo di media non supportato" ]]
end
}È importante notare che il pacchetto DNS è gestito da un server locale di caching, in questo caso dalla fornitura standard di FreeBSD. In termini di sicurezza, questa è la soluzione ottimale. Tuttavia, nulla impedisce di sostituire localhost con l'indirizzo di un altro DNS che intendi utilizzare.
root@beta: /usr/local/etc/h2o # local-unbound version
uso: local-unbound [opzioni]
avvia il demone unbound risolutore DNS.
-h questa aiuto
-c file file di configurazione da leggere invece di /var/unbound/unbound.conf
il formato del file è descritto in unbound.conf(5).
-d non fork nel background.
-p non creare un file pid.
-v dettagliato (più volte per aumentare la verbosità)
Versione 1.8.1
librerie collegate: mini-event interno (usa select), OpenSSL 1.1.1a-freebsd 20 Nov 2018
moduli collegati: dns64 respip validator iterator
Licenza BSD, vedere LICENSE nel pacchetto sorgente per i dettagli.
Segnala bug a unbound-bugs@nlnetlabs.nl
root@eprove: /usr/local/etc/h2o # 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 *:*Rimane da riavviare H2O e vedere cosa è successo.
root@beta:/usr/local/etc/h2o # service h2o restart
Arresto h2o.
Aspettando PIDS: 69871.
Avviando h2o.
start_server (pid:70532) avvio ora...4. Testing
Ora, verifichiamo i risultati inviando nuovamente una richiesta di prova e osservando il traffico di rete con l'utilità tcpdump.
root@beta/usr/local/etc/h2o # curl -H 'accept: application/dns-message' 'https://my.domain/dns-query?dns=q80BAAABAAAAAAAAB2V4YW1wbGUDY29tAAABAAE'
Attenzione: l'output binario può rovinare il tuo terminale. Usa "--output -" per dire
Attenzione: curl di output in terminale comunque, o considera "--output
Attenzione: " per salvare in un file.
...
root@beta:~ # tcpdump -n -i lo0 udp port 53 -xx -XX -vv
tcpdump: in ascolto su lo0, tipo link NULL (BSD loopback), dimensione cattura 262144 byte
16:32:40.420831 IP (tos 0x0, ttl 64, id 37575, offset 0, flags [none], proto UDP (17), length 57, bad cksum 0 (->e9ea)!)
127.0.0.1.21070 > 127.0.0.1.53: [bad 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), length 73, bad cksum 0 (->e9cb)!)
127.0.0.1.53 > 127.0.0.1.21070: [bad 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 pacchetti catturati
23 pacchetti ricevuti dal filtro
0 pacchetti persi dal kernelDall'output si può vedere come la richiesta per la risoluzione dell'indirizzo example.com sia stata ricevuta e elaborata con successo dal server DNS.
Ora dobbiamo attivare il nostro server nel browser Firefox. A questo scopo, è necessario modificare alcune impostazioni nella pagina di configurazione about:config.

In primo luogo, è l'indirizzo della nostra API al quale il browser farà richiesta di informazioni DNS nel network.trr.uri. È consigliabile anche specificare l'IP del dominio di questo URL per una risoluzione sicura in IP tramite il browser stesso senza rivolgersi al DNS in network.trr.bootstrapAddress. E infine, il parametro stesso network.trr.mode che attiva l'uso di DoH. Impostare il valore su "3" costringerà il browser a usare esclusivamente DNS-over-HTTPS per la risoluzione dei nomi, mentre un'opzione più sicura e affidabile "2" darà priorità a DoH lasciando le tradizionali richieste DNS come opzione di riserva.
5. PROFITTO!
L'articolo è stato utile? Allora non esitare a sostenerci attraverso il modulo di donazione (sotto).
Fonte: habr.com
