Session fixation é quando a vítima loga com um ID que o invasor preparou. Veja como funciona e como evitá-lo de forma confiável (sem passos de ataque).
Por que funciona
A causa é um design em que o ID de sessão não muda ao longo do login. Se ele não muda, um ID que o invasor conhecia antes do login ainda funciona como "autenticado" depois do login.
Pode se combinar com CSRF ou XSS, mas a essência da fixation em si é uma única coisa: o ID não foi regenerado no login.
O guia "How to Secure Your Website" da IPA (Agência de Promoção de Tecnologia da Informação do Japão) trata isso como uma forma de gerenciamento de sessão inadequado e diz que todo site com função de login precisa ficar atento. A correção fundamental indicada é iniciar uma nova sessão após o login bem-sucedido.
Fixation vs. sequestro de sessão vs. CSRF
Esses três são fáceis de confundir. Todos abusam de um estado logado, mas diferem no que o invasor tem e em qual defesa funciona.
| Item | Session fixation | Sequestro de sessão | CSRF |
|---|---|---|---|
| O que o invasor tem | Um ID que ele preparou (conhecido desde o início) | Um ID já emitido e roubado | Nenhum ID |
| O que acontece com a vítima | Ela loga com o ID plantado | O ID emitido dela é roubado | Ela é levada a enviar uma requisição não intencional |
| Defesa principal | Regenerar o ID no login | HttpOnly/Secure, prevenção de XSS, vidas curtas | Tokens CSRF, SameSite |
A fixation é a que um único passo, regenerar o ID no login, corrige na raiz.
Defesa: regenere o ID no login
Regenere o ID de sessão no login bem-sucedido (o mais importante)
Não aceite IDs de sessão pela URL
Defina as flags de cookie
HttpOnly (o JS não pode ler), Secure (só HTTPS) e SameSite (restringe o envio entre sites). Enfraquece em conjunto os caminhos de sequestro relacionados.Expire sessões com bom senso
O OWASP Session Management Cheat Sheet recomenda regenerar o ID a cada mudança de privilégio e usar um mecanismo "estrito", que só aceita IDs gerados pelo próprio servidor. Um mecanismo "permissivo", que adota um ID desconhecido trazido de fora, deixa espaço para que um ID escolhido pelo invasor seja aceito.
O que frameworks comuns fazem por padrão
A maioria dos frameworks regenera o ID automaticamente se você usa o login padrão deles. O risco aparece quando você escreve o login por conta própria ou desliga a proteção padrão.
| Ambiente | Comportamento padrão | O que verificar se você escreve por conta própria |
|---|---|---|
| PHP (sessões puras) | Não regenera sozinho; session.use_strict_mode tem padrão 0 | Chamar session_regenerate_id(true) no login bem-sucedido; definir use_strict_mode como 1 |
| Laravel | Regenerado automaticamente na autenticação quando você usa um starter kit ou o Fortify | Se escrever o login à mão, chamar $request->session()->regenerate() |
| Spring Security | Ativado por padrão (changeSessionId no Servlet 3.1+) | Garantir que ninguém definiu sessionFixation().none() |
No PHP, as configurações que passam IDs de sessão em URLs (ativar session.use_trans_sid, desativar session.use_only_cookies) foram descontinuadas no PHP 8.4. Se você carrega um arquivo de configuração antigo, revise-as.
Como verificar o seu próprio site
Em um site que você administra, verifique estas quatro coisas. As ferramentas de desenvolvedor bastam.
- Nas ferramentas de desenvolvedor, em "Application" (no Firefox, "Armazenamento"), anote o valor do cookie de sessão e olhe de novo depois de logar. Se não mudou, o ID não é regenerado no login
- Confira que a página de login e as URLs após o login não carregam um ID de sessão como
PHPSESSID=ou;jsessionid= - No mesmo painel, confira que o cookie de sessão tem
HttpOnly,SecureeSameSite - Depois de sair, coloque de volta o valor antigo do cookie e recarregue; confirme que você não volta a estar logado
Os atributos de cookie também são cobertos pela auditoria de segurança do site, que verifica sites cuja propriedade você confirmou. Colocar a verificação 1 num teste automatizado sempre que mexer no fluxo de login faz você perceber na hora se a regeneração sumir.
A visão deste site: não desabilite o 'regenerate' do framework
A session fixation é quase totalmente evitada por um único passo: regenerar o ID no login, e não por código personalizado elaborado. A chave é não desabilitar acidentalmente nem esquecer de chamar o mecanismo que seu framework já fornece. Usar os padrões seguros de uma implementação comprovada supera fazer seu próprio gerenciamento de sessão. Neste site mantemos "não construa autenticação/manuseio de chaves você mesmo; não desabilite os padrões seguros". Como no IDOR, a autenticação/autorização deve ser imposta por um mecanismo em cada requisição.
Fontes (primárias)
- IPA, "How to Secure Your Website", 1.4 Gerenciamento de sessão inadequado — ipa.go.jp (em japonês; iniciar nova sessão após o login; não colocar IDs em URLs)
- OWASP Session Management Cheat Sheet — cheatsheetseries.owasp.org (em inglês; regeneração na mudança de privilégio, mecanismo estrito, atributos de cookie)
- MITRE CWE-384: Session Fixation — cwe.mitre.org (em inglês)
- PHP Manual, "Runtime Configuration" (sessões) — php.net (em inglês; padrões como
use_strict_mode; descontinuações do 8.4) - Documentação do Laravel, "HTTP Session" — laravel.com / Spring Security, "Authentication Persistence and Session Management" — docs.spring.io (em inglês)
Leia a seguir
- Glossário: O que é CSRF · O que é XSS · O que é IDOR · O que é um JWT
- Fundamentos: Autenticação vs. autorização