تم تناول الجوانب المختلفة من تشغيل DNS بشكل متكرر من قبل المؤلف في عدد من المقالات المنشورة كجزء من المدونة. في الوقت نفسه ، كان التركيز الرئيسي دائمًا على تحسين أمان هذه الخدمة الرئيسية للإنترنت بأكمله.

حتى وقت قريب ، على الرغم من الضعف الواضح لحركة مرور DNS ، والتي ، في معظمها ، لا تزال تنتقل بشكل واضح ، من أجل الإجراءات الخبيثة من قبل مقدمي الخدمات الذين يسعون إلى زيادة دخلهم عن طريق تضمين الإعلان في المحتوى ، ووكالات إنفاذ القانون في الولاية والرقابة ، بالإضافة إلى المجرمين فقط ، فإن عملية تعزيز حمايتها ، على الرغم من وجود العديد من التقنيات ، مثل DNSSEC / DANE و DNScrypt و DNS-over-TLS و DNS-over-HTTPS. وإذا كانت حلول الخادم ، وبعضها موجود لبعض الوقت ، معروفة ومتاحة على نطاق واسع ، فإن دعمها من برنامج العميل يترك الكثير مما هو مرغوب فيه.
لحسن الحظ ، فإن الوضع يتغير. على وجه الخصوص ، أعلن مطورو متصفح Firefox الشهير عن خطط لتمكين وضع الدعم الافتراضي لـ DNS-over-HTTPS (DoH) في المستقبل القريب. يجب أن يساعد هذا في حماية حركة مرور DNS لمستخدم WWW من التهديدات المذكورة أعلاه ، ولكن يمكن أن يسبب تهديدات جديدة.
1. مشاكل DNS over-HTTPS
للوهلة الأولى ، لا تؤدي بداية الإدخال الهائل لنظام DNS-over-HTTPS إلى البرامج التي تعمل على الإنترنت إلا إلى رد فعل إيجابي. ومع ذلك ، فإن الشيطان ، كما يقولون ، هو في التفاصيل.
المشكلة الأولى التي تحد من نطاق الاستخدام المكثف لوزارة الصحة هي تركيزها فقط على حركة مرور الويب. في الواقع ، فإن بروتوكول HTTP وإصداره الحالي من HTTP / 2 ، الذي تقوم عليه DoH ، هو أساس WWW. لكن الإنترنت ليس فقط الويب. هناك العديد من الخدمات الشائعة ، مثل البريد الإلكتروني ، وجميع أنواع الرسائل ، وأنظمة نقل الملفات ، وتدفق الوسائط المتعددة ، وما إلى ذلك ، والتي لا تستخدم HTTP. وبالتالي ، على الرغم من التصور من قبل العديد من DoH باعتباره الدواء الشافي ، اتضح أنه غير قابل للتطبيق دون بذل جهود إضافية (وغير ضرورية) ، من أجل لا شيء غير تقنية المستعرض. بالمناسبة ، يبدو DNS-over-TLS وكأنه مرشح أكثر أهمية لهذا الدور ، والذي ينفذ تضمين حركة مرور DNS القياسية في بروتوكول TLS قياسي آمن.
المشكلة الثانية ، والتي من المحتمل أن تكون أكثر أهمية من الأولى ، هي الرفض الفعلي لنظام أسماء النطاقات اللامركزي المتأصل عن طريق التصميم من أجل استخدام خادم DoH الوحيد المحدد في إعدادات المتصفح. على وجه الخصوص ، تقدم Mozilla استخدام الخدمة من Cloudflare. كما تم إطلاق خدمة مماثلة من قِبل شخصيات بارزة أخرى على الإنترنت ، وخاصة Google. اتضح أن تطبيق DNS over-HTTPS بالشكل الذي يقترح به الآن ، يزيد فقط من اعتماد المستخدمين النهائيين على أكبر الخدمات. ليس سراً أن المعلومات التي يمكن أن يوفرها تحليل استعلامات DNS قادرة على جمع المزيد من البيانات عنها ، فضلاً عن زيادة دقتها وأهميتها.
في هذا الصدد ، كان المؤلف ولا يزال مؤيدًا للتطبيق الشامل لـ HTTPS لـ DNS-over-HTTPS ، لكن DNS-over-TLS مع DNSSEC / DANE باعتباره وسيلة عالمية وآمنة وغير أكثر تعزيزًا لمركزية وسائل الإنترنت لضمان أمان حركة مرور DNS. لسوء الحظ ، لا يوجد سبب لتوقع التقديم السريع للدعم الشامل لبدائل DoH في برنامج العميل لأسباب واضحة ، ويظل عشاق التقنيات الآمنة مصيرهم.
ولكن نظرًا لأننا نحصل على DoH الآن ، فلماذا لا نستخدمها بعد الابتعاد عن المراقبة المحتملة من قبل الشركات من خلال خوادمها إلى خادم DNS HTTPS الخاص بك؟
2. DNS أكثر من HTTPS
إذا نظرت إلى معيار RFC8484 الذي يصف بروتوكول HTTPS لنظام DNS ، يمكنك أن ترى أنه ، في الواقع ، هو واجهة ويب على الويب تسمح لك بتغليف حزمة DNS قياسية في بروتوكول HTTP / 2. يتم تنفيذ ذلك من خلال رؤوس HTTP الخاصة ، بالإضافة إلى تحويل التنسيق الثنائي لبيانات DNS المرسلة (انظر RFC1035 والمستندات اللاحقة) إلى نموذج يسمح لك بإرسالها واستقبالها ، وكذلك العمل باستخدام البيانات الأولية اللازمة.
وفقًا للمعايير ، يتم دعم HTTP / 2 فقط واتصال TLS آمن.
يمكن إرسال استعلام DNS باستخدام أساليب GET و POST القياسية. في الحالة الأولى ، يتم تحويل الطلب إلى سلسلة مشفرة base64URL ، وفي الحالة الثانية ، من خلال نص طلب POST في شكل ثنائي. في هذه الحالة ، عند الاستعلام عن DNS والرد عليه ، يتم استخدام تطبيق / Dns-message الخاص بنوع بيانات MIME.
root@eprove:~ # curl -H 'accept: application/dns-message' 'https://my.domain/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: <FILE>" to save to a file. * Failed writing body (0 != 45) * stopped the pause stream! * Connection #0 to host eprove.net left intact
لاحظ أيضًا التحكم في ذاكرة التخزين المؤقت: الرأس في الاستجابة من خادم الويب. تحتوي المعلمة max-age على قيمة TTL لسجل DNS المرتجع (أو الحد الأدنى للقيمة في حالة إرجاع المجموعة الخاصة بها).
بناءً على ما تقدم ، يتكون سير عمل DoH من عدة مراحل.
- تلقي طلب HTTP. إذا كان GET ثم فك تشفير الحزمة من base64URL الترميز.
- إرسال هذه الحزمة إلى خادم DNS.
- الحصول على استجابة من خادم DNS
- ابحث عن الحد الأدنى لقيمة TTL في السجلات المستلمة.
- إرجاع استجابة HTTP إلى العميل.
3. خادم DNS over-HTTPS
تتمثل الطريقة الأسهل والأسرع والأكثر فاعلية لبدء خادم DNS-over-HTTPS الخاص بك في استخدام خادم الويب HTTP / 2 H2O ، والذي كتبه المؤلف لفترة وجيزة بالفعل (راجع " خادم الويب عالي الأداء H2O ").
لصالح هذا الاختيار هو حقيقة أن كل رمز خادم DoH الخاص بك يمكن تنفيذه بالكامل باستخدام مترجم mruby المدمج في H2O نفسه . بالإضافة إلى المكتبات القياسية ، للتواصل مع خادم DNS ، تحتاج إلى مكتبة Socket (mrbgem) ، والتي ، لحسن الحظ ، مضمنة بالفعل في إصدار التطوير الحالي لـ H2O 2.3.0-beta2 الموجود في منافذ FreeBSD. ومع ذلك ، ليس من الصعب إضافته إلى أي إصدار سابق عن طريق استنساخ مستودع مكتبة Socket في دليل / deps قبل التحويل البرمجي.
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 «mruby-socket»… remote: Enumerating objects: 385, done. remote: Total 385 (delta 0), reused 0 (delta 0), pack-reused 385 : 100% (385/385), 98.02 KiB | 647.00 KiB/s, . : 100% (208/208), . root@beta:/usr/ports/www/h2o/work/h2o-2.2.6/deps # ll total 181 drwxr-xr-x 9 root wheel 18 12 . 16:09 brotli/ drwxr-xr-x 2 root wheel 4 12 . 16:09 cloexec/ drwxr-xr-x 2 root wheel 5 12 . 16:09 golombset/ drwxr-xr-x 4 root wheel 35 12 . 16:09 klib/ drwxr-xr-x 2 root wheel 5 12 . 16:09 libgkc/ drwxr-xr-x 4 root wheel 26 12 . 16:09 libyrmcds/ drwxr-xr-x 13 root wheel 32 12 . 16:09 mruby/ drwxr-xr-x 5 root wheel 11 12 . 16:09 mruby-digest/ drwxr-xr-x 5 root wheel 10 12 . 16:09 mruby-dir/ drwxr-xr-x 5 root wheel 10 12 . 16:09 mruby-env/ drwxr-xr-x 4 root wheel 9 12 . 16:09 mruby-errno/ drwxr-xr-x 5 root wheel 14 12 . 16:09 mruby-file-stat/ drwxr-xr-x 5 root wheel 10 12 . 16:09 mruby-iijson/ drwxr-xr-x 5 root wheel 11 12 . 16:09 mruby-input-stream/ drwxr-xr-x 6 root wheel 11 12 . 16:09 mruby-io/ drwxr-xr-x 5 root wheel 10 12 . 16:09 mruby-onig-regexp/ drwxr-xr-x 4 root wheel 10 12 . 16:09 mruby-pack/ drwxr-xr-x 5 root wheel 10 12 . 16:09 mruby-require/ drwxr-xr-x 6 root wheel 10 12 . 16:10 mruby-socket/ drwxr-xr-x 2 root wheel 9 12 . 16:09 neverbleed/ drwxr-xr-x 2 root wheel 13 12 . 16:09 picohttpparser/ drwxr-xr-x 2 root wheel 4 12 . 16:09 picotest/ drwxr-xr-x 9 root wheel 16 12 . 16:09 picotls/ drwxr-xr-x 4 root wheel 8 12 . 16:09 ssl-conservatory/ drwxr-xr-x 8 root wheel 18 12 . 16:09 yaml/ drwxr-xr-x 2 root wheel 8 12 . 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 ...
تكوين خادم الويب هو المعيار عموما.
root@beta:/usr/ports/www/h2o # cd /usr/local/etc/h2o/ root@beta:/usr/local/etc/h2o # cat h2o.conf # this sample config gives you a feel for how h2o can be used # and a high-security configuration for TLS and HTTP headers # see https://h2o.examp1e.net/ for detailed documentation # and h2o --help for command-line options and settings # v.20180207 (c)2018 by 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-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384 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.rb
الاستثناء الوحيد هو معالج URL / dns - query ، وهو المسؤول ، في الواقع ، عن خادم hTodPS الخاص بـ h2odoh DNS ، والذي يتم كتابته في mruby ويتم استدعاؤه من خلال خيار معالج ملف mruby.handler .
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") < 192 shift = str.index("\x00", shift) + 5 if ttl == 0 # skip question section next end end shift += 6 curttl = str[shift, 4].unpack1('N') shift += str[shift + 4, 2].unpack1('n') + 6 # responce data size if ttl == 0 or ttl > 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 }
يرجى ملاحظة أن خادم التخزين المؤقت المحلي مسؤول عن معالجة حزم نظام أسماء النطاقات ، وفي هذه الحالة يكون غير ملزم بتوزيع FreeBSD القياسي. من وجهة نظر أمنية ، هذا هو الحل الأفضل. ومع ذلك ، لا يوجد شيء يمنع استبدال مضيف محلي بعنوان DNS آخر تنوي استخدامه.
root@beta:/usr/local/etc/h2o # local-unbound verison 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 *:*
يبقى لإعادة تشغيل H2O ومعرفة ما جاء منه.
root@beta:/usr/local/etc/h2o # service h2o restart Stopping h2o. Waiting for PIDS: 69871. Starting h2o. start_server (pid:70532) starting now...
4. اختبار
لذلك ، دعونا نتحقق من النتائج عن طريق إرسال طلب اختبار مرة أخرى والنظر في حركة مرور الشبكة باستخدام الأداة المساعدة tcpdump .
root@beta/usr/local/etc/h2o # curl -H 'accept: application/dns-message' 'https://my.domain/dns-query?dns=q80BAAABAAAAAAAAB2V4YW1wbGUDY29tAAABAAE' 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: <FILE>" to save to a file. ... root@beta:~ # tcpdump -n -i lo0 udp port 53 -xx -XX -vv tcpdump: listening on lo0, link-type NULL (BSD loopback), capture size 262144 bytes 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 packets captured 23 packets received by filter 0 packets dropped by kernel
يُظهر الإخراج كيفية تلقي طلب تحليل عنوان example.com ومعالجته بنجاح بواسطة خادم DNS.
الآن يبقى تنشيط خادمنا في متصفح فايرفوكس. للقيام بذلك ، تحتاج إلى تغيير العديد حول: إعدادات التكوين على صفحات التكوين.

أولاً ، هذا هو عنوان API الخاص بنا والذي سيقوم فيه المستعرض بالاستعلام عن معلومات DNS في network.trr.uri . يوصى أيضًا بتحديد عنوان IP الخاص بالمجال من عنوان URL هذا لضمان الدقة في IP باستخدام المستعرض نفسه دون الوصول إلى DNS في network.trr.bootstrapAddress . وأخيراً ، المعلمة network.trr.mode نفسها ، والتي تتضمن استخدام DoH. سيؤدي تعيين القيمة إلى "3" إلى إجبار المستعرض على استخدام HTTPS لنظام DNS حصريًا لحل الأسماء ، وسيعطي "2" الأكثر موثوقية وأمانًا أولوية DoH ، تاركًا وصول DNS القياسي كخلفية احتياطية.
5. الربح!
هل كانت المقالة مفيدة؟ ثم من فضلك لا تخجل وتدعم المال من خلال نموذج التبرع (أدناه).