TLS e HTTPS explicados para desenvolvedores: o handshake sem mistério
O que o TLS realmente garante, o handshake 1.3 passo a passo, cadeia de certificados, forward secrecy e os erros de configuração que derrubam produção.
Neste artigo
A conexão caiu às três da manhã de um sábado, e o motivo apareceu no monitor externo antes de qualquer alerta interno disparar: certificado expirado. Não houve invasão, não houve bug de código, não houve pico de carga. Alguém, meses antes, tinha emitido um certificado à mão, anotado a data de renovação num calendário que ninguém mais consultava, e a validade simplesmente venceu. O navegador de todo cliente passou a mostrar a tela vermelha de aviso, o app parou de conectar, e o time gastou a madrugada renovando manualmente uma coisa que deveria ser invisível. TLS é assim: quando funciona, é transparente a ponto de você esquecer que existe; quando falha, derruba tudo de um jeito que assusta usuário. E boa parte dos desenvolvedores o trata como uma caixa preta que "o time de infra cuida", até o dia em que precisam depurar um erro de handshake e não fazem ideia do que aquelas mensagens significam. Este artigo abre a caixa.
A meta é que você saia daqui entendendo o que o TLS garante e o que ele deliberadamente não garante, como o handshake da versão 1.3 acontece de fato, o que é a cadeia de certificados e por que ela existe, e quais são os erros de configuração que mais aparecem em produção. Sem esoterismo. TLS é um protocolo com objetivos claros, e uma vez que você enxerga os objetivos, cada peça do handshake passa a fazer sentido como resposta a uma ameaça concreta.
O que o TLS garante e o que ele não garante#
TLS entrega três propriedades, e é útil nomeá-las porque cada erro comum é a violação de uma delas. A primeira é confidencialidade: ninguém no meio do caminho — o roteador do café, o provedor, o administrador de rede — consegue ler o conteúdo que trafega, porque ele viaja cifrado. A segunda é integridade: se alguém alterar um único byte em trânsito, a outra ponta detecta e rejeita, então não dá para injetar conteúdo nem corromper a mensagem silenciosamente. A terceira é autenticidade do servidor: você tem garantia criptográfica de que está falando com o servidor dono daquele domínio, e não com um impostor que sequestrou a rota. Essas três juntas são o que transforma HTTP em HTTPS.
Igualmente importante é o que o TLS não faz, porque é aqui que mora a falsa sensação de segurança. TLS não diz nada sobre se o site é honesto, se o dono é confiável ou se o conteúdo é legítimo. Ele garante que você está falando com quem controla aquele domínio de forma privada e íntegra — nada além. Um site de phishing pode ter TLS perfeito. TLS também não protege o dado depois que ele chega: assim que a mensagem é decifrada no servidor, ela vira texto claro na memória, no log, no banco, e a proteção de transporte acabou. E, por padrão, o TLS autentica só o servidor, não o cliente — quem você é do outro lado é problema da camada de autenticação da aplicação, não do TLS. Confundir "conexão segura" com "aplicação segura" é o erro conceitual que sustenta metade dos golpes.
O handshake TLS 1.3, passo a passo#
Toda conexão HTTPS começa com um handshake, uma negociação em que as duas pontas acordam como vão se proteger e provam identidade antes que qualquer dado da aplicação viaje. A versão 1.3 do protocolo, hoje o padrão, simplificou e acelerou drasticamente esse processo em relação à 1.2, cortando uma rodada inteira de ida e volta. Vamos segui-lo em prosa.
Tudo abre com o ClientHello. O cliente — seu navegador, seu app — envia a primeira mensagem anunciando qual versão do TLS suporta, quais conjuntos de cifra conhece, e, crucialmente na 1.3, já manda de imediato os parâmetros efêmeros de troca de chave: ele gera um par de chaves temporário de curva elíptica e envia a parte pública junto. Manda também a extensão SNI, indicando qual nome de domínio quer acessar — detalhe importante porque um único IP pode hospedar centenas de sites, e o servidor precisa saber qual certificado apresentar antes mesmo de estabelecer o canal.
O servidor responde com o ServerHello. Ele escolhe, entre as opções que o cliente ofereceu, a versão e a cifra que vão usar, e envia sua própria parte pública efêmera de curva elíptica. Nesse exato ponto — e isso é o pulo do gato da 1.3 — as duas pontas já têm tudo que precisam para calcular, cada uma do seu lado, o mesmo segredo compartilhado, usando o acordo de chaves ECDHE. É o Diffie-Hellman de curvas elípticas, efêmero: cada ponta combina sua chave privada temporária com a pública recebida da outra e chega, por matemática, ao mesmo valor secreto, sem que esse valor jamais tenha viajado pela rede. Um observador que capturou cada byte trocado não consegue derivar o segredo, porque falta a ele as chaves privadas, que nunca saíram das pontas. A partir desse segredo, ambos derivam as chaves simétricas de sessão, e todo o resto do handshake já viaja cifrado.
Agora vem a prova de identidade. Ainda dentro dessa resposta, já protegido, o servidor envia seu certificado — o documento que amarra o nome de domínio a uma chave pública — e, logo em seguida, uma assinatura digital feita com a chave privada correspondente a esse certificado, cobrindo os dados do handshake. Essa assinatura é o que prova que o servidor de fato possui a chave privada do certificado; não basta apresentar o certificado, é preciso demonstrar posse da chave que só o dono legítimo tem. O cliente valida o certificado — voltaremos a como — e verifica a assinatura. Por fim, cada lado envia a mensagem Finished, um resumo autenticado de todo o handshake que garante que nenhuma das mensagens anteriores foi adulterada por alguém no meio. Se os Finished batem, o canal está estabelecido e os dados da aplicação começam a fluir, cifrados e íntegros. Numa conexão nova de TLS 1.3, isso custa uma única ida e volta de rede.
Forward secrecy: por que as chaves são efêmeras#
Aquele "efêmero" no ECDHE não é detalhe decorativo — é o que dá forward secrecy, e vale entender por quê. As chaves de curva elíptica que as pontas geram no handshake são descartáveis, criadas para aquela sessão e jogadas fora ao final. A consequência é poderosa: mesmo que um atacante grave hoje todo o tráfego cifrado de uma conexão e, anos depois, consiga roubar a chave privada de longo prazo do certificado do servidor, ele ainda não conseguirá decifrar aquela sessão gravada, porque a chave que a protegeu foi efêmera e não existe mais. Cada sessão é uma ilha. Sem forward secrecy, comprometer a chave do servidor um dia comprometeria retroativamente todo o histórico de tráfego — o pesadelo do "grave agora, decifre depois". Por isso o TLS 1.3 tornou o modo efêmero obrigatório: não há mais a opção antiga, insegura, de trocar chave por RSA estático.
A cadeia de certificados e as CAs#
Um certificado é uma afirmação: "a chave pública tal pertence ao domínio tal". Mas por que seu navegador acreditaria nessa afirmação? Porque ela vem assinada por uma autoridade certificadora — uma CA — em quem o navegador já confia. Só que a CA raiz, cuja chave é preciosíssima, não assina certificados de sites diretamente; ela assina certificados intermediários, e são estes que assinam o certificado do seu site. Isso forma uma cadeia: o certificado do servidor aponta para o intermediário que o assinou, que aponta para a raiz que o assinou. O navegador percorre essa cadeia até chegar a uma raiz que está no seu armazenamento de confiança, embutido no sistema operacional ou no próprio navegador. Se a cadeia fecha numa raiz confiável e cada assinatura confere, o certificado é aceito.
Um erro operacional comuníssimo é o servidor não enviar a cadeia intermediária completa. Ele manda só o certificado da ponta, e alguns clientes — sobretudo apps e bibliotecas fora do navegador, que não têm o cache de intermediários que os browsers acumulam — falham a validação com um erro obscuro de "certificado desconhecido". O certificado está correto; falta a corrente que o liga à raiz. Configurar o servidor para enviar o fullchain resolve.
A grande transformação recente nesse mundo foi o Let's Encrypt e o protocolo ACME. Antes, obter certificado era um processo manual, pago e demorado; hoje um cliente ACME prova automaticamente ao emissor que você controla o domínio — respondendo a um desafio via HTTP ou DNS — e recebe o certificado em segundos, de graça. E aqui está a lição que abriu este artigo: certificados Let's Encrypt duram apenas noventa dias, deliberadamente, para forçar automação. Se você renova à mão, vai esquecer e vai cair de madrugada num sábado. A renovação tem que ser automática, agendada com folga, com monitoramento externo que alerta se a validade está chegando perto. Certificado expirado é sempre falha de processo, nunca de tecnologia.
HSTS, redirecionamento e os erros que derrubam produção#
Servir o site em HTTPS não basta se o usuário ainda consegue chegar por HTTP. O redirecionamento de HTTP para HTTPS resolve o primeiro contato, mas há uma janela: naquela primeira requisição em texto claro, um atacante na rede pode interceptar e impedir a subida para HTTPS — o ataque de stripping. A defesa é o HSTS, um cabeçalho que instrui o navegador a, dali em diante, jamais tentar HTTP naquele domínio, indo direto para HTTPS por conta própria. Com HSTS ativo e, idealmente, o domínio na lista de preload embutida nos navegadores, aquela primeira janela some. Ativar HSTS é barato e fecha um buraco real.
Alguns erros de configuração aparecem repetidamente e vale reconhecê-los de cara. Mixed content é quando uma página HTTPS carrega um recurso — imagem, script, folha de estilo — por HTTP puro; o navegador ou bloqueia o recurso ou degrada a segurança da página inteira, e a origem costuma ser uma URL absoluta esquecida no código. Cipher suites fracas são conjuntos de cifra obsoletos que um servidor mal configurado ainda aceita, permitindo que um atacante force a negociação para o elo mais fraco; a correção é desabilitar versões antigas do protocolo e cifras legadas, deixando só TLS 1.2 e 1.3 com suites modernas. E o erro mais traiçoeiro, já mencionado no artigo irmão sobre criptografia: terminar o TLS no balanceador de carga e trafegar do balanceador até os serviços de backend em HTTP puro. Do ponto de vista do cliente, o cadeado está lá; internamente, o dado sensível anda nu por um segmento de rede que você presume confiável e que raramente é. Se o dado justifica TLS na borda, ele justifica TLS — ou mTLS — no trecho interno também.
Certificate pinning e o mito do cadeado verde#
Para aplicações com requisitos altos, sobretudo apps móveis, existe o certificate pinning: em vez de confiar em qualquer CA do armazenamento do sistema, o app embute qual certificado ou qual chave pública específica espera do servidor, e recusa a conexão se vier outro, mesmo que assinado por uma CA legítima. Isso protege contra o cenário em que uma CA é comprometida ou coagida a emitir um certificado fraudulento para o seu domínio. O custo é operacional e afiado: se você trocar o certificado sem atualizar o pin no app, você mesmo se bloqueia, e usuários com a versão antiga ficam sem conseguir conectar até atualizarem. Pinning é ferramenta poderosa que corta na própria mão se a rotação não for coreografada com cuidado.
E fica o parágrafo que todo desenvolvedor deveria repetir para usuários e para si mesmo: cadeado não significa site confiável. O cadeado na barra de endereço diz apenas que a conexão até aquele domínio é privada e íntegra, e que o domínio provou controlar aquele certificado. Ele não diz que o domínio é honesto, que a empresa por trás é legítima ou que é seguro digitar seus dados ali. Um site de phishing hospedado num domínio parecido, com um certificado Let's Encrypt gratuito e válido, exibe o mesmo cadeado que o seu banco. A validação de domínio é automática e não atesta identidade de organização. O cadeado é sobre o canal, nunca sobre o destino.
Fechando: o que levar para o código#
Em prosa de checklist, para não esquecer o essencial. Entenda que TLS garante confidencialidade, integridade e autenticidade do servidor, e mais nada — a segurança da aplicação começa depois que a mensagem é decifrada. Prefira TLS 1.3, que é mais rápido e só oferece modos com forward secrecy, e desabilite versões e cifras antigas. Envie sempre a cadeia completa de certificados, ou apps e bibliotecas vão falhar de formas difíceis de depurar. Automatize a emissão e a renovação via ACME, com validade curta e monitoramento externo que alerta antes de vencer, porque certificado expirado é falha de processo evitável. Ative HSTS e redirecione HTTP para HTTPS para fechar a janela de stripping. Não deixe trecho interno em texto claro por confiar cegamente na rede privada; leve o TLS ponta a ponta. Reserve pinning para quando o ganho justifica o risco de se autobloquear. E jamais confunda o cadeado do canal com a confiabilidade do destino. TLS é aborrecidamente confiável quando você o configura direito e o automatiza; os desastres quase sempre vêm da operação, não da criptografia.
