Le système de noms de domaine (DNS) fait actuellement beaucoup parler de lui, alors que des changements majeurs sont 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 depuis sa création de rupture de rétrocompatibilité. Mais de nouvelles propositions visant à modifier le mécanisme de transport du DNS pourraient bien changer la donne.
Dans cet article, j’examine deux technologies émergentes permettant de sécuriser le DNS, le DNS sur TLS (DoT) et le DNS sur HTTPS (DoH), et je montre comment les mettre en œuvre à l’aide de NGINX Open Source et de NGINX Plus.
[Note de la rédaction – Cet article fait partie d’une série consacrée aux cas d’utilisation du module JavaScript de NGINX. Pour consulter la liste complète, voir Cas d’utilisation du module JavaScript de NGINX.
Le code de cet article a été mis à jour pour utiliser la directive js_import , qui remplace la directive obsolète js_include dans NGINX Plus R23<.htmla> et les versions ultérieures. Pour plus d’informations, consultez la documentation de référence du module JavaScript NGINX : la section Exemple de configuration présente la syntaxe correcte pour les fichiers de configuration NGINX et les fichiers JavaScript.]
L’histoire du DNS
Le DNS constituait la deuxième tentative de création d’un service de nommage pour les débuts d’Internet de l’Advanced Research Projects Agency (ARPA), la première étant le protocole Internet Name Server publié par John Postel en 1979 sous la référence IEN-116. Le DNS a été conçu selon une architecture hiérarchique permettant de décentraliser les noms d’hôtes en zones gérées par de nombreuses autorités distinctes. Les premières RFC relatives au DNS ont été publiées en 1983 (RFC 882 et 883). Bien qu’elles aient fait l’objet de plusieurs extensions au fil des ans, un client conforme aux normes définies à l’époque fonctionnerait encore aujourd’hui.
Alors pourquoi modifier le protocole maintenant ? Il fonctionne manifestement comme prévu, ce qui justifie la confiance de ses auteurs, tellement certains d’avoir vu juste qu’ils n’ont pas inclus de numéro de version dans le paquet DNS — je ne vois guère d’autres protocoles qui puissent en dire autant. Le DNS a été conçu à une époque plus innocente, où la plupart des protocoles transmettaient les données en clair, souvent en ASCII 7 bits, mais l’Internet d’aujourd’hui est bien plus inquiétant que l’ARPANET des années 1980. De nos jours, la plupart des protocoles ont adopté le protocole Transport Layer Security (TLS) à des fins de chiffrement et de vérification. Les détracteurs du DNS estiment qu’il aurait dû bénéficier depuis longtemps de protections de sécurité supplémentaires.
Ainsi, de la même manière que le DNS constituait la deuxième tentative visant à fournir un protocole de service de noms pour Internet, le DNS sur TLS (DoT) et le DNS sur HTTPS (DoH) apparaissent comme de nouvelles tentatives de sécurisation du protocole DNS. La première tentative était une extension appelée « DNSSEC ». Bien que la plupart des domaines de premier niveau (TLD) utilisent DNSSEC, cette extension n’a jamais été conçue pour chiffrer les données transportées dans les paquets DNS ; elle permet uniquement de vérifier que les données n’ont pas été altérées. DoT et DoH sont des extensions de protocole qui encapsulent le DNS dans un tunnel TLS et qui, si elles sont adoptées, mettront fin à 36 ans de rétrocompatibilité.
DoT et DoH plus en détail
DoT est, à mon avis, largement considéré comme une extension judicieuse. L’Internet Assigned Numbers Authority (IANA) lui a déjà attribué son propre numéro de port (TCP/853), et il se contente d’encapsuler les paquets DNS sur TCP dans un tunnel chiffré par TLS. De nombreux protocoles ont déjà adopté cette approche : HTTPS correspond à HTTP dans un tunnel TLS, tandis que SMTPS, IMAPS et LDAPS sont les versions sécurisées de ces protocoles. DNS a toujours utilisé UDP (ou TCP dans certains cas) comme protocole de transport ; l’ajout de la couche TLS ne constitue donc pas un changement majeur.
Le DoH, en revanche, est un peu plus controversé. Il encapsule un paquet DNS dans une requête HTTP de type « GET » ou « POST », qui est ensuite envoyée via HTTP/2 ou une version ultérieure sur une connexion HTTPS. En pratique, celle-ci ressemble en tout point à n’importe quelle autre connexion HTTPS, et il est impossible pour les entreprises ou les fournisseurs de services de voir quelles requêtes sont effectuées. Mozilla et d’autres partisans affirment que cette pratique renforce la confidentialité des utilisateurs en dissimulant les sites qu’ils consultent aux regards indiscrets.
Mais ce n’est pas tout à fait vrai. Les détracteurs du DoH soulignent qu’il ne s’agit pas vraiment du Tor du DNS, car lorsque le navigateur finit par se connecter à l’hôte dont il a obtenu l’adresse à l’aide du DoH, la requête utilise presque certainement l’extension TLS Server Name Indication (SNI), qui contient le nom d’hôte et est envoyée en clair. En outre, si le navigateur tente de valider le certificat du serveur à l’aide du protocole Online Certificate Status Protocol (OSCP), ce processus s’effectue très probablement lui aussi en clair. Ainsi, toute personne capable de surveiller les requêtes DNS peut également lire le SNI de la connexion ou le nom figurant sur le certificat lors de la validation OCSP.
Pour de nombreuses personnes, le principal problème du DoH est que les éditeurs de navigateurs choisissent les serveurs DNS auxquels sont envoyées par défaut les requêtes DoH de leurs utilisateurs (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 ainsi que les noms de domaine des sites auxquels il envoie des requêtes. Cela peut sembler anodin, mais des chercheurs de l’université de l’Illinois ont découvert qu’il était possible de déduire quels sites web une personne a consultés uniquement à partir des adresses de destination des requêtes portant sur les éléments d’une page web, ce que l’on appelle l’empreinte de chargement de page (« Page Load Fingerprint »). Ces informations peuvent ensuite servir à « établir le profil de l’utilisateur et à le cibler à des fins publicitaires ».
Comment NGINX peut-il vous aider ?
DoT et DoH ne sont pas intrinsèquement néfastes, et il existe des cas d’usage où ils renforcent la confidentialité des utilisateurs. Cependant, un consensus croissant se dégage sur le fait qu’un service DoH public et centralisé nuit à la confidentialité des utilisateurs, et nous vous recommandons d’éviter à tout prix d’en utiliser un.
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 encore avec un DNS à horizon partagé. Vous pourriez un jour décider d’exploiter votre propre service DoT ou DoH. C’est là que NGINX peut vous aider.
Les améliorations apportées par DoT en matière de confidentialité offrent des avantages considérables pour la sécurité DNS. Mais que faire si votre serveur DNS actuel ne prend pas en charge DoT ? NGINX peut alors servir de passerelle entre DoT et le DNS standard.
Ou peut-être appréciez-vous la capacité du DoH à contourner les pare-feu lorsque le port DoT est susceptible d’être bloqué. Là encore, NGINX peut vous aider en fournissant une passerelle DoH vers DoT/DNS.
Déploiement d’une passerelle DoT-DNS simple
Le module Stream (TCP/UDP) de NGINX prend en charge la terminaison SSL, ce qui permet de configurer très facilement un service DoT. Quelques lignes de configuration NGINX suffisent pour créer une passerelle DoT simple.
Vous avez besoin d’un bloc upstream pour vos serveurs DNS et d’un bloc server pour la terminaison TLS :
Chargement de l’exemple de code…
Bien entendu, nous pouvons également procéder dans l’autre sens et transférer les requêtes DNS entrantes vers un serveur DoT en amont. Cette approche est toutefois moins utile, car la majeure partie du trafic DNS utilise UDP et NGINX ne peut effectuer la conversion qu’entre DoT et d’autres services TCP, tels que le DNS sur TCP.
Chargement de l’exemple de code…
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 nous utilisons du code JavaScript ainsi que le module JavaScript NGINX<.htmla> (njs) pour assurer la conversion entre les deux protocoles. La configuration la plus simple est la suivante :
Chargement de l’exemple de code…
Le script JavaScript utilisé dans cette configuration (nginx_stream.js) inclut plusieurs fichiers de modules de bibliothèque DNS. Dans le module dns.js, la variable dns_decode_level définit le niveau de traitement appliqué aux 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 sur 0.
Une passerelle DoH plus avancée
Chez NGINX, nous maîtrisons vraiment très bien HTTP. Nous pensons donc qu’utiliser NGINX uniquement comme une simple passerelle DoH serait une occasion manquée.
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 des en-têtes Expires et Cache-Control définis en fonction des valeurs TTL minimales des réponses DNS.
Voici un exemple plus complet, avec une optimisation supplémentaire des connexions et la prise en charge de la mise en cache du contenu et de la journalisation :
Chargement de l’exemple de code…
Un filtre DNS avancé utilisant les fonctionnalités de NGINX Plus
Si vous disposez d’un abonnement NGINX Plus, vous pouvez combiner les exemples ci-dessus avec certaines des fonctionnalités avancées de NGINX Plus, telles que les contrôles d’intégrité 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 clé-valeur de 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 en bloque effectivement l’accès. Vous gérez dynamiquement le contenu du magasin clé-valeur à l’aide de l’API RESTful de NGINX Plus.
Nous définissons deux catégories de domaines malveillants, « blocked » et « blackhole ». Le système de filtrage DNS traite différemment une requête DNS concernant un domaine selon la catégorie à laquelle il appartient :
- Pour les domaines bloqués, le système renvoie la réponse
NXDOMAIN(indiquant que le domaine n’existe pas) - Pour les domaines de type « blackhole », il renvoie un seul enregistrement DNS
Aavec la valeur 0.0.0.0 en réponse aux requêtes d’enregistrementsA, ou un seul enregistrementAAAAavec la valeur :: en réponse aux requêtes d’enregistrementsAAAA(IPv6) ; pour les autres types d’enregistrements, il renvoie une réponse ne contenant aucune réponse
Lorsque notre filtre DNS reçoit une requête, il commence par rechercher une clé correspondant exactement au nom de domaine complet (FQDN) demandé. S’il en trouve une, il « nettoie » la requête (en la bloquant ou en la redirigeant vers un trou noir) conformément à la valeur associée. En l’absence de correspondance exacte, il recherche le nom de domaine dans deux listes – l’une contenant les domaines bloqués et l’autre les domaines redirigés vers un trou noir – puis traite la requête de la manière appropriée s’il trouve une correspondance.
Si le domaine interrogé n’est pas malveillant, le système transmet la requête à un serveur DNS de Google afin qu’elle soit traitée normalement.
Configuration du magasin clé-valeur
Nous définissons les domaines que nous considérons comme malveillants à l’aide de deux types d’entrées dans le magasin clé-valeur de NGINX Plus :
- Entrées individuelles pour les noms de domaine complets (FQDN), chacune ayant pour valeur soit «
blocked», soit «blackhole - Deux listes de domaines, avec des clés nommées «
blocked_domains» et «blackholed_domains», chacune étant associée à une liste de domaines au format CSV (valeurs séparées par des virgules)
La configuration suivante du magasin clé-valeur doit être placée dans le contexte stream. La directive keyval_zone alloue un bloc de mémoire au magasin clé-valeur, appelé dns_config. La première directive keyval charge toute paire clé-valeur correspondant à un nom de domaine complet (FQDN) qui a été définie, tandis que les deuxième et troisième directives définissent les deux listes de domaines :
Chargement de l’exemple de code…
Nous pouvons ensuite utiliser l’API NGINX Plus pour attribuer la valeur « blocked » ou « blackhole » à toute clé FQDN que nous souhaitons explicitement filtrer, ou modifier la liste au format CSV associée à la clé « blocked_domains » ou « blackhole_domains ». Nous pouvons à tout moment modifier ou supprimer des FQDN exacts, ou modifier l’ensemble des domaines de l’une ou l’autre liste ; les modifications sont alors instantanément appliquées au filtre DNS.
Choisir le serveur en amont chargé de traiter la requête
La configuration suivante charge la variable « $dns_response », qui est renseignée par une directive js_preread dans les blocs server définis dans la section Configuration des serveurs à l’écoute des requêtes DNS ci-dessous. Lorsque le code JavaScript appelé détermine que la requête doit être filtrée, il définit la variable sur blocked ou blackhole selon le cas.
Nous utilisons une directive map pour affecter la valeur de la variable $dns_response à la variable $upstream_pool, ce qui permet de déterminer lequel des groupes en amont décrits dans la section Définition des serveurs en amont ci-dessous traite la requête. Les requêtes concernant des domaines non malveillants sont transférées au serveur DNS Google par défaut, tandis que celles concernant des domaines bloqués ou mis en trou noir sont traitées par le serveur en amont correspondant à leur catégorie.
Chargement de l’exemple de code…
Définition des serveurs en amont
Cette configuration définit les groupes de serveurs en amont blocked, blackhole et google, qui traitent respectivement les requêtes concernant les domaines bloqués, les domaines de type « trou noir » et les domaines non malveillants.
Chargement de l’exemple de code…
Configuration des serveurs à l’écoute des requêtes DNS
Nous définissons ici les serveurs du contexte stream 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 dans le 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 figurant dans la liste blocked_domains ou blackhole_domains, il est filtré. Sinon, il est envoyé au serveur DNS de Google pour résolution.
Chargement de l’exemple de code…
Nous y sommes presque : il ne nous reste plus qu’à ajouter notre dernier bloc « server », qui répond aux requêtes soit par une réponse redirigée vers un trou noir, soit par une réponse bloquée.
Chargement de l’exemple de code…
Notez que les serveurs de ce bloc sont presque identiques aux serveurs DNS réels situés juste au-dessus. La principale différence est que ces serveurs envoient un paquet de réponse au client au lieu de transmettre la requête à un groupe de serveurs DNS en amont. Notre code JavaScript détecte s’il est exécuté depuis le port 9953 ou 9853 et, au lieu de définir un indicateur signalant que le paquet doit être bloqué, il renseigne $dns_response avec le paquet de réponse réel. C’est aussi simple que cela.
Bien entendu, nous aurions également pu appliquer ce filtrage aux services DoT et DoH, mais nous avons utilisé le DNS standard par souci de simplicité. La combinaison du filtrage DNS avec une passerelle DoH est laissée en exercice au lecteur.
Tester le filtre
Nous avons précédemment utilisé l’API NGINX Plus pour ajouter des entrées correspondant à deux noms de domaine complets (FQDN), ainsi que plusieurs domaines aux deux listes de domaines :
$ curl -s http://localhost:8080/api/5/stream/keyvals/dns_config | jq{
"www.some.bad.host": "blocked",
"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 appartenant au domaine « foo.com » mis sur liste noire), 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 server found)
;; global options: +mcd
;; Got answer:
;; ->>HEADER,,- opcode: QUERY, status: NOERROR, id: 58558
;; flags: qr aa rd ad; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 0
;; WARNING: recursion requested but not available
;; QUESTION SECTION:
; www.foo.com. IN A
;; ANSWER SECTION:
www.foo.com. 300 IN A 0.0.0.0
;; Query time: 0 msec
;; SERVER: 172.0.0.1#53(126.0.0.1)
;; WHEN: Mon Dec 2 14:31:35 UTC 2019
;; MSG SIZEW rcvd: 45Accé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 « examples »
Pour essayer NGINX Plus, commencez votre essai gratuit de 30 jours dès aujourd’hui ou contactez-nous pour discuter de vos cas d’utilisation.
À propos de l’auteur
Articles de blog associés

Tendances actuelles des technologies cloud natives, de l’ingénierie de plateforme et de l’IA
Découvrez les principaux enseignements tirés des réponses à l’enquête annuelle F5 NGINX sur les dernières tendances en matière de technologies cloud natives, de sécurité, d’ingénierie de plateforme et d’IA.
Quels contrôleurs Ingress NGINX sont affectés par les vulnérabilités CVE-2022-4886, CVE-2023-5043 et CVE-2023-5044 ?
Lorsque de nouvelles CVE sont signalées, il est facile de ne plus savoir si elles concernent un outil de contrôleur Ingress NGINX particulier, car il existe plusieurs projets. Cet article présente les CVE et explique comment distinguer les différents projets de contrôleurs Ingress afin de dissiper toute confusion.
Votre API est-elle en temps réel ? Testez sa latence avec l’outil rtapi de NGINX
Votre API répond-elle aux requêtes en moins de 30 ms ? Si ce n’est pas le cas, il ne s’agit pas d’une API en temps réel offrant la faible latence exigée par la grande majorité des organisations. Mesurez la latence de votre API avec l’outil rtapi de NGINX et découvrez comment NGINX peut l’aider à offrir une réactivité en temps réel.

Un testeur d’expressions régulières pour NGINX et NGINX Plus
Le testeur d’expressions régulières (regex) pour NGINX et NGINX Plus vous évite de tâtonner en vous indiquant si une expression régulière utilisée dans un bloc location ou map correspond aux valeurs comme prévu. Il génère la configuration appropriée et affiche les valeurs des groupes de capture.
Caches partagés avec les clusters de cache NGINX Plus, partie 1
Optimisez la capacité de votre cache web en le répartissant entre plusieurs serveurs de cache web NGINX ou NGINX Plus. Découvrez comment procéder dans cet article.
Introduction aux microservices
Les microservices suscitent actuellement beaucoup d’intérêt. Cet article de blog est le premier d’une série de sept consacrée à la conception, au développement et au déploiement de microservices.