Quando escreves https://app.randomt.pt/api/accounts e
carregas Enter, o browser executa silenciosamente uma sequência de operações
de rede que envolve pelo menos quatro protocolos distintos antes de um único
byte da tua aplicação Spring Boot ser lido. Perceber esta sequência é perceber
onde vivem as vulnerabilidades, onde os cookies são transmitidos, e porque
o HTTPS não é opcional em segurança web.
A internet é construída em camadas — cada camada resolve um problema específico e oferece um serviço à camada acima. Não precisas de perceber Ethernet ou IP para programar uma API, mas perceber onde o HTTP se encaixa na pilha explica porquê certas garantias de segurança existem (ou não existem) em cada nível.
| Camada | Protocolo | Resolve | Relevante para |
|---|---|---|---|
| Aplicação | HTTP / HTTPS | Formato dos pedidos e respostas web | Todo o desenvolvimento web |
| Segurança | TLS | Encriptação e autenticação do servidor | Cookies Secure, JWT em trânsito |
| Transporte | TCP | Entrega ordenada e fiável de bytes | Garante que o pedido chega completo e em ordem |
| Internet | IP | Endereçamento e encaminhamento de pacotes | Identificar servidor de destino |
| Tradução de nomes | DNS | Converter nome em endereço IP | Primeiro passo de qualquer pedido |
Os computadores comunicam por endereços IP numéricos (93.184.216.34),
não por nomes. O DNS (Domain Name System) é o sistema distribuído que traduz
app.randomt.pt no endereço IP do servidor. É o primeiro passo
de qualquer pedido web — e um vector de ataque frequentemente ignorado.
// O que acontece quando o browser precisa de resolver app.randomt.pt:
// 1. Cache local — o sistema operativo tem uma cache DNS
// Se já resolveste este nome recentemente, usa o resultado em cache.
// TTL (Time To Live) define quanto tempo o resultado é válido.
// 2. Resolver recursivo — normalmente o servidor DNS do teu ISP ou 1.1.1.1/8.8.8.8
// O teu sistema operativo pergunta ao resolver: "qual é o IP de app.randomt.pt?"
// 3. Hierarquia DNS — se o resolver não tem em cache:
// Root nameserver → "quem gere .pt?"
// TLD nameserver → "quem gere randomt.pt?"
// Authoritative NS → "app.randomt.pt é 93.184.216.34"
// 4. Resposta — o resolver devolve o IP ao browser e guarda em cache
// Exemplo de resolução (simplificada):
app.randomt.pt
↓ pergunta ao resolver
↓ resolver pergunta ao root NS: quem gere .pt?
↓ root NS responde: nameserver do .pt
↓ resolver pergunta ao NS do .pt: quem gere randomt.pt?
↓ NS do .pt responde: ns1.randomt.pt
↓ resolver pergunta a ns1.randomt.pt: qual o IP de app.randomt.pt?
↓ ns1.randomt.pt responde: 93.184.216.34, TTL=300
↓ resolver devolve 93.184.216.34 ao browser e guarda em cache por 300 segundos
app.randomt.pt. DNS over HTTPS (DoH) e DNS over TLS (DoT)
resolvem isto, mas não são universais. Para segurança web, o mais
importante é que o próprio conteúdo viaja encriptado via TLS — mesmo que
o nome do servidor seja visível na consulta DNS.
Com o IP do servidor resolvido, o browser precisa de estabelecer uma ligação. O TCP (Transmission Control Protocol) garante que os dados chegam completos, em ordem, e sem corrupção. Faz-o através de um three-way handshake antes de qualquer dado da aplicação ser transmitido.
// TCP Three-Way Handshake — estabelecer a ligação
Browser (cliente) Servidor (93.184.216.34:443)
| |
|-------- SYN (quero ligar) ----------->| // "posso ligar?"
| |
|<------- SYN-ACK (aceito, confirma) ----| // "podes, confirma"
| |
|-------- ACK (confirmado) ------------->| // "confirmado"
| |
// ligação TCP estabelecida — agora TLS negocia por cima desta ligação
// Portas TCP relevantes:
// 80 — HTTP (texto claro — nunca usar em produção)
// 443 — HTTPS (HTTP sobre TLS)
TLS (Transport Layer Security) é o protocolo que transforma HTTP em HTTPS. Resolve dois problemas distintos: confidencialidade (ninguém entre o browser e o servidor consegue ler o conteúdo) e autenticação do servidor (o browser verifica que está a falar com o servidor legítimo, não com um impostor).
// TLS Handshake (versão simplificada — TLS 1.3)
Browser Servidor
| |
|-- ClientHello ----------------------->|
| (versões TLS suportadas, |
| algoritmos de cifra suportados, |
| número aleatório) |
| |
|<-- ServerHello + Certificado ---------|
| (algoritmo escolhido, |
| número aleatório do servidor, |
| certificado TLS — chave pública) |
| |
| [browser verifica o certificado] |
| - está assinado por uma CA confiável?
| - o nome coincide com app.randomt.pt?
| - não expirou? |
| |
|-- Finished (chave de sessão) -------->|
| (derivada dos números aleatórios |
| trocados + chave pública servidor) |
| |
// daqui em diante: tudo encriptado com a chave de sessão simétrica
// O que o TLS garante:
// ✅ Confidencialidade — intermediários vêem bytes encriptados, não conteúdo
// ✅ Integridade — qualquer alteração dos dados em trânsito é detectada
// ✅ Autenticação — o servidor prova que é quem diz ser via certificado
// ❌ Anonimato — o IP do servidor e o nome (SNI) ainda são visíveis
Com a ligação TCP estabelecida e o canal TLS negociado, o browser finalmente envia o pedido HTTP. Neste ponto, o conteúdo do pedido — incluindo headers, cookies, e body — viaja encriptado pelo TLS. Apenas o browser e o servidor conseguem ler o conteúdo.
// O pedido HTTP que o browser envia (dentro do canal TLS encriptado):
GET /api/accounts HTTP/1.1
Host: app.randomt.pt
Accept: application/json
Cookie: access_token=eyJhbGciOiJIUzI1NiJ9... ← o JWT viaja aqui, encriptado pelo TLS
Connection: keep-alive
// O servidor processa o pedido e responde:
HTTP/1.1 200 OK
Content-Type: application/json
Content-Length: 248
[{"id":1,"ownerName":"Ana Silva","balance":1500.0,"type":"SAVINGS"}]
// Tudo junto — digitar https://app.randomt.pt/api/accounts e carregar Enter:
1. DNS
browser → resolver → hierarquia DNS → IP: 93.184.216.34
duração: ~1-50ms (se não está em cache)
2. TCP Handshake
browser ↔ 93.184.216.34:443 — SYN → SYN-ACK → ACK
duração: 1 RTT (round-trip time)
3. TLS Handshake
browser ↔ servidor — negociação de algoritmos, troca de certificado,
derivação de chave de sessão simétrica
duração: 1 RTT (TLS 1.3) ou 2 RTT (TLS 1.2)
4. HTTP Request (dentro do canal TLS)
GET /api/accounts HTTP/1.1
Cookie: access_token=... ← JWT em HttpOnly cookie, viaja encriptado
duração: 1 RTT + tempo de processamento do servidor
5. HTTP Response (dentro do canal TLS)
200 OK + JSON body
// Total mínimo: ~3-4 RTT para a primeira ligação
// RTT Lisboa→servidor em Frankfurt: ~20ms → mínimo ~60-80ms para a primeira resposta
// Ligações subsequentes reutilizam a ligação TCP + sessão TLS — muito mais rápidas
Sem TLS, todo o conteúdo HTTP viaja em texto claro. Qualquer nó intermediário na rede — router de café, ISP, servidor de proxy corporativo — pode ler e modificar o conteúdo dos pedidos e respostas.
// Sem HTTPS — o que um atacante na mesma rede consegue fazer:
// 1. Ler cookies em trânsito
// Cookie: access_token=eyJhbGciOiJIUzI1NiJ9...
// → o atacante obtém o JWT e faz-se passar pelo utilizador
// 2. Modificar respostas (man-in-the-middle)
// O servidor responde com {"balance": 1500}
// O atacante modifica para {"balance": 0} antes de chegar ao browser
// 3. Injectar conteúdo
// O atacante adiciona um script malicioso à resposta HTML
// Com HTTPS — o que o atacante vê:
// ✅ O nome do servidor (via SNI no TLS handshake — ainda visível)
// ✅ O IP do servidor
// ❌ Headers HTTP (incluindo cookies) — encriptados
// ❌ URL path e query string — encriptados
// ❌ Body do pedido e resposta — encriptados
// Por isso o flag Secure no cookie é crítico:
// Set-Cookie: access_token=...; HttpOnly; Secure; SameSite=Strict
// ^^^^^^
// o browser RECUSA-SE a enviar este cookie sobre HTTP
// mesmo que o utilizador aceda via http:// por engano
Secure protege cookies em trânsito, mas o utilizador
ainda pode aceder a http://app.randomt.pt na primeira visita
— antes de ser redireccionado para HTTPS. O HSTS resolve isto: o servidor
diz ao browser "nunca acedas a este domínio via HTTP, mesmo se o utilizador
escrever http://". Em Spring Boot:
http.headers(h -> h.httpStrictTransportSecurity(hsts -> hsts.includeSubDomains(true).maxAgeInSeconds(31536000)))
| Versão | Transporte | Multiplexing | Headers | Uso actual |
|---|---|---|---|---|
| HTTP/1.1 | TCP | ❌ Um pedido por ligação (serializado) | Texto claro | Ainda prevalente, suportado por tudo |
| HTTP/2 | TCP + TLS | ✅ Múltiplos pedidos em paralelo (streams) | Comprimidos (HPACK) | Standard actual para APIs e browsers modernos |
| HTTP/3 | QUIC (UDP) | ✅ Multiplexing sem head-of-line blocking | Comprimidos (QPACK) | Crescente — CDNs e grandes plataformas |
server.http2.enabled=true).
Os conceitos de pedido, resposta, headers, cookies, e status codes são
idênticos em todas as versões.
Secure no cookie impede o browser de o enviar sobre HTTP — complemento obrigatório ao HttpOnly.