Como HTTPS e TLS realmente funcionam: handshake e certificados

Security2026-10-27TryQuickToolBox

Você adiciona um certificado SSL, aponta seu domínio para um servidor e o cadeado aparece. A maioria dos desenvolvedores para por aí. Então, um dia, um cliente de API falha com UNABLE_TO_VERIFY_LEAF_SIGNATURE, um aplicativo móvel rejeita seu certificado em um Android mais antigo, ou um balanceador de carga termina o TLS e sua aplicação vê tudo como HTTP simples. De repente, você precisa saber o que realmente acontece entre a conexão TCP e a primeira requisição HTTP.

Este artigo percorre como HTTPS e TLS realmente funcionam: o que o handshake faz, como os certificados são validados, o que mudou no TLS 1.3 e como diagnosticar os erros que você realmente encontrará.

O que o HTTPS realmente adiciona

HTTPS é HTTP enviado sobre uma conexão TLS. O TLS fornece três garantias:

Observe o que não está nessa lista: o cliente não é autenticado por padrão. O TLS autentica o servidor; sua aplicação autentica o usuário.

O handshake TLS 1.2, passo a passo

O TLS 1.2 ainda é comum em infraestruturas mais antigas e em muitos proxies corporativos, então vale a pena entendê-lo. Um handshake completo funciona assim:

  1. ClientHello — o cliente envia as versões de TLS suportadas, um valor aleatório, uma lista de suítes de cifras e (se aplicável) o hostname SNI.
  2. ServerHello — o servidor escolhe uma versão e uma suíte de cifras, retorna seu próprio valor aleatório e envia sua cadeia de certificados.
  3. Troca de chaves — com ECDHE, o servidor envia uma chave pública efêmera; o cliente envia a sua. Ambos derivam o mesmo segredo compartilhado. O servidor assina o transcript do handshake com a chave privada do seu certificado.
  4. Finished — ambos os lados enviam um MAC sobre o transcript do handshake, confirmando que nada foi adulterado.
  5. Dados da aplicação — requisições e respostas HTTP fluem criptografadas.

O detalhe crítico é a troca de chaves efêmera. Com ECDHE, um novo par de chaves é gerado por conexão. Mesmo que um atacante registre anos de tráfego e depois roube a chave privada do servidor, ele não consegue descriptografar sessões passadas. Essa propriedade é chamada de sigilo forward (forward secrecy) e é a principal razão pela qual a troca de chaves RSA estática foi descontinuada.

Como o TLS 1.3 mudou o jogo

O TLS 1.3 simplifica o handshake para uma única ida e volta e remove algoritmos legados completamente.

AspectoTLS 1.2TLS 1.3
Idas e voltas (handshake completo)21
Troca de chavesRSA ou ECDHESomente ECDHE (forward secret)
Suítes de cifrasCifra, MAC e troca de chaves separadosSomente suítes AEAD, ex.: TLS_AES_128_GCM_SHA256
RSA estático, CBC, RC4PermitidoRemovido
Retomada de sessãoIDs de sessão / ticketsPSK com opção 0-RTT

No TLS 1.3, o cliente adivinha o grupo de troca de chaves e envia sua parte na primeira mensagem, para que o servidor possa concluir o acordo de chaves imediatamente. Os certificados ainda são enviados, mas agora são criptografados, o que significa que observadores passivos não podem mais ver qual hostname está sendo servido — apenas o SNI no ClientHello o revela, a menos que o Encrypted Client Hello esteja em uso.

A retomada 0-RTT permite que um cliente recorrente envie dados da aplicação na primeira mensagem. É rápido, mas os dados 0-RTT são reproduzíveis, então nunca use isso para requisições não idempotentes, como pagamentos.

Certificados e validação da cadeia

Um certificado vincula uma chave pública a um hostname. A validação é uma caminhada pela cadeia:

A causa mais comum de erros unable to verify é um certificado intermediário ausente. Os navegadores às vezes contornam isso armazenando intermediários em cache, mas ferramentas de linha de comando e aplicativos móveis falham rigidamente. Sempre sirva a cadeia completa, folha primeiro, depois os intermediários — nunca a raiz.

Depuração prática com OpenSSL

Quando algo quebra, inspecione o que o servidor realmente envia antes de culpar o cliente.

# Mostra a cadeia de certificados que o servidor apresenta
openssl s_client -connect example.com:443 -servername example.com -showcerts

# Negocia apenas TLS 1.3 e lista a cifra escolhida
openssl s_client -connect example.com:443 -tls1_3

# Verifica a validade do certificado em uma linha
echo | openssl s_client -connect example.com:443 2>/dev/null \
  | openssl x509 -noout -dates -subject -ext subjectAltName

Se s_client relatar verify error:num=21:unable to verify the first certificate, a cadeia está incompleta. Se relatar incompatibilidade de hostname, verifique a lista SAN — certificados curinga cobrem apenas um rótulo, então *.example.com corresponde a api.example.com, mas não a a.b.example.com.

Erros comuns de configuração

Uma configuração de servidor razoável

Para o Nginx, uma linha de base moderna é assim:

ssl_protocols TLSv1.2 TLSv1.3;
ssl_prefer_server_ciphers off;
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 1d;
ssl_session_tickets off;

add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
add_header X-Content-Type-Options "nosniff" always;

Deixe o servidor escolher as cifras no TLS 1.3 — a preferência do cliente aí é aceitável porque as suítes são todas fortes. Mantenha os tickets de sessão desativados a menos que você faça rotação das chaves de ticket, já que uma chave de ticket vazada pode comprometer a retomada.

Perguntas frequentes

O HTTPS criptografa o hostname?

Não por padrão. A extensão SNI no ClientHello é enviada em texto simples para que o servidor saiba qual certificado apresentar. O Encrypted Client Hello (ECH) a oculta, mas a adoção ainda é limitada. O caminho e a query string são sempre criptografados.

Por que meu certificado funciona no navegador, mas falha no curl ou em um aplicativo móvel?

Quase sempre é um certificado intermediário ausente. Os navegadores frequentemente buscam ou armazenam intermediários por conta própria, enquanto clientes mais rigorosos exigem que o servidor envie a cadeia completa. Verifique com openssl s_client -showcerts.

O TLS 1.3 é sempre mais rápido que o TLS 1.2?

Para novas conexões, sim — uma ida e volta em vez de duas. Para conexões retomadas, a diferença diminui, e o 0-RTT pode tornar o TLS 1.3 ainda mais rápido, ao custo do risco de replay em requisições não idempotentes.

Se você está auditando um servidor web após uma mudança no TLS, a análise de logs frequentemente revela o impacto real: redirecionamentos quebrados, picos inesperados de 4xx ou clientes ainda acessando HTTP. Você pode carregar um log de acesso no Analisador de logs do Nginx para ver a distribuição dos códigos de status e identificar clientes que nunca concluíram a atualização para HTTPS.