Um novo marco na história da Internet começa diante de nossos olhos: podemos assumir que o HTTP / 3 já foi anunciado. No final de outubro, Mark Nottingham, da IETF,
sugeriu já decidir sobre um nome para o novo protocolo sobre o qual a IETF vem construindo desde 2015. Então, em vez de nomes semelhantes a QUIC, HTTP / 3 alto apareceu. As publicações ocidentais já
escreveram sobre isso e
mais de uma vez . A história do QUIC começou nas entranhas da Good Corporation em 2012, desde então, apenas os servidores do Google suportavam conexões HTTP sobre QUIC, mas o tempo passa e o Facebook já começou a implementar essa tecnologia (em 7 de novembro, o
Facebook e o
LiteSpeed fizeram a primeira interação via HTTP / 3 ); Atualmente, a participação de sites que suportam QUIC é de 1,2%. Por fim, o grupo de trabalho do WebRTC
também está
olhando para o QUIC (além de ver a
API do
QUIC ), portanto, no futuro previsível, o vídeo / áudio em tempo real passará pelo QUIC em vez de RTP / RTCP. Portanto, decidimos que seria ótimo revelar os detalhes do IETF QUIC: especialmente para Habr, preparamos uma tradução do longread que pontilha i. Aproveite!
O QUIC (Quick UDP Internet Connections) é um novo protocolo de camada de transporte criptografado e padrão que possui muitos aprimoramentos HTTP: para acelerar o tráfego e aumentar a segurança. O QUIC também tem um objetivo de longo prazo - eventualmente substituir o TCP e o TLS. Neste artigo, examinaremos os principais chips QUIC e por que a Web se beneficiará deles, bem como os problemas de suporte a esse protocolo completamente novo.
De fato, existem dois protocolos com o mesmo nome: Google QUIC (gQUIC), o protocolo original desenvolvido pelos engenheiros do Google há vários anos, que, após uma série de experimentos, foi adotado pela Internet Engineering Task Force (IETF) para padronização.
O IETF QUIC (daqui em diante simplesmente QUIC) já possui diferenças tão fortes com o gQUIC que pode ser considerado um protocolo separado. Do formato do pacote ao handshake e ao mapeamento HTTP, o QUIC melhorou a arquitetura original do gQUIC, colaborando com muitas organizações e desenvolvedores que têm um objetivo comum: tornar a Internet mais rápida e segura.
Então, quais melhorias o QUIC oferece?
Segurança Integrada (e Desempenho)
Uma das diferenças mais notáveis entre o QUIC e o venerável TCP é o objetivo originalmente declarado de ser um protocolo de transporte
seguro por padrão . O QUIC consegue isso usando autenticação e criptografia, que geralmente ocorre em um nível superior (por exemplo, no TLS), e não no próprio protocolo de transporte.
O handshake QUIC original combina a comunicação de três vias usual por TCP com o handshake TLS 1.3, que fornece autenticação dos participantes, bem como coordenação dos parâmetros criptográficos. Para aqueles que estão familiarizados com TLS: QUIC substitui o nível de gravação TLS por seu próprio formato de quadro, mas ao mesmo tempo usa handshakes TLS.
Isso não apenas permite que a conexão seja sempre criptografada e autenticada, mas também é mais rápida para fazer a conexão inicial: um handshake QUIC comum faz a troca entre o cliente e o servidor em uma passagem, enquanto o TCP + TLS 1.3 faz duas passagens.
No entanto, o QUIC vai além e criptografa os metadados da conexão que podem ser facilmente comprometidos por terceiros. Por exemplo, os invasores podem usar números de pacotes para direcionar usuários através de vários caminhos de rede quando a migração de conexão é usada (veja abaixo). O QUIC criptografa números de pacotes, para que não possam ser corrigidos por ninguém além dos verdadeiros participantes da conexão.
A criptografia também pode ser eficaz contra a “estagnação” - um fenômeno que não permite que a flexibilidade do protocolo seja usada na prática devido a suposições incorretas nas implementações (ossificação - é por isso que o
TLS 1.3 foi estabelecido por um
longo tempo . impedir bloqueios indesejados para novas revisões do TLS).
Bloqueando o início da fila (bloqueio de linha de frente)
Uma das principais melhorias que o
HTTP / 2 nos trouxe é a capacidade de combinar solicitações HTTP diferentes em uma conexão TCP. Isso permite que aplicativos HTTP / 2 processem solicitações em paralelo e façam melhor uso do canal de rede.
Obviamente, este foi um passo significativo adiante. Como os aplicativos anteriores precisavam iniciar muitas conexões TCP + TLS se desejavam processar várias solicitações HTTP ao mesmo tempo (por exemplo, quando o navegador precisa receber CSS e JavaScript para renderizar a página). Criar novas conexões requer vários handshakes, além de inicializar a janela de sobrecarga: isso significa diminuir a renderização da página. Solicitações HTTP combinadas evitam isso.
No entanto, há uma desvantagem: como várias solicitações / respostas são transmitidas pela mesma conexão TCP, elas são igualmente dependentes da perda de pacotes, mesmo que os dados perdidos digam respeito apenas a uma das solicitações. Isso é chamado de "bloquear o início da fila".
O QUIC é mais profundo e fornece suporte de primeira classe para combinar solicitações, por exemplo, solicitações HTTP diferentes podem ser consideradas solicitações QUIC de transporte diferentes, mas ao mesmo tempo todas elas usam a mesma conexão QUIC - ou seja, não são necessários handshakes adicionais, existe um status de congestionamento, as solicitações QUIC são entregues independentemente - como resultado, na maioria dos casos, a perda de pacotes afeta apenas uma solicitação.
Assim, é possível reduzir significativamente o tempo para, por exemplo, a renderização completa de uma página da web (CSS, JavaScript, imagens e outros recursos), especialmente no caso de uma rede sobrecarregada com alta perda de pacotes.
Tão simples, né?
Para cumprir sua promessa, o protocolo QUIC deve superar algumas das suposições que muitos aplicativos de rede têm como certo. Isso pode complicar a implementação e implementação do QUIC.
O QUIC foi projetado para ser entregue através de datagramas UDP, a fim de facilitar o desenvolvimento e evitar problemas com dispositivos de rede que descartam pacotes de protocolos desconhecidos (porque a maioria dos dispositivos suporta UDP). Ele também permite que o QUIC viva no espaço do usuário; portanto, por exemplo, os navegadores poderão implementar novos recursos de protocolo e transmiti-los aos usuários finais, sem aguardar atualizações do sistema operacional.
No entanto, o bom objetivo de reduzir os problemas de rede dificulta a proteção de pacotes e o roteamento adequado.
Um NAT para reunir todos juntos e unir-se com uma única vontade negra
Normalmente, os roteadores NAT trabalham com conexões TCP usando uma tupla de 4 valores (IP e porta de origem mais IP e porta de destino), além de monitorar pacotes TCP SYN, ACK e FIN transmitidos pela rede; Os roteadores podem determinar quando uma nova conexão é estabelecida e quando ela é finalizada. Portanto, é possível gerenciar com precisão as ligações NAT (comunicações entre IP interno e externo e portas).
No caso do QUIC, isso ainda não é possível, porque Os roteadores NAT modernos ainda não conhecem o QUIC, portanto, eles costumam fazer o downgrade para o processamento UDP padrão e menos preciso, o que significa
tempos limite de duração arbitrária (às vezes curta) , que podem afetar as conexões de longo prazo.
Quando ocorre uma nova ligação (por exemplo, devido a um tempo limite), o dispositivo fora do perímetro NAT começa a receber pacotes de outra fonte, o que torna impossível manter a conexão usando apenas uma tupla de 4 valores.
E não é apenas NAT! Um recurso QUIC é chamado de migração de conexão e permite que os dispositivos transfiram conexões para outros endereços / caminhos IP, a seu critério. Por exemplo, um cliente móvel poderá transferir uma conexão QUIC de uma rede móvel para uma rede WiFi já conhecida (o usuário entrou em uma cafeteria favorita etc.).
O QUIC tenta resolver esse problema com o conceito de ID de conexão: uma informação de tamanho arbitrário, transmitida em pacotes QUIC e permitindo identificar a conexão. Os dispositivos de terminal podem usar esse ID para rastrear suas conexões sem se reconciliar com a tupla. Na prática, deve haver muitos IDs que indiquem a mesma conexão, por exemplo, para evitar a conexão de caminhos diferentes quando a conexão é migrada - porque todo o processo é controlado apenas pelos dispositivos finais, não pelas caixas intermediárias.
No entanto, pode haver um problema para as operadoras de telecomunicações que usam roteamento anycast e ECMP, em que um IP pode potencialmente identificar centenas ou milhares de servidores. Como os roteadores de borda nessas redes ainda não sabem como lidar com o tráfego QUIC, pode acontecer que pacotes UDP da mesma conexão QUIC, mas com tuplas diferentes, sejam enviados para servidores diferentes, o que significa desconexão.
Para evitar isso, os operadores podem precisar implementar um balanceador de nível mais inteligente. Isso pode ser conseguido programaticamente sem afetar os próprios roteadores de borda (por exemplo, veja o projeto
Katran no Facebook).
Qpack
Outro recurso útil do HTTP / 2 foi a
compactação de cabeçalho (HPACK) , que permite que os dispositivos finais reduzam o tamanho dos dados enviados descartando solicitações e respostas desnecessárias.
Em particular, entre outras técnicas, o HPACK usa tabelas dinâmicas com cabeçalhos que já foram enviados / recebidos de solicitações / respostas HTTP anteriores, o que permite que os dispositivos se refiram em novas solicitações / respostas a cabeçalhos encontrados anteriormente (em vez de enviá-los novamente) .
As tabelas HPACK devem ser sincronizadas entre o codificador (a parte que envia a solicitação / resposta) e o decodificador (o lado receptor); caso contrário, o decodificador simplesmente não pode decodificar o que recebe.
No caso do HTTP / 2 sobre TCP, essa sincronização é transparente porque a camada de transporte (TCP) entrega solicitações / respostas na mesma ordem em que foram enviadas. Ou seja, você pode enviar instruções ao decodificador para atualizar as tabelas em uma solicitação / resposta simples. Mas com o QUIC, as coisas são muito mais complicadas.
O QUIC pode entregar várias solicitações / respostas HTTP em direções diferentes ao mesmo tempo, o que significa que o QUIC garante a ordem de entrega em uma direção, enquanto não existe essa garantia no caso de várias direções.
Por exemplo, se um cliente envia uma solicitação HTTP A no fluxo QUIC A, bem como uma solicitação B no fluxo B, devido à permutação de pacotes ou a perdas de rede, o servidor receberá a solicitação B antes da solicitação A. E se a solicitação B foi codificada como foi indicado no cabeçalho da solicitação A, o servidor simplesmente não poderá decodificar a solicitação B, pois ainda não viu a solicitação A.
O protocolo gQUIC resolveu esse problema simplesmente tornando todos os cabeçalhos (mas não os corpos) das solicitações / respostas HTTP
seqüenciais em um único fluxo gQUIC. Isso garantiu que todos os cabeçalhos chegassem na ordem correta, independentemente do que acontecesse. Este é um esquema muito simples, com sua ajuda, as soluções existentes podem continuar a usar código aprimorado no HTTP / 2; por outro lado, isso aumenta a probabilidade de bloquear o início da fila, que o QUIC foi projetado para reduzir. Portanto, o grupo de trabalho IETF QUIC desenvolveu um novo mapeamento entre HTTP e QUIC (HTTP / QUIC), bem como um novo princípio de compactação de cabeçalho, QPACK.
No rascunho final das especificações HTTP / QUIC e QPACK, cada troca de solicitação / resposta HTTP usa seu próprio fluxo QUIC bidirecional, portanto, o bloqueio do início da fila não ocorre. Além disso, para oferecer suporte ao QPACK, cada participante cria dois fluxos QUIC adicionais e unidirecionais, um para enviar atualizações de tabela e outro para confirmar seu recebimento. Portanto, o codificador QPACK pode usar o link para a tabela dinâmica somente depois que o decodificador confirmar seu recebimento.
Reflexão refratária
Um problema comum nos protocolos baseados em UDP é sua suscetibilidade a ataques de reflexão, quando o invasor força um servidor a enviar uma quantidade enorme de dados à vítima. O invasor falsifica seu IP para que o servidor pense que a solicitação de dados veio do endereço da vítima.
Esse tipo de ataque pode ser muito eficaz quando a resposta do servidor for incomparavelmente maior que a solicitação. Nesse caso, eles falam de "ganho".
O TCP geralmente não é usado para esses ataques, porque os pacotes no handshake original (SYN, SYN + ACK, ...) têm o mesmo comprimento e, portanto, não têm potencial para "amplificação".
Por outro lado, o handshake QUIC é muito assimétrico: como no TLS, primeiro o servidor QUIC envia sua cadeia de certificados, que pode ser bastante grande, apesar de o cliente enviar apenas alguns bytes (a mensagem do cliente ClientHello TLS está embutida no pacote QUIC ) Por esse motivo, o pacote QUIC original deve ser aumentado para um determinado comprimento mínimo, mesmo que o conteúdo do pacote seja muito menor. Seja como for, essa medida ainda não é muito eficaz, pois uma resposta típica do servidor contém vários pacotes e, portanto, pode ser mais do que um pacote de cliente ampliado.
O protocolo QUIC também define um mecanismo explícito de verificação de origem: o servidor, em vez de fornecer uma resposta grande, envia apenas um pacote de repetição com um token exclusivo, que o cliente envia ao servidor em um novo pacote. Portanto, o servidor tem mais confiança de que o cliente não possui um endereço IP substituto e você pode finalizar o handshake. Menos a decisão - o tempo do aperto de mão aumenta, em vez de um passe, dois já são necessários.
Uma solução alternativa é reduzir a resposta do servidor para um tamanho em que o ataque de reflexão se torne menos eficaz - por exemplo, usando
certificados ECDSA (geralmente eles são muito menores que o RSA). Também experimentamos um mecanismo de
compactação de certificado TLS usando algoritmos de compactação prontos para uso, como zlib e brotli; esse é um recurso que apareceu pela primeira vez no gQUIC, mas atualmente não é suportado no TLS.
Desempenho UDP
Um dos problemas constantes do QUIC é o hardware e o software existentes que não conseguem trabalhar com o QUIC. Já examinamos como o QUIC tenta lidar com caixas intermediárias da rede, como roteadores, mas outra área potencialmente problemática é o desempenho do envio / recebimento de dados entre dispositivos QUIC por UDP. Por muitos anos, foram feitos esforços para otimizar ao máximo as implementações de TCP, incluindo recursos internos de descarregamento em software (por exemplo, sistemas operacionais) e em hardware (interfaces de rede), mas nada disso se refere ao UDP.
No entanto, é apenas uma questão de tempo até que as implementações do QUIC superem essas melhorias e benefícios. Veja os esforços recentes para implementar o
descarregamento de UDP no Linux , o que permitiria que os aplicativos combinassem e transmitissem vários segmentos UDP entre a pilha de rede do espaço do usuário e do espaço do kernel, ao custo de aproximadamente um segmento; outro exemplo é o suporte
à zerocópia para soquetes no Linux , graças ao qual os aplicativos podem evitar o custo de copiar a memória do espaço do usuário no espaço do kernel.
Conclusão
Como o HTTP / 2 e o TLS 1.3, o protocolo QUIC deve trazer uma série de novos recursos que melhorarão o desempenho e a segurança dos sites e de outros participantes da infraestrutura da Internet. O grupo de trabalho da IETF pretende lançar a primeira versão das especificações do QUIC até o final do ano, então é hora de pensar em como podemos tirar o máximo proveito dos benefícios do QUIC.