Atsevišķi DNS izmantošanas aspekti jau vairākkārt ir aplūkoti autors dažos publicētajos emuāra ierakstos. Tomēr galvenā uzmanība vienmēr tika pievērsta šī nozīmīgā interneta pakalpojuma drošības uzlabošanai.

Līdz pēdējam laikam, neskatoties uz acīmredzamām DNS datu plūsmas ievainojamībām, kas joprojām tiek nosūtīta lielākoties atklātā veidā, ļaunprātīgiem nodomiem no pakalpojumu sniedzējiem, kurus interesē ieņēmumu palielināšana, iekļaujot reklāmas saturā, valsts varas iestādēm un cenzūrai, kā arī vienkāršiem noziedzniekiem, process , neskatoties uz to, ka pastāv dažādas tehnoloģijas, piemēram, DNSSEC/DANE, DNScrypt, DNS-over-TLS un DNS-over-HTTPS bija lēns. Un, ja servera risinājumi, daži no kuriem pastāv jau ilgu laiku, ir plaši zināmi un pieejami, tad atbalsts no klientu programmatūras puses atstāj vēlēšanos.
Par laimi, situācija mainās. Proti, populārā pārlūkprogrammas Firefox par plāniem iekļaut noklusējuma režīmā (DoH) tuvā nākotnē. Tam vajadzētu palīdzēt aizsargāt WWW lietotāju DNS datu plūsmu no iepriekš minētajiem draudiem, taču potenciāli var radīt jaunas.
1. DNS-over-HTTPS problēmas
Pirmajā mirklī masveida DNS-over-HTTPS ieviešana programmatūrā, kas darbojas internetā, rada tikai pozitīvu reakciju. Tomēr, kā saka, sīkumos slēpjas velns.
Pirma problēma, kas ierobežo DoH plašu ieviešanu, ir tā orientācija tikai uz tīmekļa trafiku. Patiesībā HTTP protokols un tā aktuālā redakcija HTTP/2, uz kuras pamata balstās DoH, ir WWW pamatā. Taču internets nav tikai tīmeklis. Pastāv milzīgs skaits populāru pakalpojumu, piemēram, elektroniskā pasta, dažādu ziņojumapmaiņas pakalpojumu, datu pārsūtīšanas sistēmu, multivides straumēšanas u.c., kas neizmanto HTTP. Tādējādi, neskatoties uz to, ka daudzi DoH uztver kā panaceju, tas izrādās neizmantojams bez papildu (un nevajadzīgām) pūlēm nekam citam, izņemot pārlūkprogrammu tehnoloģijas. Jāatzīmē, ka uz šo lomu daudz piemērotāks ir DNS-over-TLS, kas īsteno standarta DNS trafika enkapsulāciju drošā standarta TLS protokolā.
Otrā problēma, kas potenciāli ir daudz nozīmīgāka par pirmo, ir faktiskā atteikšanās no DNS dabiski decentralizētā rakstura, labojot pārlūkprogrammas iestatījumos norādīto DoH serveri. Proti, Mozilla piedāvā izmantot Cloudflare pakalpojumu. Līdzīgu pakalpojumu ir uzsākuši arī citi ievērojami interneta dalībnieki, tostarp Google. Izrādās, ka DNS-over-HTTPS ieviešana šādā veidā tikai palielina galalietotāju atkarību no lielākajiem pakalpojumiem. Nav noslēpums, ka informāciju, ko var sniegt DNS pieprasījumu analīze, var savākt vēl lielākus datus par tiem, kā arī palielināt to precizitāti un aktualitāti.
Šajā sakarā autors ir un paliek masu ieviešanas atbalstītājs nevis DNS-over-HTTPS, bet gan DNS-over-TLS kopā ar DNSSEC/DANE kā vispārēju, drošu un neizsaucot interneta tālāku centralizāciju, risinājumu DNS trafika drošībai. Diemžēl nav cerību uz ātru alternatīvām DoH masveida atbalstu klientu programmā saprotamu iemeslu dēļ, un šī joma pagaidām pieder drošu tehnoloģiju entuziastiem.
Bet, ja nu mēs tagad saņemam DoH, tad kāpēc to neizmantot, iepriekš izvairoties no potenciālās uzraudzības no korporācijām, izmantojot viņu serverus, uz savu personīgo DNS-over-HTTPS serveri?
2. Protokols DNS-over-HTTPS
Ja paskatāmies standartā Apskatot DNS-over-HTTPS protokolu, var redzēt, ka tas pamatā ir tīmekļa API, kas ļauj iesaiņot standarta DNS paketi HTTP/2 protokolā. Tas tiek īstenots, izmantojot īpašus HTTP galvenes, kā arī pārveidojot pārsūtīto DNS datu bināro formātu (skat. un tālākos dokumentus) formā, kas ļauj tos pārsūtīt un saņemt, kā arī strādāt ar nepieciešamajiem metadatiem.
Standarts atbalsta tikai HTTP/2 un drošu TLS savienojumu.
DNS pieprasījuma nosūtīšana var tikt veikta ar standarta GET un POST metodēm. Pirmajā gadījumā pieprasījums tiek pārvērsts base64URL-encoded virknē, bet otrajā — caur POST pieprasījuma ķermeni binārā formātā. Pieprasījumam un atbildei uz DNS tiek izmantots īpašs MIME datu tips application/dns-message.
root@eprove:~ # curl -H 'accept: application/dns-message' 'https://my.domaint/dns-query?dns=q80BAAABAAAAAAAAB2V4YW1wbGUDY29tAAABAAE' -v
* Mēģina 2001:100:200:300::400:443...
* TCP_NODELAY iestatīts
* Savienots ar eprove.net (2001:100:200:300::400) ports 443 (#0)
* ALPN, piedāvā h2
* ALPN, piedāvā http/1.1
* veiksmīgi iestatītas sertifikātu pārbaudes atrašanās vietas:
* CAfail: /usr/local/share/certs/ca-root-nss.crt
CApath: nav
* TLSv1.3 (OUT), TLS roku spiediens, Klienta sveiciens (1):
* TLSv1.3 (IN), TLS roku spiediens, Servera sveiciens (2):
* TLSv1.3 (IN), TLS roku spiediens, Šifrētas paplašinājumi (8):
* TLSv1.3 (IN), TLS roku spiediens, Sertifikāts (11):
* TLSv1.3 (IN), TLS roku spiediens, CERT pārbaude (15):
* TLSv1.3 (IN), TLS roku spiediens, Pabeigt (20):
* TLSv1.3 (OUT), TLS maina šifru, Maina šifra spec (1):
* TLSv1.3 (OUT), TLS roku spiediens, Pabeigt (20):
* SSL savienojums izmanto TLSv1.3 / TLS_AES_256_GCM_SHA384
* ALPN, serveris pieņēma lietot h2
* Servera sertifikāts:
* subjekts: CN=my.domain
* sākuma datums: Jul 22 00:07:13 2019 GMT
* beigu datums: Oct 20 00:07:13 2019 GMT
* subjectAltName: viesis "my.domain" sakrīt ar sertifikāta "my.domain"
* izsniedzējs: C=US; O=Let's Encrypt; CN=Let's Encrypt Authority X3
* SSL sertifikāts pārbaudīts.
* Izmantojot HTTP2, serveris atbalsta multi-use
* Savienojuma stāvoklis mainījies (HTTP/2 apstiprināts)
* Kopējot HTTP/2 datus plūsmas buferī uz savienojuma buferi pēc atjaunināšanas: garums=0
* Izmantojot plūsmas ID: 1 (viegls rokturis 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 roku spiediens, Jaunais sesijas biļetens (4):
* Savienojuma stāvoklis mainījies (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
<
Brīdinājums: binārā izeja var sabojāt jūsu termināli. Izmantojiet "--output -", lai pateiktu
Brīdinājums: curl to izvadīt terminālā, vai apsveriet "--output
Brīdinājums: <FILE>", lai saglabātu failā.
* Neizdevās rakstīt ķermeni (0 != 45)
* apstājies pauzes plūsmā!
* Savienojums #0 ar viesi eprove.net palicis nepārtrauktsLūdzu, ņemiet vērā arī galveni cache-control: atbildē no tīmekļa servera. Parametrā max-age ir TTL vērtība atgrieztajai DNS ierakstam (vai minimālā vērtība, ja tiek atgriezta to kopums).
Pamatojoties uz iepriekš minēto, DoH servera darbība sastāv no vairākiem posmiem.
- Saņemt HTTP pieprasījumu. Ja tas ir GET, tad dekodēt paketi no base64URL kodēšanas.
- Nosūtīt šo paketi DNS serverim.
- Saņemt atbildi no DNS servera.
- Atrast minimālo TTL vērtību saņemtajos ierakstos.
- Atgriezt klientam atbildi pa HTTP.
3. Savs DNS-over-HTTPS serveris
Visvienkāršākais, ātrākais un efektīvākais veids, kā izveidot savu DNS-over-HTTPS serveri, ir izmantot HTTP/2 tīmekļa serveri. , par kuru autors jau īsumā rakstījis (skat. „«).
Par labu šai izvēlei spēlē fakts, ka visu savu DoH servera kodu var pilnībā īstenot, izmantojot H2O integrēto . Papildus standarta bibliotēkām datu apmaiņai ar DNS serveri nepieciešama bibliotēka (mrbgem) Socket, kas, par laimi, jau ir iekļauta pašreizējā izstrādes versijā H2O 2.3.0-beta2. FreeBSD portos. Tomēr nav grūti pievienot to jebkurai iepriekšējai versijai, klonējot repozitoriju. katalogā /deps pirms kompilācijas.
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 accepted by the user
===> h2o-2.2.6 depends on file: /usr/local/sbin/pkg - found
===> Fetching all distfiles required by h2o-2.2.6 for building
===> Extracting for h2o-2.2.6.
=> SHA256 Checksum OK for h2o-h2o-v2.2.6_GH0.tar.gz.
===> h2o-2.2.6 depends on file: /usr/local/bin/ruby26 - found
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
Klonēšana "mruby-socket"…
remote: Enumerating objects: 385, done.
remote: Total 385 (delta 0), reused 0 (delta 0), pack-reused 385
Iegūst objekti: 100% (385/385), 98.02 KiB | 647.00 KiB/s, gatavs.
Izmaiņu noteikšana: 100% (208/208), gatavs.
root@beta:/usr/ports/www/h2o/work/h2o-2.2.6/deps # ll
total 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
...Vietējā tīmekļa servera konfigurācija ir standartā.
root@beta:‹/usr/ports/www/h2o # cd ‹/usr/local/etc/h2o/ root@beta:‹/usr/local/etc/h2o # cat h2o.conf # šis paraugs konfigurācija sniedz jums sajūtu par to, kā h2o var tikt izmantots # un augstas drošības konfigurāciju TLS un HTTP galviņām # skatiet https://h2o.examp1e.net/ detalizētai dokumentācijai # un h2o --help komandrindas opcijām un iestatījumiem # v.20180207 (c)2018 by Max Kostikov http://kostikov.co e-pasts: 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.rbIzņēmums ir tikai URL apstrādātājs /dns-query par kuru atbild mūsu DNS-over-HTTPS servers, kas uzrakstīts mruby valodā un tiek izsaukts caur apstrādātāja opciju mruby.handler-file.
root@beta:\/usr\/local\/etc\/h2o # cat h2odoh.rb\n# H2O HTTP\/2 tīmekļa serveris kā DNS-over-HTTP pakalpojums\n# v.20190908 (c)2018-2019 Max Kostikov https:\/\/kostikov.co e-pasts: max@kostikov.co\n\nproc {|env|\n if env['HTTP_ACCEPT'] == "application\/dns-message"\n case env['REQUEST_METHOD']\n when "GET"\n req = env['QUERY_STRING'].gsub(\/^dns=\/, '')\n # base64URL dekodēšana\n req = req.tr("-_", "+\/")\n if !req.end_with?("=") && req.length % 4 != 0\n req = req.ljust((req.length + 3) & ~3, "=")\n end\n req = req.unpack1("m")\n when "POST"\n req = env['rack.input'].read\n else\n req = ""\n end\n if req.empty?\n [400, { 'content-type' => 'text\/plain' }, [ "Slikta pieprasījums" ]]\n else\n # --- jautā DNS serverim\n sock = UDPSocket.new\n sock.connect("localhost", 53)\n sock.send(req, 0)\n str = sock.recv(4096)\n sock.close\n # --- atrod zemāko TTL atbildē\n nans = str[6, 2].unpack1('n') # atbilžu skaits\n if nans > 0 # nav DNS kļūdas\n shift = 12\n ttl = 0\n while nans > 0\n # apstrādā domēna nosaukuma kompresiju\n if str[shift].unpack1("C") < 192\n shift = str.index("x00", shift) + 5\n if ttl == 0 # izlaiž jautājumu daļu\n next\n end\n end\n shift += 6\n curttl = str[shift, 4].unpack1('N')\n shift += str[shift + 4, 2].unpack1('n') + 6 # atbildes datu izmērs\n if ttl == 0 or ttl > curttl\n ttl = curttl\n end\n nans -= 1\n end\n cc = 'max-age=' + ttl.to_s\n else\n cc = 'nav-kešs'\n end\n [200, { 'content-type' => 'application\/dns-message', 'content-length' => str.size, 'cache-control' => cc }, [ str ] ]\n end\n else\n [415, { 'content-type' => 'text\/plain' }, [ "Nenoturams mediju veids" ]]\n end\n}Lūdzu, ņemiet vērā, ka DNS paketēm apstrādi veic lokālais kešatmiņas serveris šajā gadījumā no standarta FreeBSD piegādes. No drošības viedokļa tas ir optimāls risinājums. Tomēr nekas netraucē to aizstāt localhost ar citu DNS adresi, kuru plānojat izmantot.
root@beta:\/usr\/local\/etc\/h2o # local-unbound versija\nizmantošana: local-unbound [opcijas]\n uzsākt unbound deamona DNS risinātāju.\n-h šī palīdzība\n-c fails konfigurācijas fails, ko lasīt, nevis \/var\/unbound\/unbound.conf\n faila formāts ir aprakstīts unbound.conf(5).\n-d nemainīt fonu.\n-p neradīt pidfailu.\n-v detalizēti (vairākas reizes, lai palielinātu detalizācijas pakāpi)\nVersija 1.8.1\npiesaistītās bibliotēkas: mini-event iekšējais (tas izmanto select), OpenSSL 1.1.1a-freebsd 20 Nov 2018\npiesaistītie moduļi: dns64 respip validators iterators\nBSD licence, skatīt LICENSE avota paketē\nZiņojiet par kļūdām uz unbound-bugs@nlnetlabs.nl\nroot@eprove:\/usr\/local\/etc\/h2o # sockstat -46 | grep unbound\nunbound local-unbo 69749 3 udp6 ::1:53 *:*\nunbound local-unbo 69749 4 tcp6 ::1:53 *:*\nunbound local-unbo 69749 5 udp4 127.0.0.1:53 *:*\nunbound local-unbo 69749 6 tcp4 127.0.0.1:53 *:*Paliek tikai pārstartēt H2O un redzēt, kas no tā sanāks.
root@beta: /usr/local/etc/h2o # service h2o restart
Apturē h2o.
Gaida PIDS: 69871.
Sāk h2o.
start_server (pid:70532) sāk tagad...4. Testēšana
Tātad, pārbaudīsim rezultātus, atkārtoti nosūtot izmēģinājuma pieprasījumu un skatoties tīkla trafiku ar rīku tcpdump.
root@beta/usr/local/etc/h2o # curl -H 'accept: application/dns-message' 'https://my.domain/dns-query?dns=q80BAAABAAAAAAAAB2V4YW1wbGUDY29tAAABAAE'
Brīdinājums: Binārie iznākumi var sabojāt jūsu termināli, izmantojiet "--output -" lai pateiktu
Brīdinājums: curl, lai izvadītu to terminālī, vai apsveriet "--output
Brīdinājums: " lai saglabātu failā.
...
root@beta:~ # tcpdump -n -i lo0 udp port 53 -xx -XX -vv
tcpdump: klausoties lo0, saite- tips NULL (BSD loopback), saglabāšanas izmērs 262144 baiti
16:32:40.420831 IP (tos 0x0, ttl 64, id 37575, offset 0, flags [none], proto UDP (17), garums 57, slikta cksum 0 (->e9ea)!)
127.0.0.1.21070 > 127.0.0.1.53: [slikta 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), garums 73, slikta cksum 0 (->e9cb)!)
127.0.0.1.53 > 127.0.0.1.21070: [slikta 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 iekrāms ieņemts
23 iekrāms saņēma filtram
0 iekrāms noraidīts no kodolaIzvadē redzams, ka pieprasījums adreses izsniegšanai example.com tika saņemts un veiksmīgi apstrādāts DNS serverī.
Tagad palicis tikai aktivizēt mūsu serveri pārlūkā Firefox. Lai to izdarītu, jāizdara dažas izmaiņas konfigurācijas lapās about:config.

Vispirms, tas ir mūsu API adrese, caur kuru pārlūks pieprasīs DNS informāciju network.trr.uri. Ir ieteicams arī norādīt domēna IP no šī URL drošai pārvēršanai IP pārlūka līdzekļiem bez DNS izmantošanas network.trr.bootstrapAddress. Un, visbeidzot, pats parametrs network.trr.mode aktivizējot DoH izmantošanu. Iestatot vērtību uz "3", pārlūks izmantos tikai DNS-over-HTTPS adreses izsniegšanai, bet labāka un drošāka "2" dot prioritāti DoH, atstājot standarta piekļuvi DNS kā rezerves variantu.
5. PEļŅA!
Vēl joprojām ir noderīga raksts? Tad lūdzu nevilcinieties un atbalstiet ar naudu caur donācijas formu (apakšā).
Avots: habr.com
