Aprenda / Segurança web

FundamentosAula 2 de 1618 min0% da trilha

Autenticação por sessão e cookie: o mecanismo clássico

'O navegador manda o cookie sozinho' esconde um mecanismo inteiro — vale entender o que acontece entre o login e a segunda requisição.

HTTP não tem memória — cada requisição chega no servidor sem nenhuma lembrança da anterior. Isso significa que, sem nenhum mecanismo extra, todo clique num site com login precisaria mandar email e senha de novo. O jeito mais antigo (e ainda hoje o mais comum pra aplicação web tradicional) de resolver isso é sessão com cookie — vale entender o mecanismo completo, não só decorar que "o navegador manda o cookie sozinho".

O fluxo completo, passo a passo

Navegador
Servidor
Banco / store de sessão

Clique em “Reproduzir fluxo” para ver a requisição passo a passo.

O passo 5 é o detalhe que costuma passar despercebido: o navegador reenviar o cookie automaticamente não é "mágica de framework" — é um comportamento do protocolo HTTP em si, implementado em todo navegador. Qualquer requisição (fetch, formulário, até uma tag <img>) pro mesmo domínio que emitiu o cookie carrega ele junto, automaticamente. Isso é exatamente o que torna CSRF possível — assunto da lição 8 — mas por ora fica o ponto: ninguém no seu código está lendo localStorage e anexando header a cada chamada. É o navegador fazendo isso sozinho.

O que um cookie fisicamente é

Um cookie não é um objeto complexo — é só um par chave=valor, mais um punhado de atributos que controlam quando e pra onde ele é enviado. O header que o servidor manda pra criar um se parece com isto:

header de resposta do login
Set-Cookie: sessao=a1b2c3d4e5; Path=/; Max-Age=86400; HttpOnly

sessao=a1b2c3d4e5 é o par chave/valor propriamente dito — nesse caso, o valor é só um identificador aleatório, não a sessão inteira. Path=/ diz em quais rotas do domínio o cookie se aplica; Max-Age=86400 diz que ele expira em 24h; HttpOnly é um dos atributos de segurança aprofundados na próxima lição. O navegador guarda isso associado ao domínio que o emitiu e decide sozinho, a cada requisição, se aquele cookie se aplica ali.

Onde a sessão de verdade mora — e por que o cookie é só um ponteiro

Um erro comum de quem está aprendendo é achar que o cookie é a sessão. Não é — o cookie carrega só um ID. Os dados de verdade (qual usuário está logado, desde quando, talvez preferências temporárias) ficam guardados do lado do servidor, numa tabela de banco de dados ou num store rápido como Redis, indexados por esse mesmo ID:

tabela de sessões, simplificada
CREATE TABLE sessoes (
  id            VARCHAR(64) PRIMARY KEY,  -- o mesmo valor que vai no cookie
  usuario_id    INTEGER NOT NULL REFERENCES usuarios(id),
  criado_em     TIMESTAMP NOT NULL,
  expira_em     TIMESTAMP NOT NULL
);

Isso explica por que "derrubar a sessão de um usuário" é possível mesmo sem acesso ao navegador dele: basta apagar (ou marcar como inválida) a linha correspondente nessa tabela. Na próxima requisição, o servidor busca pelo ID recebido, não encontra sessão válida, e trata como se o usuário nunca tivesse feito login — mesmo que o cookie continue fisicamente guardado no navegador dele. Esse controle central é o principal trunfo de sessão por cookie sobre JWT, que a lição 5 mostra ser bem mais difícil de revogar.

Logout, na prática

"Fazer logout" é, do lado do servidor, simplesmente apagar (ou marcar como expirado) o registro daquele ID de sessão. O servidor também costuma mandar um Set-Cookie de resposta pedindo pro navegador esquecer o cookie (Max-Age=0), mas a parte que realmente importa pra segurança é a exclusão do lado do servidor — mesmo que alguém copie o valor do cookie antes do logout, ele para de funcionar assim que a sessão correspondente deixa de existir no banco.

Exercício

Um usuário faz login em dois navegadores diferentes (celular e notebook) com a mesma conta. Ele clica "sair de todos os dispositivos" no notebook. Descreva, em termos da tabela sessoes do exemplo acima, o que essa ação precisa fazer pra realmente derrubar a sessão do celular também.

Quiz rápido

O que o cookie de sessão (Set-Cookie: sessao=abc123) realmente carrega?
Por que o navegador consegue reenviar o cookie de sessão automaticamente em toda requisição seguinte, sem o desenvolvedor escrever nada pra isso?