Různé aspekty provozu DNS byly autorem již několikrát probrány v rámci publikovaných příspěvků v blogu. Přitom byl vždy kladen hlavní důraz na zvýšení bezpečnosti této klíčové služby pro celý internet.

Až do nedávné doby, i přes zřejmou zranitelnost DNS provozu, který je dosud převážně přenášen otevřeně, pro zlé úmysly ze strany poskytovatelů, kteří se snaží zvýšit své příjmy vložením reklam do obsahu, vládních orgánů a cenzury, stejně jako prostých zločinců, proces , i přes existenci různých technologií, jako jsou DNSSEC/DANE, DNScrypt, DNS-over-TLS a DNS-over-HTTPS, stagnoval. Zatímco serverové řešení, z nichž některé existují již poměrně dlouho, jsou široce známé a dostupné, podpora ze strany uživatelského softwaru zanechává mnoho co do přání.
Naštěstí se situace mění. Konkrétně vývojáři populárního prohlížeče Firefox plánují brzy výchozí podporu pro (DoH). To by mělo pomoci chránit DNS provoz uživatelů WWW před výše uvedenými hrozbami, avšak potenciálně může vyvolat nové.
1. Problémy s DNS-over-HTTPS
Na první pohled začínající masové zavádění DNS-over-HTTPS do softwaru na webu vyvolává pouze pozitivní reakce. Ale, jak se říká, ďábel se skrývá v detailech.
Prvním problémem, který omezuje oblast masového použití DoH, je jeho zaměření výhradně na webový provoz. Opravdu, protokol HTTP a jeho aktuální verze HTTP/2, na níž je DoH založen, je základnou WWW. Ale internet není jen web. Existuje celá řada populárních služeb, jako je e-mail, různé messengery, systémy pro přenos souborů, streaming multimédií a další, které HTTP nevyužívají. Tím pádem, navzdory tomu, že mnozí vnímají DoH jako panaceu, se ukazuje jako nepoužitelný bez dalších (a zbytečných) snah pro něco jiného než webové technologie. Pokud bych měl hovořit, pak by na tuto roli byl mnohem lepším kandidátem DNS-over-TLS, který realizuje enkapsulaci standardního DNS provozu do zabezpečeného standardního protokolu TLS.
Druhým problémem, který je potenciálně mnohem významnější než první, je faktické vzdání se inherentní decentralizace DNS kvůli používání jediného serveru DoH uvedeného v nastavení prohlížeče. Zejména Mozilla doporučuje používat službu od Cloudflare. Podobné služby spustily také jiné významné internetové společnosti, konkrétně Google. Vzniká tak situace, kdy zavedení DNS-over-HTTPS v podobě, v jaké je nyní navrhováno, pouze zvyšuje závislost koncových uživatelů na největších službách. Není žádným tajemstvím, že informace, které může poskytovat analýza DNS dotazů, může shromažďovat ještě více dat o uživatelském chování a také zvyšovat jejich přesnost a aktuálnost.
V této souvislosti byl a zůstává autor zastáncem masového zavedení ne DNS-over-HTTPS, ale DNS-over-TLS společně s DNSSEC/DANE jako univerzálního, bezpečného a neumožňujícího další centralizaci internetu prostředku pro zajištění bezpečnosti DNS trafik. Bohužel není reálné očekávat rychlé zavedení masové podpory alternativ DoH v klientském softwaru kvůli zřejmým důvodům a zbývá to zatím pouze na nadšence bezpečných technologií.
Ale pokud nyní máme DoH, proč ho nevyužít, přičemž se vyhneme možnosti sledování ze strany společností prostřednictvím jejich serverů a přejdeme na vlastní server DNS-over-HTTPS?
2. Protokol DNS-over-HTTPS
Pokud nahlédneme do standardu popisujícího protokol DNS-over-HTTPS, můžeme vidět, že v podstatě představuje webové API, které umožňuje enkapsulaci standardního DNS paketu do protokolu HTTP/2. To se realizuje prostřednictvím speciálních HTTP hlaviček a konverze binárního formátu přenášených DNS dat (viz a další dokumenty) do formátu, který umožňuje jejich přenos a příjem, a také práci s potřebnými metadaty.
Podle standardu je podporováno pouze HTTP/2 a zabezpečené připojení TLS.
Odeslání DNS dotazu může probíhat standardními metodami GET a POST. V prvním případě se dotaz transformuje na base64URL-encoded řetězec, a ve druhém — prostřednictvím těla POST dotazu v binární formě. Při tom se pro dotaz a odpověď DNS používá speciální MIME typ dat 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 intactVěnujte také pozornost hlavičce cache-control: v odpovědi ze strany webového serveru. V parametru max-age je uvedena hodnota TTL pro vracený záznam DNS (nebo minimální hodnota, pokud se vrací jejich skupina).
Na základě výše uvedeného, fungování serveru DoH zahrnuje několik fází.
- Získat HTTP požadavek. Pokud jde o GET, dekódovat paket z base64URL kódování.
- Odeslat tento paket DNS serveru.
- Získat odpověď od DNS serveru.
- Najít minimální hodnotu TTL v získaných záznamech.
- Vrátit klientovi odpověď přes HTTP.
3. Vlastní server DNS-over-HTTPS
Nejjednodušším, nejrychlejším a nejefektivnějším způsobem, jak spustit svůj vlastní server DNS-over-HTTPS, se zdá být použití HTTP/2 webového serveru , o kterém autor již stručně psal (viz „«).
V prospěch této volby hraje skutečnost, že celý kód vlastního serveru DoH může být kompletně implementován prostřednictvím integrovaného interpretu v samotném H2O . Kromě standardních knihoven je pro výměnu dat se serverem DNS potřebná knihovna (mrbgem) Socket, která je, naštěstí, již zahrnuta v aktuální vývojové verzi H2O 2.3.0-beta2. v portech FreeBSD. Nicméně není těžké ji přidat ani do jakékoli předchozí verze klonováním repozitáře. do adresáře /deps před kompilací.
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
===> Uživatel přijal licenci MIT BSD2CLAUSE
===> h2o-2.2.6 závisí na souboru: /usr/local/sbin/pkg - bylo nalezeno
===> Stahování všech distfile potřebných pro h2o-2.2.6 pro sestavení
===> Extrakce pro h2o-2.2.6.
=> SHA256 kontrolní součet OK pro h2o-h2o-v2.2.6_GH0.tar.gz.
===> h2o-2.2.6 závisí na souboru: /usr/local/bin/ruby26 - bylo nalezeno
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
Klonování do „mruby-socket“...
remote: Počítání objektů: 385, hotovo.
remote: Celkem 385 (delta 0), znovu použito 0 (delta 0), pack-reused 385
Přijímání objektů: 100% (385/385), 98.02 KiB | 647.00 KiB/s, hotovo.
Určování změn: 100% (208/208), hotovo.
root@beta:/usr/ports/www/h2o/work/h2o-2.2.6/deps # ll
total 181
drwxr-xr-x 9 root wheel 18 12 srp. 16:09 brotli/
drwxr-xr-x 2 root wheel 4 12 srp. 16:09 cloexec/
drwxr-xr-x 2 root wheel 5 12 srp. 16:09 golombset/
drwxr-xr-x 4 root wheel 35 12 srp. 16:09 klib/
drwxr-xr-x 2 root wheel 5 12 srp. 16:09 libgkc/
drwxr-xr-x 4 root wheel 26 12 srp. 16:09 libyrmcds/
drwxr-xr-x 13 root wheel 32 12 srp. 16:09 mruby/
drwxr-xr-x 5 root wheel 11 12 srp. 16:09 mruby-digest/
drwxr-xr-x 5 root wheel 10 12 srp. 16:09 mruby-dir/
drwxr-xr-x 5 root wheel 10 12 srp. 16:09 mruby-env/
drwxr-xr-x 4 root wheel 9 12 srp. 16:09 mruby-errno/
drwxr-xr-x 5 root wheel 14 12 srp. 16:09 mruby-file-stat/
drwxr-xr-x 5 root wheel 10 12 srp. 16:09 mruby-iijson/
drwxr-xr-x 5 root wheel 11 12 srp. 16:09 mruby-input-stream/
drwxr-xr-x 6 root wheel 11 12 srp. 16:09 mruby-io/
drwxr-xr-x 5 root wheel 10 12 srp. 16:09 mruby-onig-regexp/
drwxr-xr-x 4 root wheel 10 12 srp. 16:09 mruby-pack/
drwxr-xr-x 5 root wheel 10 12 srp. 16:09 mruby-require/
drwxr-xr-x 6 root wheel 10 12 zář. 16:10 mruby-socket/
drwxr-xr-x 2 root wheel 9 12 srp. 16:09 neverbleed/
drwxr-xr-x 2 root wheel 13 12 srp. 16:09 picohttpparser/
drwxr-xr-x 2 root wheel 4 12 srp. 16:09 picotest/
drwxr-xr-x 9 root wheel 16 12 srp. 16:09 picotls/
drwxr-xr-x 4 root wheel 8 12 srp. 16:09 ssl-conservatory/
drwxr-xr-x 8 root wheel 18 12 srp. 16:09 yaml/
drwxr-xr-x 2 root wheel 8 12 srp. 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
...Konfigurace webového serveru je vcelku standardní.
root@beta:\/usr\/ports\/www\/h2o # cd \/usr\/local\/etc\/h2o\/
root@beta:\/usr\/local\/etc\/h2o # cat h2o.conf
# Tato vzorová konfigurace vám ukáže, jak může být h2o použit
# a vysokou bezpečnostní konfiguraci pro TLS a HTTP hlavičky
# viz https:\/\/h2o.examp1e.net\/ pro podrobné dokumentace
# a h2o --help pro možnosti příkazového řádku a nastavení
# v.20180207 (c)2018 od Maxe Kostikova 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.rbVýjimku tvoří pouze zpracovatel URL /dns-query za který je odpovědný náš server DNS-over-HTTPS, napsaný v mruby a vyvolávaný prostřednictvím možnosti zpracovatele mruby.handler-file.
root@beta:/usr/local/etc/h2o # cat h2odoh.rb
# H2O HTTP/2 web server as DNS-over-HTTP service
# 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=/,'')
# base64URL decode
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' }, [ "Bad Request" ]]
else
# --- ask DNS server
sock = UDPSocket.new
sock.connect("localhost", 53)
sock.send(req, 0)
str = sock.recv(4096)
sock.close
# --- find lowest TTL in response
nans = str[6, 2].unpack1('n') # number of answers
if nans > 0 # no DNS failure
shift = 12
ttl = 0
while nans > 0
# process domain name compression
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' }, [ "Unsupported Media Type" ]]
end
}Všimněte si, že za zpracování DNS paketů odpovídá lokální caching server, v tomto případě z standardní verze FreeBSD. Z hlediska bezpečnosti je to optimální řešení. Nicméně nic nebrání tomu, abyste to nahradili localhost adresou jiného DNS, o kterém uvažujete, že ho budete používat.
root@beta:/usr/local/etc/h2o # local-unbound version
usage: local-unbound [options]
start unbound daemon DNS resolver.
-h this help
-c file config file to read instead of /var/unbound/unbound.conf
file format is described in unbound.conf(5).
-d do not fork into the background.
-p do not create a pidfile.
-v verbose (more times to increase verbosity)
Version 1.8.1
linked libs: mini-event internal (it uses select), OpenSSL 1.1.1a-freebsd 20 Nov 2018
linked modules: dns64 respip validator iterator
BSD licensed, see LICENSE in source package for details.
Report bugs to 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 *:*Zbývá restartovat H2O a podívat se, co z toho vyšlo.
root@beta:/usr/local/etc/h2o # service h2o restart
Zastavuji h2o.
Čekám na PIDS: 69871.
Spouštím h2o.
start_server (pid:70532) nyní začíná...4. Testování
Takže zkontrolujeme výsledky tím, že opět zašleme testovací požadavek a podíváme se na síťový provoz pomocí utility tcpdump.
root@beta/usr/local/etc/h2o # curl -H 'accept: application/dns-message' 'https://my.domain/dns-query?dns=q80BAAABAAAAAAAAB2V4YW1wbGUDY29tAAABAAE'
Upozornění: Binární výstup může poškodit váš terminál. Použijte "--output -", aby
Upozornění: curl výstup odeslal do terminálu, nebo zvažte "--output
Upozornění: " pro uložení do souboru.
...
root@beta:~ # tcpdump -n -i lo0 udp port 53 -xx -XX -vv
tcpdump: naslouchá na lo0, typ odkazu NULL (BSD smyčka), velikost zachycení 262144 bytů
16:32:40.420831 IP (tos 0x0, ttl 64, id 37575, offset 0, flags [none], proto UDP (17), délka 57, špatný kontrolní součet 0 (->e9ea)!)
127.0.0.1.21070 > 127.0.0.1.53: [špatný 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), délka 73, špatný kontrolní součet 0 (->e9cb)!)
127.0.0.1.53 > 127.0.0.1.21070: [špatný 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 pakety zachyceny
23 paketů přijato filtrem
0 paketů zahozeno jádremVe výstupu je vidět, jak byl požadavek na rozřešení adresy example.com přijat a úspěšně zpracován DNS serverem.
Nyní zbývá aktivovat náš server v prohlížeči Firefox. K tomu na stránce konfigurace je třeba změnit několik nastavení about:config.

Za prvé, to je adresa našeho API, kam prohlížeč bude posílat žádosti o DNS informace v network.trr.uri. Doporučuje se také uvést IP domény z této URL pro bezpečné rozřešení do IP prostředky samotného prohlížeče bez volání k DNS v network.trr.bootstrapAddress. A nakonec vlastně samotný parametr network.trr.mode který zahrnuje použití DoH. Nastavení hodnoty na "3" donutí prohlížeč používat výhradně DNS-over-HTTPS pro rozřešení názvů, zatímco spolehlivější a bezpečnější "2" dá přednost DoH, přičemž standardní dotaz na DNS zůstane jako záložní možnost.
5. ZISK!
Byl článek užitečný? Pak se nebojte podpořit nás finančně přes formulář pro dary (níže).
Zdroj: habr.com
