Fundamentos de Programação/03 - Sistemas Reais/Semana 10 - Rede e HTTP6 min
TLS
- O que TLS garante: confidencialidade, integridade, autenticidade — as três?
- Qual o papel do certificado e de quem o assinou?
- Por que o handshake usa assimétrico e o tráfego usa simétrico?
- O que exatamente falha quando o navegador diz "certificado inválido"?
Conceito
TLS entrega três garantias, e quase todo mundo pensa só na primeira:
| Garantia | Significa | Sem ela |
|---|---|---|
| confidencialidade | ninguém no caminho lê | qualquer roteador lê sua senha |
| integridade | ninguém no caminho altera sem detecção | injeção de conteúdo, downgrade |
| autenticidade | você está falando com quem pensa que está | man-in-the-middle perfeito |
A terceira é a que o certificado resolve, e é a mais sutil: sem autenticidade, um atacante estabelece um canal cifrado com você e outro com o servidor, lendo tudo no meio. A criptografia funcionaria perfeitamente — com a pessoa errada.
O certificado liga uma identidade (o nome do host) a uma chave pública, e é assinado por uma autoridade certificadora. Seu sistema confia em ~150 CAs raiz; a cadeia vai do certificado do servidor até uma delas. Quem assinou é o que importa — o certificado em si é público e copiável.
Por que o handshake usa assimétrico e o tráfego usa simétrico: criptografia assimétrica é ordens de magnitude mais lenta. Então ela é usada apenas para (a) autenticar o servidor e (b) acordar uma chave simétrica. Depois disso, todo o tráfego usa a chave simétrica, que é rápida e frequentemente acelerada em hardware (AES-NI).
O que "certificado inválido" quer dizer, concretamente:
| Causa | Significado |
|---|---|
| expirado | passou da validade (o mais comum, e o mais bobo) |
| nome errado | o certificado é para a.com e você acessou b.com |
| emissor não confiável | autoassinado, ou CA interna não instalada |
| revogado | a CA declarou inválido (OCSP/CRL) |
| cadeia incompleta | o servidor não enviou os intermediários |
TLS 1.3 melhorou o que importa: handshake de 1 RTT (contra 2 no 1.2), remoção de cifras antigas e de renegociação, sigilo futuro (forward secrecy) obrigatório, e retomada 0-RTT.
Na prática
Verificado contra um servidor TLS local:
TLS: versao=TLS 1.3 cifra=TLS_AES_128_GCM_SHA256
E o custo, isolado das idas e voltas de rede (é loopback):
TCP connect: 223µs
TLS handshake: 3.889ms <- 17x o TCP connect, só de CPU
Esses 3,9 ms são criptografia de chave pública — em rede real, somam-se a eles 1 RTT (TLS 1.3) ou 2 (TLS 1.2) (2. Ciclo de uma Requisição). É a razão pela qual keep-alive importa tanto em HTTPS: você paga isso uma vez por conexão, não por requisição.
Em Go
Go tem TLS na biblioteca padrão (crypto/tls), sem OpenSSL — implementação própria em
Go. Consequências: um binário estático fala HTTPS sem dependência de sistema, e as
vulnerabilidades de OpenSSL não te afetam.
Inspecionar a conexão é direto, e é como você audita o que realmente foi negociado:
resp, _ := cliente.Get(url)
cs := resp.TLS // *tls.ConnectionState
tls.VersionName(cs.Version) // "TLS 1.3"
tls.CipherSuiteName(cs.CipherSuite) // "TLS_AES_128_GCM_SHA256"
cs.PeerCertificates[0].Subject.CommonName
cs.PeerCertificates[0].NotAfter // quando expira
Servidor TLS mínimo:
srv := &http.Server{Addr: ":443", Handler: mux, TLSConfig: &tls.Config{MinVersion: tls.VersionTLS12}}
srv.ListenAndServeTLS("cert.pem", "key.pem")
MinVersion merece atenção: sem definir, versões antigas podem ser aceitas. tls.VersionTLS12
é o piso razoável hoje.
InsecureSkipVerify: true desliga a autenticidade — as três garantias caem a duas&tls.Config{InsecureSkipVerify: true} // NUNCA em produção
Ele mantém a cifra e desliga a verificação do certificado, o que reabre exatamente o man-in-the-middle que o TLS existia para impedir. O canal continua cifrado — com o atacante.
Se o problema é uma CA interna, a solução é adicionar a CA, não desligar a verificação:
pool := x509.NewCertPool()
pool.AppendCertsFromPEM(pemDaCAInterna)
&tls.Config{RootCAs: pool}
Em teste, httptest.NewTLSServer gera um certificado e srv.Client() devolve um cliente
que confia nele — sem InsecureSkipVerify e sem gerar certificado à mão. É o jeito
correto de testar código HTTPS (2. Teste de Integração).
mTLS (autenticação mútua, comum entre serviços) é ClientCAs + ClientAuth:
&tls.Config{ClientCAs: pool, ClientAuth: tls.RequireAndVerifyClientCert}
Respostas às perguntas-guia
1. O que TLS garante: confidencialidade, integridade, autenticidade — as três?
As três. E a autenticidade é a que sustenta as outras duas: sem saber com quem você fala, cifrar e verificar integridade não protegem de nada.
Em Go: InsecureSkipVerify remove exatamente a autenticidade, mantendo a aparência de
segurança.
2. Qual o papel do certificado e de quem o assinou?
O certificado liga nome a chave pública. Quem assinou é o que cria a confiança — o certificado sozinho não prova nada, porque qualquer um gera um.
Em Go: cs.PeerCertificates[0].Issuer mostra o emissor; RootCAs define em quem você
confia.
3. Por que o handshake usa assimétrico e o tráfego usa simétrico?
Porque assimétrico é lento demais para o volume, e simétrico não resolve o problema de acordar a chave com quem você nunca conversou. Cada um faz o que é bom.
Em Go: medido — 3,9 ms de handshake contra 223 µs de TCP connect, e depois o tráfego é AES-GCM acelerado em hardware.
4. O que exatamente falha quando o navegador diz "certificado inválido"?
Uma das cinco causas da tabela. Em Go o erro é específico e vale ler em vez de contornar:
x509: certificate has expired, x509: certificate is valid for a.com, not b.com,
x509: certificate signed by unknown authority.
Cada uma tem correção diferente — e nenhuma delas é InsecureSkipVerify.
Trade-offs
Do conceito:
- TLS compra as três garantias e cobra 1–2 RTTs por conexão nova mais CPU de handshake.
- TLS 1.3 compra 1 RTT e sigilo futuro obrigatório, e cobra compatibilidade com clientes antigos.
- Certificado de CA pública compra confiança universal e cobra renovação e exposição em logs de transparência; CA interna compra controle e cobra distribuir a raiz para todo cliente.
Em Go:
crypto/tlspróprio compra binário estático e independência de OpenSSL; cobra depender do ciclo de releases de Go para correções.httptest.NewTLSServercompra teste HTTPS honesto quase de graça.InsecureSkipVerifycompra cinco minutos hoje e cobra um incidente depois.
Exemplo prático
package main
import (
"crypto/tls"
"crypto/x509"
"fmt"
"io"
"net/http"
"net/http/httptest"
"time"
)
func main() {
srv := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
fmt.Fprint(w, "conteúdo protegido")
}))
defer srv.Close()
// 1. o cliente CORRETO em teste: confia no certificado do servidor de teste
resp, err := srv.Client().Get(srv.URL)
if err != nil {
fmt.Println("erro:", err)
return
}
corpo, _ := io.ReadAll(resp.Body)
resp.Body.Close()
fmt.Printf("resposta: %q\n", corpo)
cs := resp.TLS
fmt.Printf("versão: %s\n", tls.VersionName(cs.Version))
fmt.Printf("cifra: %s\n", tls.CipherSuiteName(cs.CipherSuite))
fmt.Printf("cert válido até: %s\n", cs.PeerCertificates[0].NotAfter.Format(time.DateOnly))
fmt.Printf("nomes no cert: %v %v\n",
cs.PeerCertificates[0].DNSNames, cs.PeerCertificates[0].IPAddresses)
// 2. cliente SEM confiar na CA do teste: a autenticidade falha
semCA := &http.Client{Timeout: 3 * time.Second}
_, err = semCA.Get(srv.URL)
fmt.Printf("\nsem a CA: %v\n", err)
// 3. a correção CORRETA: adicionar a CA, não desligar a verificação
pool := x509.NewCertPool()
pool.AddCert(srv.Certificate())
comCA := &http.Client{
Timeout: 3 * time.Second,
Transport: &http.Transport{TLSClientConfig: &tls.Config{RootCAs: pool, MinVersion: tls.VersionTLS12}},
}
r3, err := comCA.Get(srv.URL)
if err == nil {
r3.Body.Close()
fmt.Println("com a CA: ok, verificação ATIVA")
}
// 4. a correção ERRADA: mantém a cifra, joga fora a autenticidade
inseguro := &http.Client{
Timeout: 3 * time.Second,
Transport: &http.Transport{TLSClientConfig: &tls.Config{InsecureSkipVerify: true}},
}
r4, err := inseguro.Get(srv.URL)
if err == nil {
r4.Body.Close()
fmt.Println("InsecureSkipVerify: ok — e vulnerável a man-in-the-middle")
}
}
A diferença entre os itens 3 e 4 é o ponto da nota: os dois "funcionam", e só um deles é
seguro. O erro do item 2 (certificate signed by unknown authority) é um sintoma correto —
contorná-lo com InsecureSkipVerify é desligar o alarme em vez de apagar o fogo.
Relacionado
- 2. Ciclo de uma Requisição — o handshake medido dentro do ciclo
- 6. Headers HTTP — HSTS e as políticas que dependem de TLS
- 7. Sessão vs JWT — cookie
Securesó funciona sobre TLS - 2. Teste de Integração — semana 7,
httptest.NewTLSServer
Parte de Semana 10 - Rede e HTTP · 00 - MOC Fundamentos de Programação