A primeira menção ao QUIC e ao HTTP/3 no blog do NGINX foi há quatro anos (!) e, assim como você, agora estamos ansiosos pela iminente fusão da nossa implementação do QUIC na ramificação principal do NGINX Open Source. Dada a longa gestação, é compreensível que você não tenha pensado muito no QUIC.
Neste ponto, no entanto, como desenvolvedor ou administrador do site, você precisa estar ciente de como o QUIC transfere a responsabilidade por alguns detalhes de rede do sistema operacional para o NGINX (e todos os aplicativos HTTP). Mesmo que networking não seja sua praia, adotar o QUIC significa que se preocupar com a rede agora é (pelo menos um pouco) parte do seu trabalho.
Nesta postagem, nos aprofundamos nos principais conceitos de rede e criptografia usados no QUIC, simplificando alguns detalhes e omitindo informações não essenciais em busca de clareza. Embora algumas nuances possam ser perdidas no processo, nossa intenção é fornecer informações suficientes para que você adote o QUIC de forma eficaz em seu ambiente, ou pelo menos uma base sobre a qual construir seu conhecimento.
Se o QUIC é uma novidade para você, recomendamos que você leia primeiro uma de nossas postagens anteriores e assista ao nosso vídeo de visão geral.
Para uma explicação mais detalhada e completa do QUIC, recomendamos o excelente documento Manageability of the QUIC Transport Protocol do grupo de trabalho QUIC da IETC, juntamente com os materiais adicionais vinculados ao longo deste documento.
Os detalhes obscuros da conexão de rede entre clientes e NGINX não foram particularmente relevantes para a maioria dos usuários até agora. Afinal, com HTTP/1. x e HTTP/2 o sistema operacional cuida da configuração da conexão Transmission Control Protocol (TCP) entre clientes e NGINX. O NGINX simplesmente usa a conexão uma vez que ela é estabelecida.
Com o QUIC, no entanto, a responsabilidade pela criação, validação e gerenciamento de conexões muda do sistema operacional subjacente para o NGINX. Em vez de receber uma conexão TCP estabelecida, o NGINX agora obtém um fluxo de datagramas do User Datagram Protocol (UDP), que ele deve analisar em conexões e fluxos de clientes. O NGINX agora também é responsável por lidar com perda de pacotes, reinicializações de conexão e controle de congestionamento.
Além disso, o QUIC combina iniciação de conexão, negociação de versão e troca de chave de criptografia em uma única operação de estabelecimento de conexão. E embora a criptografia TLS seja tratada de maneira amplamente semelhante para QUIC+HTTP/3 e TCP+HTTP/1+2, há diferenças que podem ser significativas para dispositivos downstream, como balanceadores de carga de Camada 4, firewalls e dispositivos de segurança.
No final das contas, o efeito geral dessas mudanças é uma experiência mais segura, rápida e confiável para os usuários, com muito poucas alterações na configuração ou nas operações do NGINX. Os administradores do NGINX, no entanto, precisam entender pelo menos um pouco do que está acontecendo com o QUIC e o NGINX, mesmo que seja apenas para manter seu tempo médio de inocência o mais curto possível em caso de problemas.
(Vale a pena notar que, embora esta postagem se concentre em operações HTTP porque o HTTP/3 requer QUIC, o QUIC também pode ser usado para outros protocolos. Um bom exemplo é o DNS sobre QUIC, conforme definido no RFC 9250 , DNS sobre conexões QUIC dedicadas .)
Com essa introdução feita, vamos mergulhar em alguns detalhes específicos da rede QUIC.
O QUIC introduz uma mudança significativa no protocolo de rede subjacente usado para transmitir dados de aplicativos HTTP entre um cliente e um servidor.
Como mencionado, o TCP sempre foi o protocolo para transmissão de dados de aplicativos web HTTP. O TCP foi projetado para fornecer dados de forma confiável através de uma rede IP. Ele tem um mecanismo bem definido e compreendido para estabelecer conexões e confirmar o recebimento de dados, juntamente com uma variedade de algoritmos e técnicas para gerenciar a perda e o atraso de pacotes que são comuns em redes não confiáveis e congestionadas.
Embora o TCP forneça transporte confiável, há compensações em termos de desempenho e latência. Além disso, a criptografia de dados não é incorporada ao TCP e deve ser implementada separadamente. Também tem sido difícil melhorar ou estender o TCP em face das mudanças nos padrões de tráfego HTTP – como o processamento do TCP é realizado no kernel do Linux, quaisquer alterações devem ser projetadas e testadas cuidadosamente para evitar efeitos inesperados no desempenho e na estabilidade geral do sistema.
Outro problema é que, em muitos cenários, o tráfego HTTP entre cliente e servidor passa por vários dispositivos de processamento TCP, como firewalls ou balanceadores de carga (conhecidos coletivamente como “middleboxes”), que podem ser lentos para implementar mudanças nos padrões TCP.
O QUIC usa UDP como protocolo de transporte. O UDP foi projetado para transmitir dados através de uma rede IP como o TCP, mas ele intencionalmente descarta o estabelecimento de conexão e a entrega confiável. Essa ausência de sobrecarga torna o UDP adequado para muitas aplicações em que eficiência e velocidade são mais importantes que confiabilidade.
Para a maioria dos aplicativos web, no entanto, a entrega confiável de dados é essencial. Como a camada de transporte UDP subjacente não fornece entrega confiável de dados, essas funções precisam ser fornecidas pelo QUIC (ou pelo próprio aplicativo). Felizmente, o QUIC tem algumas vantagens sobre o TCP nesse aspecto:
Os fluxos QUIC são objetos lógicos que contêm solicitações ou respostas HTTP/3 (ou quaisquer outros dados do aplicativo). Para transmissão entre pontos de extremidade da rede, eles são encapsulados dentro de várias camadas lógicas, conforme ilustrado no diagrama.
Começando de fora para dentro, as camadas e objetos lógicos são:
Cabeçalho QUIC – Contém metadados sobre o pacote. Existem dois tipos de cabeçalho:
O conhecido handshake triplo SYN
/ SYN-ACK
/ ACK
estabelece uma conexão TCP:
Estabelecer uma conexão QUIC envolve etapas semelhantes, mas é mais eficiente. Ele também incorpora a validação de endereço na configuração da conexão como parte do handshake criptográfico. A validação de endereço protege contra ataques de amplificação de tráfego, nos quais um invasor envia ao servidor um pacote com informações de endereço de origem falsificadas para a vítima pretendida do ataque. O invasor espera que o servidor gere mais pacotes ou pacotes maiores para a vítima do que ele mesmo consegue gerar, resultando em uma quantidade enorme de tráfego. (Para mais detalhes, consulte a Seção 8 do RFC 9000, QUIC: Um transporte multiplexado e seguro baseado em UDP .)
Como parte do estabelecimento da conexão, o cliente e o servidor fornecem IDs de conexão independentes que são codificados no cabeçalho QUIC, fornecendo uma identificação simples da conexão, independente do endereço IP de origem do cliente.
Entretanto, como o estabelecimento inicial de uma conexão QUIC também inclui operações para troca de chaves de criptografia TLS, é mais caro computacionalmente para o servidor do que a simples resposta SYN-ACK
que ele gera durante o estabelecimento de uma conexão TCP. Ele também cria um vetor potencial para ataques de negação de serviço distribuído (DDoS) , porque o endereço IP do cliente não é validado antes que as operações de troca de chaves ocorram.
Mas você pode configurar o NGINX para validar o endereço IP do cliente antes que operações criptográficas complexas comecem, definindo a diretiva quic_retry
como on
. Nesse caso, o NGINX envia ao cliente um pacote de nova tentativa contendo um token, que o cliente deve incluir nos pacotes de configuração de conexão.
Esse mecanismo é um pouco parecido com o handshake TCP de três vias e, fundamentalmente, estabelece que o cliente é o proprietário do endereço IP de origem que está apresentando. Sem essa verificação, servidores QUIC como o NGINX podem ficar vulneráveis a ataques DoS fáceis com endereços IP de origem falsificados. (Outro mecanismo QUIC que atenua tais ataques é o requisito de que todos os pacotes de conexão iniciais devem ser preenchidos com um mínimo de 1200 bytes, tornando seu envio uma operação mais cara.)
Além disso, os pacotes de repetição atenuam um ataque semelhante ao ataque de inundação TCP SYN
(em que os recursos do servidor são esgotados por um grande número de handshakes abertos, mas não concluídos, armazenados na memória), codificando detalhes da conexão na ID de conexão que ele envia ao cliente; isso tem o benefício adicional de que nenhuma informação do lado do servidor precisa ser retida, pois as informações de conexão podem ser reconstituídas a partir da ID de conexão e do token posteriormente apresentados pelo cliente. Essa técnica é análoga aos cookies TCP SYN
. Além disso, servidores QUIC como o NGINX podem fornecer um token expirado para ser usado em conexões futuras do cliente, para acelerar a retomada da conexão.
O uso de IDs de conexão permite que a conexão seja independente da camada de transporte subjacente, de modo que alterações na rede não precisem causar a interrupção das conexões. Isso é discutido em Gerenciando com elegância as alterações de endereço IP do cliente .
Com uma conexão estabelecida (e criptografia habilitada, conforme discutido mais adiante ), solicitações e respostas HTTP podem fluir para frente e para trás entre o cliente e o NGINX. Datagramas UDP são enviados e recebidos. No entanto, há muitos fatores que podem causar a perda ou atraso de alguns desses datagramas.
O TCP tem mecanismos complexos para reconhecer a entrega de pacotes, detectar perdas ou atrasos de pacotes e gerenciar a retransmissão de pacotes perdidos, entregando dados devidamente sequenciados e completos para a camada de aplicação. O UDP não possui esse recurso e, portanto, o controle de congestionamento e a detecção de perdas são implementados na camada QUIC.
Quando um pacote contendo quadros que exigem entrega confiável não é confirmado após um período de tempo limite definido, ele é considerado perdido.
Os períodos de tempo limite variam dependendo do que está no pacote – por exemplo, o tempo limite é menor para pacotes que são necessários para estabelecer criptografia e configurar a conexão, porque eles são essenciais para o desempenho do QUIC handshake.
Uma descrição completa da detecção de perdas está além do escopo deste manual. Consulte RFC 9002 , QUIC Loss Detection and Congestion Control , para obter detalhes sobre os mecanismos para determinar tempos limite e quantos dados não confirmados podem estar em trânsito.
O endereço IP de um cliente (chamado de endereço IP de origem no contexto de uma sessão de aplicativo) está sujeito a alterações durante a sessão, por exemplo, quando uma VPN ou gateway altera seu endereço público ou um usuário de smartphone sai de um local coberto por WiFi, o que força uma troca para uma rede celular. Além disso, os administradores de rede tradicionalmente definem tempos limite mais baixos para o tráfego UDP do que para conexões TCP, o que resulta em maior probabilidade de revinculação de tradução de endereço de rede (NAT).
O QUIC fornece dois mecanismos para reduzir a interrupção que pode resultar: um cliente pode informar proativamente o servidor que seu endereço vai mudar, e os servidores podem lidar com elegância com uma mudança não planejada no endereço do cliente. Como o ID da conexão permanece consistente durante a transição, os quadros não confirmados podem ser retransmitidos para o novo endereço IP.
Alterações no endereço IP de origem durante sessões QUIC podem representar um problema para balanceadores de carga downstream (ou outros componentes de rede da Camada 4) que usam o endereço IP de origem e a porta para determinar qual servidor upstream deve receber um datagrama UDP específico. Para garantir o gerenciamento correto do tráfego, os provedores de dispositivos de rede da Camada 4 precisarão atualizá-los para lidar com IDs de conexão QUIC. Para saber mais sobre o futuro do balanceamento de carga e QUIC, consulte o rascunho do QUIC‑LB da IETF: Gerando IDs de conexão QUIC roteáveis .
Em Estabelecimento de conexão , aludimos ao fato de que o handshake QUIC inicial faz mais do que simplesmente estabelecer uma conexão. Ao contrário do handshake TLS para TCP, com UDP a troca de chaves e parâmetros de criptografia TLS 1.3 ocorre como parte da conexão inicial. Esse recurso remove várias trocas e permite tempo de ida e volta zero (0‑RTT) quando o cliente retoma uma conexão anterior.
Além de incorporar o handshake de criptografia ao processo de estabelecimento de conexão, o QUIC criptografa uma porção maior dos metadados do que o TCP+TLS. Mesmo antes da troca de chaves ocorrer, os pacotes de conexão iniciais são criptografados; embora um espião ainda possa obter as chaves, isso exige mais esforço do que com pacotes não criptografados. Isso protege melhor dados como o Indicador de Nome do Servidor (SNI), que é relevante tanto para invasores quanto para possíveis censores estaduais. A Figura 5 ilustra como o QUIC criptografa metadados potencialmente mais sensíveis (em vermelho) do que o TCP+TLS.
Todos os dados na carga útil do QUIC são criptografados usando TLS 1.3. Há duas vantagens: conjuntos de cifras e algoritmos de hash mais antigos e vulneráveis não são permitidos e mecanismos de troca de chaves de sigilo de encaminhamento (FS) são obrigatórios. O sigilo de encaminhamento impede que um invasor descriptografe os dados, mesmo que ele capture a chave privada e uma cópia do tráfego.
Reduzir o número de viagens de ida e volta que devem ocorrer entre um cliente e um servidor antes que quaisquer dados do aplicativo possam ser transmitidos melhora o desempenho dos aplicativos, principalmente em redes com maior latência.
O TLS 1.3 introduziu uma única viagem de ida e volta para estabelecer uma conexão criptografada e zero viagens de ida e volta para retomar uma conexão, mas com o TCP isso significa que o handshake tem que ocorrer antes do TLS Client Hello.
Como o QUIC combina operações criptográficas com configuração de conexão, ele fornece um verdadeiro restabelecimento de conexão 0-RTT, onde um cliente pode enviar uma solicitação no primeiro pacote QUIC. Isso reduz a latência eliminando a viagem de ida e volta inicial para estabelecimento da conexão antes da primeira solicitação.
Nesse caso, o cliente envia uma solicitação HTTP criptografada com os parâmetros usados em uma conexão anterior e, para fins de validação de endereço, inclui um token fornecido pelo servidor durante a conexão anterior.
Infelizmente, a retomada da conexão 0-RTT não fornece sigilo de encaminhamento, portanto, a solicitação inicial do cliente não é criptografada com tanta segurança quanto outros tráfegos na troca. Solicitações e respostas além da primeira solicitação são protegidas pelo Forward Secrecy. Talvez o mais problemático seja que a solicitação inicial também seja vulnerável a ataques de repetição , onde um invasor pode capturar a solicitação inicial e reproduzi-la no servidor diversas vezes.
Para muitos aplicativos e sites, a melhoria de desempenho da retomada da conexão 0-RTT supera essas vulnerabilidades potenciais, mas essa é uma decisão que você precisa tomar por si mesmo.
Este recurso é desabilitado por padrão no NGINX. Para habilitá-lo, defina a diretiva ssl_early_data
como on
.
Alt-Svc
Quase todos os clientes (navegadores em particular) fazem conexões iniciais via TCP/TLS. Se um servidor suportar QUIC+HTTP/3, ele sinaliza esse fato ao cliente retornando uma resposta HTTP/1.1 que inclui o parâmetro h3
no cabeçalho Alt-Svc
. O cliente então escolhe se deseja usar QUIC+HTTP/3 ou manter uma versão anterior do HTTP. (A título de curiosidade, o cabeçalho Alt-Svc
, definido no RFC 7838 , é anterior ao QUIC e pode ser usado para outros propósitos também.)
Alt-Svc
é usado para converter uma conexão de HTTP/1.1 para HTTP/3O cabeçalho Alt-Svc
informa ao cliente que o mesmo serviço está disponível em um host, protocolo ou porta alternativos (ou uma combinação deles). Além disso, os clientes podem ser informados sobre por quanto tempo é seguro assumir que esse serviço continuará disponível.
Alguns exemplos:
Alt-Svc: h3=":443" |
HTTP/3 está disponível neste servidor na porta 443 |
Alt-Svc: h3="new.example.com:8443" |
HTTP/3 está disponível no servidor new.example.com na porta 8443 |
Alt-Svc: h3=":8443"; ma=600 |
HTTP/3 está disponível neste servidor na porta 8443 e estará disponível por pelo menos 10 minutos |
Embora não seja obrigatório, na maioria dos casos os servidores são configurados para responder a conexões QUIC na mesma porta que o TCP+TLS.
Para configurar o NGINX para incluir o cabeçalho Alt-Svc
, use a diretiva add_header
. Neste exemplo, a variável $server_port
significa que o NGINX aceita conexões QUIC na porta para a qual o cliente enviou sua solicitação TCP+TLS, e 86.400 são 24 horas:
add_header Alt-Svc 'h3=":$server_port"; ma=86400';
Este blog fornece uma introdução simplificada ao QUIC e esperamos que lhe dê uma visão geral suficiente para entender as principais operações de rede e criptografia usadas com o QUIC.
Para uma visão mais abrangente sobre a configuração do NGINX para QUIC + HTTP/3, leia Pacotes binários agora disponíveis para a implementação prévia do NGINX QUIC+HTTP/3 em nosso blog ou assista ao nosso webinar, Pratique o NGINX e o QUIC+HTTP/3 . Para obter detalhes sobre todas as diretivas NGINX para QUIC+HTTP/3 e instruções completas para instalar binários pré-compilados ou compilar a partir do código-fonte, consulte a página da Web NGINX QUIC .
"Esta postagem do blog pode fazer referência a produtos que não estão mais disponíveis e/ou não têm mais suporte. Para obter as informações mais atualizadas sobre os produtos e soluções F5 NGINX disponíveis, explore nossa família de produtos NGINX . O NGINX agora faz parte do F5. Todos os links anteriores do NGINX.com redirecionarão para conteúdo semelhante do NGINX no F5.com."