Uma análise arquitetural das três camadas complementares que constituem uma aplicação web verdadeiramente segura: identidade via JWT stateless, transporte via Cookie HttpOnly, e autorização final ao nível da query SQL. Cada camada resolve um problema distinto — nenhuma substitui as outras.
A arquitetura que este repositório defende assenta em três garantias complementares. Cada uma é necessária; nenhuma é suficiente isoladamente.
O servidor não guarda sessões em RAM. A identidade e os privilégios viajam num token assinado matematicamente, verificável por qualquer instância horizontal sem consultar um store central.
O JWT nunca é exposto ao JavaScript. Viaja dentro de um Cookie com
HttpOnly (bloqueia leitura por JS) e Secure
(exige HTTPS). O browser anexa-o automaticamente a cada pedido.
Autenticação prova quem é o utilizador, não o que lhe pertence. Todas as
queries filtram por resource_id e
owner_id para neutralizar IDOR na raiz.
Insecure Direct Object Reference (IDOR) ocorre quando um sistema confia num identificador fornecido pelo cliente sem verificar se o recurso pertence ao utilizador autenticado:
-- Pedido: GET /api/accounts/5
-- Utilizador autenticado: user 99. O servidor não verifica a posse.
SELECT * FROM accounts WHERE id = 5;
-- Atacante muda 5 → 6 na URL: lê dados de outro utilizador sem qualquer erro.
O backend extrai o user id diretamente do JWT no cookie seguro e projeta-o como
condição obrigatória na query. O cliente nunca controla o owner_id:
-- Pedido: GET /api/accounts/6
-- JWT no cookie → user_id = 99 (extraído pelo servidor, nunca pelo cliente)
SELECT * FROM accounts
WHERE id = 6
AND owner_id = 99;
-- Conta 6 não pertence ao user 99 → 0 resultados → 404 Not Found
Credenciais validadas. Servidor emite JWT via
Set-Cookie: access_token=...; HttpOnly; Secure; SameSite=Lax.
O token nunca toca no JavaScript.
Browser anexa o cookie automaticamente. JavaScript não tem acesso ao
valor do token — não existe em localStorage nem em variáveis JS.
Servidor extrai o cookie, valida a assinatura criptográfica e extrai o
sub (user id). Qualquer falha → 401 Unauthorized imediato.
O user id extraído do JWT é injetado como owner_id na query.
A autorização é estrutural — não uma verificação opcional após a leitura.
Resultados encontrados → dados devolvidos. Zero resultados → 404 Not Found, sem revelar a existência do recurso.
| Camada | Pergunta que responde | O que protege | O que não resolve sozinha |
|---|---|---|---|
| JWT | Quem é este utilizador? | Identidade verificável, escalabilidade horizontal | Exposição browser, CSRF, IDOR |
| Cookie HttpOnly | Como o token viaja em segurança? | Mitigação de XSS, transporte forçado por HTTPS | Autorização ao recurso, CSRF completo |
| Query owner_id | Este objeto pertence a quem autenticou? | Posse de recursos, anti-enumeração | Autenticação de pedidos |