BLOG | NGINX

Utilisation de NGINX comme passerelle DoT ou DoH

NGINX-Partie-de-F5-horiz-black-type-RGB
Vignette de Mark Boddington
Marc Boddington
Publié le 22 février 2022

On parle beaucoup du système de noms de domaine (DNS) en ce moment, avec des changements massifs proposés pour ce protocole vieux de 36 ans . Le service de noms d'Internet, qui trouve ses origines dans ARPANET , n'a jamais connu de rupture de compatibilité rétroactive depuis sa création. Mais de nouvelles propositions visant à modifier le mécanisme de transport DNS pourraient être sur le point de changer cela.

Dans cet article, j'examine deux technologies émergentes pour sécuriser le DNS, DNS sur TLS (DoT) et DNS sur HTTPS (DoH), et je montre comment les mettre en œuvre à l'aide de NGINX Open Source et NGINX Plus.

[ Éditeur – Cet article est l’un des nombreux articles qui explorent les cas d’utilisation du module JavaScript NGINX. Pour une liste complète, voir Cas d'utilisation du module JavaScript NGINX .

Le code de cet article est mis à jour pour utiliser la directive js_import , qui remplace la directive js_include obsolète dans NGINX Plus R23<.htmla> et versions ultérieures. Pour plus d'informations, consultez la documentation de référence du module JavaScript NGINX – la section Exemple de configuration montre la syntaxe correcte pour la configuration NGINX et les fichiers JavaScript.]

L'histoire du DNS

Le DNS a été la deuxième tentative de création d'un service de dénomination pour le premier Internet de l'Advanced Research Project Agency (ARPA), la première étant le protocole Internet Name Server publié par John Postel en 1979 sous le nom IEN-116. . Le DNS a été conçu pour être hiérarchique et fournir une structure permettant aux noms d'hôtes d'être décentralisés en zones et gérés par de nombreuses autorités distinctes. Les premiers RFC pour le DNS ont été publiés en 1983 (RFC882 et883 ), et bien qu'ils aient eu plusieurs extensions au fil des ans, un client écrit selon les normes définies à l'époque fonctionnerait toujours aujourd'hui.

Alors pourquoi changer le protocole maintenant ? Cela fonctionne clairement comme prévu, justifiant la confiance de ses auteurs, qui étaient tellement sûrs d'avoir raison qu'ils n'ont pas inclus de numéro de version dans le paquet DNS - je ne vois pas beaucoup d'autres protocoles qui peuvent prétendre à cela. Le DNS a été conçu à une époque plus innocente, lorsque la plupart des protocoles étaient en texte clair et souvent en ASCII 7 bits , mais l'Internet d'aujourd'hui est un endroit beaucoup plus effrayant que l'ARPANET des années 1980. Aujourd’hui, la plupart des protocoles ont adopté la sécurité de la couche transport (TLS) à des fins de chiffrement et de vérification. Les critiques du DNS affirment qu’il est grand temps de mettre en place des mesures de sécurité supplémentaires.

Ainsi, de la même manière que le DNS a été la deuxième tentative de fournir un protocole de service de noms pour Internet, le DNS sur TLS (DoT) et le DNS sur HTTPS (DoH) apparaissent comme des deuxièmes tentatives de sécurisation du protocole DNS. La première tentative était une extension connue sous le nom de DNSSEC , et bien que la plupart des domaines de premier niveau (TLD) utilisent DNSSEC, il n'a jamais été conçu pour crypter les données transportées dans les paquets DNS ; il fournit uniquement une vérification que les données n'ont pas été falsifiées. DoT et DoH sont des extensions de protocole qui encapsulent le DNS dans un tunnel TLS et, si elles sont adoptées, elles mettront fin à 36 ans de compatibilité descendante.

DoT et DoH plus en détail

DoT, je pense, est largement considéré comme une extension judicieuse. Son propre numéro de port (TCP/853) lui a déjà été attribué par l'Internet Assigned Numbers Authority (IANA) et il encapsule simplement les paquets DNS TCP dans un tunnel chiffré TLS. De nombreux protocoles l’ont déjà fait : HTTPS est HTTP à l'intérieur d'un tunnel TLS, et SMTPS, IMAPS et LDAPS sont des versions sécurisées de ces protocoles. Le DNS a toujours utilisé UDP (ou TCP dans certains cas) comme protocole de transport, donc l'ajout du wrapper TLS n'est pas un changement majeur.

DoH, en revanche, est un peu plus controversé. DoH prend un paquet DNS et l'enveloppe dans une requête HTTP GET ou POST , qui est ensuite envoyée via HTTP/2 ou supérieur via une connexion HTTPS. Cela ressemble en fait à n'importe quelle autre connexion HTTPS, et il est impossible pour les entreprises ou les fournisseurs de services de voir quelles demandes sont effectuées. Mozilla et d'autres partisans affirment que cette pratique renforce la confidentialité des utilisateurs en préservant la confidentialité des sites qu'ils visitent, à l'abri des regards indiscrets.

Mais ce n’est pas tout à fait vrai. Les critiques de DoH soulignent qu'il ne s'agit pas vraiment du Tor du DNS, car lorsque le navigateur établit finalement la connexion à l'hôte qu'il a recherché à l'aide de DoH, la requête utilisera presque certainement l'extension TLS Server Name Indication (SNI) - et cela inclut le nom d'hôte et est envoyé en texte clair. De plus, si le navigateur tente de valider le certificat du serveur à l'aide du protocole OSCP (Online Certificate Status Protocol), ce processus se produit probablement également en texte clair. Ainsi, toute personne ayant la capacité de surveiller les recherches DNS a également la possibilité de lire le SNI dans la connexion ou le nom du certificat dans la validation OCSP.

Pour de nombreuses personnes, le plus gros problème avec DoH est que les fournisseurs de navigateurs choisissent les serveurs DNS auxquels les requêtes DoH effectuées par leurs utilisateurs sont envoyées par défaut (dans le cas des utilisateurs de Firefox aux États-Unis, par exemple, les serveurs DNS appartiennent à Cloudflare ). L'opérateur des serveurs DNS peut voir l'adresse IP de l'utilisateur et les noms de domaine des sites auxquels il fait des requêtes. Cela peut sembler peu, mais des chercheurs de l'Université de l'Illinois ont découvert qu'il est possible de déduire quels sites Web une personne a visités à partir de rien de plus que les adresses de destination des requêtes d'éléments d'une page Web, ce que l'on appelle l'empreinte digitale de chargement de page. Ces informations peuvent ensuite être utilisées pour « profiler et cibler l’utilisateur à des fins publicitaires ».

Comment NGINX peut-il vous aider ?

DoT et DoH ne sont pas intrinsèquement mauvais, et il existe des cas d’utilisation où ils augmentent la confidentialité des utilisateurs. Cependant, il existe un consensus croissant selon lequel un service DoH public et centralisé est mauvais pour la confidentialité des utilisateurs, et nous vous recommandons d’éviter d’en utiliser un à tout prix.

Dans tous les cas, pour vos sites et applications, vous gérez probablement vos propres zones DNS – certaines publiques, d’autres privées et d’autres avec un horizon divisé. À un moment donné, vous pourriez décider de gérer votre propre service DoT ou DoH. C'est là que NGINX peut vous aider.

Les améliorations de confidentialité fournies par DoT offrent de grands avantages pour la sécurité DNS, mais que se passe-t-il si votre serveur DNS actuel n’offre pas de prise en charge de DoT ? NGINX peut aider ici en fournissant une passerelle entre DoT et DNS standard.

Ou peut-être appréciez-vous le potentiel de contournement du pare-feu de DoH pour les cas où le port DoT peut être bloqué. Encore une fois, NGINX peut aider en fournissant une passerelle DoH vers DoT/DNS .

Déploiement d'une passerelle DoT-DNS simple

Le module NGINX Stream (TCP/UDP) prend en charge la terminaison SSL, il est donc très simple de configurer un service DoT. Vous pouvez créer une passerelle DoT simple en quelques lignes de configuration NGINX.

Vous avez besoin d'un bloc en amont pour vos serveurs DNS et d'un bloc serveur pour la terminaison TLS :

Bien sûr, nous pouvons également procéder dans l’autre sens et transférer les requêtes DNS entrantes vers un serveur DoT en amont. Cela est toutefois moins utile, car la plupart du trafic DNS est UDP et NGINX ne peut traduire qu’entre DoT et d’autres services TCP, tels que le DNS basé sur TCP.

Une passerelle DoH-DNS simple

Par rapport à une passerelle DoT, la configuration d'une passerelle DoH simple est un peu plus complexe. Nous avons besoin à la fois d'un service HTTPS et d'un service Stream, et utilisons le code JavaScript et le module JavaScript NGINX <.htmla> (njs) pour traduire entre les deux protocoles. La configuration la plus simple est :

Cette configuration effectue la quantité minimale de traitement requise pour envoyer le paquet vers le service DNS. Ce cas d’utilisation suppose que le serveur DNS en amont exécute toutes les autres fonctions de filtrage, de journalisation ou de sécurité.

Le script JavaScript utilisé dans cette configuration ( nginx_stream.js ) inclut divers fichiers de modules de bibliothèque DNS. Dans le module dns.js , la variable dns_decode_level définit la quantité de traitement effectuée sur les paquets DNS. Le traitement des paquets DNS nuit évidemment aux performances. Si vous utilisez une configuration comme celle ci-dessus, définissez dns_decode_level sur0 .

Une passerelle DoH plus avancée

Chez NGINX, nous sommes plutôt bons en HTTP, nous pensons donc qu’utiliser NGINX uniquement comme une simple passerelle DoH est une opportunité perdue.

Le code JavaScript utilisé ici peut être configuré pour effectuer un décodage complet ou partiel des paquets DNS. Cela nous permet de créer un cache de contenu HTTP pour les requêtes DoH avec les en-têtes Expires et Cache-Control définis en fonction des TTL minimum des réponses DNS.

Voici un exemple plus complet, avec une optimisation de connexion supplémentaire et la prise en charge de la mise en cache et de la journalisation du contenu :

Un filtre DNS avancé utilisant les fonctionnalités NGINX Plus

Si vous disposez d'un abonnement NGINX Plus, vous pouvez combiner les exemples ci-dessus avec certaines des fonctionnalités NGINX Plus les plus avancées, telles que les contrôles de santé actifs et la haute disponibilité, ou même utiliser l'API de purge du cache pour gérer les réponses DoH mises en cache.

Il est également possible d'utiliser le magasin de clés-valeurs NGINX Plus pour créer un système de filtrage DNS qui protège les utilisateurs contre les domaines malveillants en renvoyant une réponse DNS qui empêche efficacement l'accès à ces derniers. Vous gérez le contenu du magasin clé-valeur de manière dynamique avec l' API RESTful NGINX Plus .

Nous définissons deux catégories de domaines malveillants, « bloqués » et « trous noirs ». Le système de filtrage DNS gère une requête DNS sur un domaine différemment selon sa catégorie :

  • Pour les domaines bloqués , il renvoie la réponse NXDOMAIN (indiquant que le domaine n'existe pas)
  • Pour les domaines blackhole , il renvoie un seul enregistrement DNS A de 0.0.0.0 en réponse aux demandes d'enregistrements A , ou un seul enregistrement AAAA de :: en réponse aux demandes d'enregistrements AAAA (IPv6) ; pour les autres types d'enregistrement, il renvoie une réponse contenant zéro réponse

Lorsque notre filtre DNS reçoit une demande, il recherche d’abord une clé correspondant exactement au nom de domaine complet interrogé. S'il en trouve un, il « nettoie » (bloque ou met en trou noir) la requête comme spécifié par la valeur associée. S'il n'y a pas de correspondance exacte, il recherche le nom de domaine dans deux listes (l'une de domaines bloqués et l'autre de domaines mis en blackhole) et nettoie la demande de manière appropriée s'il y a une correspondance.

Si le domaine interrogé n'est pas malveillant, le système le transmet à un serveur DNS de Google pour un traitement régulier.

Configuration du magasin de valeurs clés

Nous définissons les domaines que nous considérons comme malveillants dans deux types d'entrées dans le magasin de clés-valeurs NGINX Plus :

  • Entrées individuelles pour les noms de domaine entièrement qualifiés (FQDN), chacune avec une valeur bloquée ou blackhole
  • Deux listes de domaines, avec des clés appelées blocked_domains et blackholed_domains , chacune mappée à une liste de domaines au format CSV (valeurs séparées par des virgules)

La configuration suivante pour le magasin clé-valeur est placée dans le contexte du flux . La directive keyval_zone alloue un bloc de mémoire pour le magasin de valeurs clés, appelé dns_config . La première directive keyval charge toute paire clé-valeur FQDN correspondante qui a été définie, tandis que la deuxième et la troisième définissent les deux listes de domaines :

Nous pouvons ensuite utiliser l’ API NGINX Plus pour attribuer la valeur blocked ou blackhole à n’importe quelle clé FQDN que nous souhaitons explicitement nettoyer, ou modifier la liste au format CSV associée à la clé blocked_domains ou blackhole_domains . Nous pouvons modifier ou supprimer des FQDN exacts, ou modifier l'ensemble des domaines dans l'une ou l'autre liste, à tout moment et le filtre DNS est instantanément mis à jour avec les modifications.

Choix du serveur en amont pour traiter la requête

La configuration suivante charge la variable $dns_response , qui est renseignée par une directive js_preread dans les blocs de serveur définis dans Configuration des serveurs qui écoutent les requêtes DNS ci-dessous. Lorsque le code JavaScript invoqué détermine que la requête doit être nettoyée, il définit la variable sur bloqué ou trou noir selon le cas.

Nous utilisons une directive map pour attribuer la valeur de la variable $dns_response à la variable $upstream_pool , contrôlant ainsi lequel des groupes en amont dans Définition des serveurs en amont ci-dessous gère la demande. Les requêtes pour les domaines non malveillants sont transmises au serveur DNS Google par défaut, tandis que les requêtes pour les domaines bloqués ou mis en blackhole sont traitées par le serveur en amont pour ces catégories.

Définition des serveurs en amont

Cette configuration définit les groupes blocked , blackhole et google des serveurs en amont, qui gèrent respectivement les requêtes pour les domaines blocked, blackhole et non malveillants.

Configuration des serveurs qui écoutent les requêtes DNS

Ici, nous définissons les serveurs dans le contexte de flux qui écoutent les requêtes DNS entrantes. La directive js_preread appelle le code Javascript qui décode le paquet DNS, récupère le nom de domaine à partir du champ NAME du paquet et recherche le domaine dans le magasin clé-valeur. Si le nom de domaine correspond à une clé FQDN ou se trouve dans la zone de l'un des domaines de la liste blocked_domains ou blackhole_domains , il est supprimé. Sinon, il finit par être envoyé au serveur DNS de Google pour résolution.

C'est presque tout – nous devons juste ajouter notre bloc de serveur final, qui répond aux requêtes avec la réponse blackholed ou bloquée.

Notez que les serveurs de ce bloc sont presque identiques aux serveurs DNS réels juste au-dessus d'eux, la principale différence étant que ces serveurs envoient un paquet de réponse au client au lieu de transmettre la demande à un groupe de serveurs DNS en amont. Notre code JavaScript détecte quand il est exécuté à partir du port 9953 ou 9853, et au lieu de définir un indicateur pour indiquer que le paquet doit être bloqué, il remplit $dns_response avec le paquet de réponse réel. C'est tout ce qu'il y a à dire.

Bien sûr, nous aurions également pu appliquer ce filtrage aux services DoT et DoH, mais nous avons utilisé le DNS standard afin de garder les choses simples. La fusion du filtrage DNS avec la passerelle DoH est laissée en exercice au lecteur.

Test du filtre

Nous avons précédemment utilisé l' API NGINX Plus pour ajouter des entrées pour deux FQDN et certains domaines aux deux listes de domaines :

$ curl -s http://localhost:8080/api/5/stream/keyvals/dns_config | jq { "www.some.bad.host": "bloqué", "www.some.other.host": "blackhole", "blocked_domains": "bar.com,baz.com", "blackhole_domains": "foo.com,nginx.com" }

Ainsi, lorsque nous demandons la résolution de www.foo.com (un hôte dans le domaine foo.com noirci), nous obtenons un enregistrement A avec l'adresse IP 0.0.0.0 :

$ dig @localhost www.foo.com ; <<>> DiG 9.11.3-1ubuntu1.9-Ubuntu <<>> @localhost www.foo.com ; (1 serveur trouvé) ;; options globales : +mcd ;; Réponse obtenue : ;; ->>HEADER,,- opcode : REQUÊTE, statut : PAS D'ERREUR, id: 58558 ;; drapeaux : qr aa rd ad ; REQUÊTE : 1, RÉPONSE : 1. AUTORITÉ : 0, SUPPLÉMENTAIRE : 0 ;; AVERTISSEMENT : récursivité demandée mais non disponible ;; SECTION QUESTION : ; www.foo.com.                  DANS UNE SECTION RÉPONSE : www.foo.com.           300 IN A 0.0.0.0 ;; Heure de la requête : 0 msec ;; SERVEUR : 172.0.0.1#53(126.0.0.1) ;; QUAND : Lun 2 Déc 14:31:35 UTC 2019 ;; MSG SIZEW reçu : 45

Accéder au code

Les fichiers pour DOH et DOT sont disponibles dans mon dépôt GitHub :

  • Le code JavaScript dans le dossier njs.d/dns
  • La configuration NGINX dans le dossier des exemples

Pour essayer NGINX Plus, démarrez votre essai gratuit de 30 jours dès aujourd'hui ou contactez-nous pour discuter de vos cas d'utilisation .


« Cet article de blog peut faire référence à des produits qui ne sont plus disponibles et/ou qui ne sont plus pris en charge. Pour obtenir les informations les plus récentes sur les produits et solutions F5 NGINX disponibles, explorez notre famille de produits NGINX . NGINX fait désormais partie de F5. Tous les liens NGINX.com précédents redirigeront vers un contenu NGINX similaire sur F5.com."