Atualmente, fala-se muito sobre o Sistema de Nomes de Domínio (DNS), com grandes mudanças sendo propostas para esse protocolo de 36 anos. O serviço de nomes da Internet, que teve origem na ARPANET, nunca sofreu nenhuma alteração incompatível com versões anteriores desde a sua criação. Mas novas propostas para mudar o mecanismo de transporte do DNS podem estar prestes a mudar isso.
Neste post, analiso duas tecnologias emergentes para proteger o DNS, o DNS sobre TLS (DoT) e o DNS sobre HTTPS (DoH), e mostro como implementá-las usando o NGINX Open Source e o NGINX Plus.
[Editor – Este post é um dos vários que exploram casos de uso do módulo JavaScript do NGINX. Para ver a lista completa, consulte Casos de uso do módulo JavaScript do NGINX.
O código desta publicação foi atualizado para usar a js_import diretiva, que substitui a obsoleta js_include no NGINX Plus R23<.htmla> e em versões posteriores. Para obter mais informações, consulte a documentação de referência do módulo JavaScript do NGINX — a seção Exemplo de configuração mostra a sintaxe correta para os arquivos de configuração do NGINX e JavaScript.]
A história do DNS
O DNS foi a segunda tentativa de criar um serviço de nomes para a Internet inicial da Agência de Projetos de Pesquisa Avançada (ARPA); a primeira foi o protocolo Internet Name Server, publicado por John Postel em 1979 como IEN-116. O DNS foi projetado para ser hierárquico e fornecer uma estrutura que permitisse descentralizar os nomes de host em zonas, gerenciadas por diversas autoridades independentes. As primeiras RFCs sobre DNS foram publicadas em 1983 (RFC 882 e 883) e, embora tenham recebido várias extensões ao longo dos anos, um cliente desenvolvido de acordo com os padrões definidos naquela época ainda funcionaria hoje.
Então, por que mudar o protocolo agora? Ele claramente funciona como previsto, o que justifica a confiança de seus autores, que tinham tanta certeza de que haviam acertado que nem sequer incluíram um número de versão no pacote DNS — não consigo pensar em muitos outros protocolos que possam afirmar o mesmo. O DNS foi concebido em uma época mais inocente, quando a maioria dos protocolos usava texto não criptografado e, muitas vezes, ASCII de 7 bits, mas a Internet de hoje é um lugar muito mais assustador do que a ARPANET da década de 1980. Atualmente, a maioria dos protocolos adotou o Transport Layer Security (TLS) para fins de criptografia e verificação. Os críticos do DNS argumentam que proteções adicionais de segurança já deveriam ter sido implementadas há muito tempo.
Assim, da mesma forma que o DNS foi a segunda tentativa de fornecer um protocolo de serviço de nomes para a Internet, o DNS sobre TLS (DoT) e o DNS sobre HTTPS (DoH) estão surgindo como novas tentativas de proteger o protocolo DNS. A primeira tentativa foi uma extensão conhecida como DNSSEC e, embora a maioria dos domínios de primeiro nível (TLDs) utilize DNSSEC, ela nunca teve como objetivo criptografar os dados transportados nos pacotes DNS; ela apenas permite verificar se os dados não foram adulterados. DoT e DoH são extensões de protocolo que encapsulam o DNS em um túnel TLS e, se adotadas, acabarão com 36 anos de compatibilidade retroativa.
DoT e DoH em mais detalhes
Acredito que o DoT seja amplamente considerado uma extensão sensata. Ele já recebeu seu próprio número de porta (TCP/853) da Internet Assigned Numbers Authority (IANA) e simplesmente encapsula pacotes DNS via TCP em um túnel criptografado com TLS. Muitos protocolos já fizeram isso antes: HTTPS é HTTP dentro de um túnel TLS, e SMTPS, IMAPS e LDAPS são versões seguras desses protocolos. O DNS sempre usou UDP (ou TCP, em determinados casos) como protocolo de transporte, portanto, adicionar o encapsulamento TLS não representa uma mudança tão significativa.
O DoH, por outro lado, é um pouco mais controverso. O DoH pega um pacote DNS e o encapsula em uma solicitação HTTP GET ou POST, que é então enviada usando HTTP/2 ou superior por meio de uma conexão HTTPS. Para todos os efeitos, ela se parece com qualquer outra conexão HTTPS, e é impossível para empresas ou provedores de serviços ver quais solicitações estão sendo feitas. A Mozilla e outros defensores afirmam que essa prática aumenta a privacidade dos usuários ao manter os sites que eles visitam longe de olhares indiscretos.
Mas isso não é bem verdade. Os críticos do DoH ressaltam que ele não chega a ser o Tor do DNS, pois, quando o navegador finalmente se conecta ao host que consultou usando DoH, a solicitação quase certamente usa a extensão TLS Indicação do Nome do Servidor (SNI) — que inclui o nome do host e é enviada sem criptografia. Além disso, se o navegador tentar validar o certificado do servidor usando o Protocolo de Status de Certificado Online (OSCP), esse processo provavelmente também ocorrerá sem criptografia. Portanto, qualquer pessoa capaz de monitorar consultas DNS também pode ler o SNI da conexão ou o nome do certificado na validação OCSP.
Para muitas pessoas, o maior problema do DoH é que os fornecedores de navegadores escolhem os servidores DNS para os quais as solicitações DoH feitas por seus usuários são enviadas por padrão (no caso dos usuários do Firefox nos EUA, por exemplo, os servidores DNS pertencem à Cloudflare). A operadora dos servidores DNS pode ver o endereço IP do usuário e os nomes de domínio dos sites aos quais ele faz solicitações. Isso pode não parecer muita coisa, mas pesquisadores da Universidade de Illinois descobriram que é possível deduzir quais sites uma pessoa visitou usando apenas os endereços de destino das solicitações de elementos de uma página da web, a chamada impressão digital de carregamento de página. Essas informações podem então ser usadas para “traçar o perfil do usuário e direcionar publicidade a ele”.
Como o NGINX pode ajudar?
DoT e DoH não são inerentemente ruins, e há casos de uso em que aumentam a privacidade do usuário. No entanto, há um consenso crescente de que um serviço público e centralizado de DoH é prejudicial à privacidade do usuário, e recomendamos que você evite usá-lo a todo custo.
De qualquer forma, para seus sites e aplicativos, você provavelmente gerencia suas próprias zonas DNS — algumas públicas, outras privadas e algumas com DNS de horizonte dividido. Em algum momento, talvez você decida executar seu próprio serviço DoT ou DoH. É aí que o NGINX pode ajudar.
Os aprimoramentos de privacidade oferecidos pelo DoT trazem grandes vantagens para a segurança do DNS, mas e se o seu servidor DNS atual não for compatível com DoT? O NGINX pode ajudar fornecendo um gateway entre o DoT e o DNS padrão.
Ou talvez você goste do potencial do DoH para contornar firewalls nos casos em que a porta do DoT possa estar bloqueada. Mais uma vez, o NGINX pode ajudar, fornecendo um gateway de DoH para DoT/DNS.
Implantando um gateway DoT-DNS simples
O módulo Stream (TCP/UDP) do NGINX oferece suporte à terminação SSL, portanto, é realmente muito simples configurar um serviço DoT. Você pode criar um gateway DoT simples com apenas algumas linhas de configuração do NGINX.
Você precisa de um bloco upstream para seus servidores DNS e de um bloco server para a terminação TLS:
Carregando exemplo de código…
É claro que também podemos fazer o caminho inverso e encaminhar as solicitações de DNS recebidas para um servidor DoT upstream. No entanto, isso é menos útil, pois a maior parte do tráfego DNS usa UDP, e o NGINX só consegue fazer a conversão entre DoT e outros serviços TCP, como DNS baseado em TCP.
Carregando exemplo de código…
Um gateway DoH-DNS simples
Em comparação com um gateway DoT, a configuração de um gateway DoH simples é um pouco mais complexa. Precisamos de um serviço HTTPS e de um serviço Stream, além de usar código JavaScript e o módulo JavaScript do NGINX<.htmla> (njs) para fazer a conversão entre os dois protocolos. A configuração mais simples é:
Carregando exemplo de código…
O script JavaScript usado nesta configuração (nginx_stream.js) inclui vários arquivos de módulos da biblioteca DNS. No módulo dns.js, a variável dns_decode_level define o nível de processamento realizado nos pacotes DNS. Obviamente, o processamento de pacotes DNS prejudica o desempenho. Se você estiver usando uma configuração como a acima, defina dns_decode_level como 0.
Um gateway DoH mais avançado
Aqui na NGINX, somos realmente muito bons em HTTP, por isso acreditamos que usar a NGINX apenas como um simples gateway DoH é desperdiçar uma oportunidade.
O código JavaScript usado aqui pode ser configurado para realizar a decodificação total ou parcial dos pacotes DNS. Isso nos permite criar um cache de conteúdo HTTP para as consultas DoH, com os cabeçalhos Expires e Cache-Control definidos com base nos menores TTLs das respostas DNS.
Veja a seguir um exemplo mais completo, com otimizações adicionais de conexão e suporte a cache de conteúdo e registro de logs:
Carregando exemplo de código…
Um filtro DNS avançado usando recursos do NGINX Plus
Se você tiver uma assinatura do NGINX Plus, poderá combinar os exemplos acima com alguns dos recursos mais avançados do NGINX Plus, como verificações ativas de integridade e alta disponibilidade, ou até mesmo usar a API de limpeza de cache para gerenciar respostas DoH armazenadas em cache.
Também é possível usar o armazenamento de chave-valor do NGINX Plus para criar um sistema de filtragem de DNS que proteja os usuários contra domínios maliciosos, retornando uma resposta DNS que efetivamente impeça o acesso a eles. Você pode gerenciar dinamicamente o conteúdo do armazenamento de chave-valor com a API RESTful do NGINX Plus.
Definimos duas categorias de domínios maliciosos: “bloqueados” e “blackhole”. O sistema de filtragem de DNS trata uma consulta DNS sobre um domínio de maneira diferente, dependendo da categoria à qual ele pertence:
- Para domínios bloqueados, o sistema retorna a resposta
NXDOMAIN(indicando que o domínio não existe) - Para domínios de blackhole, ele retorna um único registro DNS
Acom o valor 0.0.0.0 em resposta a solicitações de registrosA, ou um único registroAAAAcom o valor :: em resposta a solicitações de registrosAAAA(IPv6); para outros tipos de registro, ele retorna uma resposta sem nenhuma resposta
Quando nosso filtro de DNS recebe uma solicitação, ele primeiro verifica se há uma chave que corresponda exatamente ao FQDN consultado. Se encontrar uma, ele “limpa” (bloqueia ou direciona para um blackhole) a solicitação conforme especificado pelo valor associado. Se não houver uma correspondência exata, ele procura o nome de domínio em duas listas – uma de domínios bloqueados e outra de domínios direcionados para blackhole – e limpa a solicitação da maneira apropriada caso encontre uma correspondência.
Se o domínio consultado não for malicioso, o sistema o encaminhará a um servidor DNS do Google para processamento normal.
Configurando o armazenamento de chave-valor
Definimos os domínios que consideramos maliciosos em dois tipos de entradas no armazenamento de chave-valor do NGINX Plus:
- Entradas individuais para nomes de domínio totalmente qualificados (FQDNs), cada uma com o valor
blockedoublackhole - Duas listas de domínios, com chaves chamadas
blocked_domainseblackholed_domains, cada uma associada a uma lista de domínios no formato de valores separados por vírgulas (CSV)
A configuração a seguir para o armazenamento de chave-valor deve ser inserida no contexto stream. A diretiva keyval_zone aloca um bloco de memória para o armazenamento de chave-valor, chamado dns_config. A primeira diretiva keyval carrega qualquer par de chave-valor de FQDN correspondente que tenha sido definido, enquanto a segunda e a terceira definem as duas listas de domínios:
Carregando exemplo de código…
Em seguida, podemos usar a API do NGINX Plus para atribuir o valor blocked ou blackhole a qualquer chave de FQDN que queiramos explicitamente filtrar ou modificar a lista em formato CSV associada à chave blocked_domains ou blackhole_domains. Podemos modificar ou remover FQDNs exatos ou alterar o conjunto de domínios em qualquer uma das listas a qualquer momento, e o filtro de DNS é atualizado instantaneamente com as alterações.
Escolhendo o servidor upstream para processar a solicitação
A configuração a seguir carrega a variável $dns_response, que é preenchida por uma diretiva js_preread nos blocos server definidos em Configuração dos servidores que escutam consultas DNS abaixo. Quando o código JavaScript invocado determina que a solicitação precisa ser filtrada, ele define a variável como blocked ou blackhole, conforme apropriado.
Usamos uma diretiva map para atribuir o valor da variável $dns_response à variável $upstream_pool, controlando assim qual dos grupos de upstream em Definição dos servidores upstream abaixo processa a solicitação. As consultas de domínios não maliciosos são encaminhadas ao servidor DNS padrão do Google, enquanto as consultas de domínios bloqueados ou descartados são processadas pelo servidor upstream correspondente a essas categorias.
Carregando exemplo de código…
Definindo os servidores upstream
Esta configuração define os grupos de servidores upstream blocked, blackhole e google, que processam solicitações de domínios bloqueados, blackhole e não maliciosos, respectivamente.
Carregando exemplo de código…
Configurando os servidores que recebem consultas DNS
Aqui definimos os servidores no contexto stream que escutam as solicitações DNS recebidas. A diretiva js_preread invoca o código JavaScript que decodifica o pacote DNS, recupera o nome de domínio do campo NAME do pacote e procura o domínio no armazenamento de chave-valor. Se o nome de domínio corresponder a uma chave FQDN ou estiver na zona de um dos domínios da lista blocked_domains ou blackhole_domains, ele será filtrado. Caso contrário, será enviado ao servidor DNS do Google para resolução.
Carregando exemplo de código…
Está quase pronto – só precisamos adicionar nosso último bloco server, que responde às consultas com a resposta de blackhole ou de bloqueio.
Carregando exemplo de código…
Observe que os servidores neste bloco são quase idênticos aos servidores DNS reais logo acima. A principal diferença é que estes servidores enviam um pacote de resposta ao cliente, em vez de encaminhar a solicitação para um grupo de servidores DNS upstream. Nosso código JavaScript detecta quando está sendo executado na porta 9953 ou 9853 e, em vez de definir um sinalizador para indicar que o pacote deve ser bloqueado, preenche $dns_response com o pacote de resposta propriamente dito. É só isso.
É claro que também poderíamos ter aplicado essa filtragem aos serviços DoT e DoH, mas usamos o DNS padrão para simplificar. A integração da filtragem de DNS com o gateway DoH fica como exercício para o leitor.
Testando o filtro
Anteriormente, usamos a API do NGINX Plus para adicionar entradas de dois FQDNs e alguns domínios às duas listas de domínios:
$ 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"
}Portanto, quando solicitamos a resolução de www.foo.com (um host dentro do domínio foo.com bloqueado), recebemos um registro A com o endereço 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: 45Acessando o código
Os arquivos de DOH e DOT estão disponíveis no meu repositório do GitHub:
- O código JavaScript na pasta njs.d/dns folder
- A configuração do NGINX na pasta examples folder
Para experimentar o NGINX Plus, comece hoje mesmo sua avaliação gratuita de 30 dias ou entre em contato conosco para conversar sobre seus casos de uso.
Sobre o autor
Publicações relacionadas no blog

Como o F5 NGINX One aprimora o gerenciamento e a observabilidade
Descubra como o F5 NGINX One aprimora o gerenciamento e a observabilidade de ambientes híbridos e multicloud ao oferecer um console web centralizado baseado em SaaS, com insights em tempo real, conformidade automatizada e gerenciamento simplificado de configurações.

Do OpenAPI ao NGINX como gateway de API usando uma API declarativa
Descubra como transformar uma definição de esquema OpenAPI em uma configuração NGINX totalmente funcional, operando como um API Gateway com a segurança de um Web Application Firewall e um Portal do Desenvolvedor, usando uma abordagem declarativa de API.

Como gerenciar picos repentinos de tráfego e sobrecarga do servidor
Picos de tráfego e sobrecarga de servidores são preocupações sérias para varejistas online em qualquer época, mas especialmente durante a “Cyber Season” de compras de fim de ano. Detalhamos como você pode aproveitar as soluções de entrega de aplicações de nível de produção da NGINX para se preparar para aumentos repentinos de tráfego.

Distribuição segura de chaves privadas SSL com o NGINX
Descrevemos três maneiras progressivamente mais seguras de proteger chaves privadas SSL ao configurar o NGINX para processar tráfego HTTPS: permitir acesso de leitura apenas ao usuário root, criptografar as chaves com senhas armazenadas separadamente e distribuir as senhas a partir de um repositório central.
Agrupando solicitações de API em lotes com NGINX Plus e o módulo JavaScript do NGINX
O módulo JavaScript do NGINX lançado com o NGINX Plus R15 oferece suporte a subsolicitações, possibilitando uma classe totalmente nova de casos de uso para o NGINX Plus. Este exemplo completo também usa a API do NGINX Plus e os módulos de chave-valor para converter solicitações de API dos clientes em solicitações separadas para as APIs dos microsserviços que compõem um aplicativo.
Como superar o esgotamento de portas efêmeras no NGINX e no NGINX Plus
Confira dicas para evitar o esgotamento de portas efêmeras com ajustes no kernel do Linux, conexões keepalive e conexões vinculadas dinamicamente a endereços IP locais.