Gerenciamento de sessão é a disciplina de criar, validar e destruir o estado server-side que vincula requisições HTTP a um único usuário. O HTTP em si não lembra de nada — cada requisição chega como uma estranha — então as aplicações fecham essa lacuna com uma sessão: um registro server-side mais um ID aleatório que o navegador apresenta a cada requisição. O insight de segurança do qual todo o resto decorre: esse ID equivale a uma credencial completa — quem o possui é o usuário, sem senha nenhuma — e por isso merece geração, transporte e destruição no mesmo padrão de uma senha.
Principais pontos
| Pergunta | Resposta |
|---|---|
| O mecanismo | Login → registro no servidor + ID aleatório num cookie → ID devolvido a cada requisição |
| O insight | O ID de sessão é uma credencial — ID sequestrado = conta tomada |
| O ciclo de vida | Criar → regenerar no login/mudança de privilégio → validar → expirar → destruir server-side |
| Os números | ≥64 bits de entropia de CSPRNG · 15–30 min de inatividade · horas no absoluto |
| O bug clássico | ”Logout” que apaga o cookie, mas deixa o registro vivo no servidor |
O ciclo de vida em cinco estágios
1 CRIAR no login: registro server-side + ID aleatório novo (≥64 bits, CSPRNG)
2 REGENERAR a CADA mudança de privilégio — login, elevação de papel, troca de
senha — emita um ID novo, aposente o antigo (mata a fixação)
3 VALIDAR toda requisição: o ID existe, não expirou, pertence a este usuário
4 EXPIRAR dois relógios, impostos pelo servidor: timeout de inatividade + absoluto
5 DESTRUIR logout = apague o registro do servidor PRIMEIRO, depois limpe o cookie
("logout" só de cookie deixa a sessão viva para um ladrão)
Sessões como objetos consultáveis, de primeira classe — o ciclo de vida com alças:
// JavaScript / Node.js — Back4app JS SDK
// Sessions are objects: queryable, per-device, revocable
const user = await Parse.User.logIn('ada', password); // Session object created
console.log(user.getSessionToken()); // r:… — the credential
// "Active devices" UI: each login is a Session row (ACL: owner-only)
const sessions = await new Parse.Query(Parse.Session).find();
// Logout = server-side destroy — the token dies NOW
await Parse.User.logOut(); // Flutter / Dart — Back4app Flutter SDK
// Sessions are objects: queryable, per-device, revocable
final user = ParseUser('ada', password, null);
await user.login(); // Session object created
print(user.sessionToken); // r:… — the credential
// "Active devices" UI: each login is a Session row (ACL: owner-only)
final sessions = await QueryBuilder(ParseSession.forQuery()).query();
// Logout = server-side destroy — the token dies NOW
await user.logout(); // iOS / Swift — Back4app Swift SDK
// Sessions are objects: queryable, per-device, revocable
let user = try await User.login(username: "ada", password: password)
print(user.sessionToken ?? "") // r:… — the credential
// "Active devices" UI: each login is a Session row (ACL: owner-only)
let sessions = try await ParseSession.query().find()
// Logout = server-side destroy — the token dies NOW
try await User.logout() // Android / Kotlin — Back4app Android SDK
// Sessions are objects: queryable, per-device, revocable
val user = ParseUser.logIn("ada", password) // Session object created
println(user.sessionToken) // r:… — the credential
// "Active devices" UI: each login is a Session row (ACL: owner-only)
val sessions = ParseQuery.getQuery(ParseSession::class.java).find()
// Logout = server-side destroy — the token dies NOW
ParseUser.logOut() Cookies de sessão: as flags, e o que cada uma bloqueia
O mapeamento que nenhuma página de ranking tabula — cada flag é a lápide de um ataque com nome:
| Flag | O que faz | Ataque que bloqueia |
|---|---|---|
Secure | O cookie só viaja por HTTPS | Sniffing de rede |
HttpOnly | Invisível para o JavaScript | Roubo de cookie via XSS |
SameSite=Lax/Strict | Retido em requisições cross-site | CSRF |
Prefixo __Host- | Tranca o cookie na origem, sem truques de subdomínio | Fixação via subdomínios |
| (sem Max-Age/Expires) | Morre com a sessão do navegador | Sessões velhas em máquinas compartilhadas |
Semântica conforme a RFC 6265, com os detalhes práticos no MDN. As cinco juntas são a linha de base, não a configuração endurecida.
Os ataques, cada um com sua defesa
Hijacking (sequestro de sessão) — roubar um ID válido (sniffing em HTTP puro, XSS, malware) e apresentá-lo; o servidor enxerga o usuário. Defesa: TLS em tudo, a tabela de flags acima, vidas curtas, monitoramento de viagens impossíveis. Fixação — a inversão que vale entender mecanicamente: o atacante dá à vítima um ID antes do login (link forjado, cookie plantado); a vítima se autentica; o ID que o atacante conhece agora é uma sessão logada. Defesa em um movimento: regenerar o ID na autenticação — o ID pré-login que o atacante conhece vira pó no instante em que privilégios se anexam, e servidores estritos rejeitam qualquer ID que eles não cunharam. Roubo via XSS — o script injetado lê o cookie; HttpOnly remove essa leitura, o que é contenção de dano enquanto o XSS em si é corrigido. CSRF — o navegador, prestativo, anexa cookies a requisições cross-site forjadas; SameSite mais tokens anti-CSRF fecham a porta.
Sessões vs. JWTs
| Sessões server-side | JWTs | |
|---|---|---|
| Onde o estado mora | No servidor | Dentro do token |
| Revogação | Instantânea — apague o registro | Espera o exp, ou estado de denylist |
| Custo por requisição | Um lookup no store | Verificação de assinatura |
| Escala entre serviços | Precisa de store compartilhado | Qualquer detentor da chave verifica |
O ponto crucial é a revogabilidade, e ela é uma decisão de arquitetura, não um checkbox de feature: sessões podem morrer no momento em que você mandar; tokens stateless não podem, e cada contorno reintroduz o estado que você tinha removido. O verbete de JWT defende o lado stateless; o assunto deste artigo é o que fazer o stateful bem feito exige.
Os números que tornam isso real
A cheat sheet da OWASP põe a entropia em ≥64 bits vindos de um CSPRNG — dezesseis caracteres hexadecimais aleatórios, o bastante para que forçar IDs na base da tentativa leve séculos em taxas de requisição realistas — sem nada significativo codificado no ID. Timeouts correm em dois relógios: inatividade (2–5 minutos para aplicações de alto valor, 15–30 para as típicas) e absoluto (poucas horas, encerrando até sessões ativas para que um ID roubado tenha um teto rígido). As diretrizes de identidade digital do NIST formalizam o mesmo desenho: no nível de garantia 2, reautenticação após 30 minutos de inatividade e pelo menos a cada 12 horas, aconteça o que acontecer.
Escalando sessões: sticky routing vs. store compartilhado
| Sticky sessions | Store compartilhado (estilo Redis) | |
|---|---|---|
| Como | O load balancer prende usuário → servidor | Todos os servidores leem um único session store |
| O servidor morre | As sessões dele morrem junto | Os usuários nem percebem |
| Escala | Carga desigual, drain a cada deploy | Qualquer servidor, qualquer requisição |
| Veredito | Um remendo de roteamento | A arquitetura |
Memória de sessão in-process funciona em exatamente um servidor. Sticky routing estica isso — e transforma cada servidor numa pequena queda à espera de deslogar usuários. A resposta padrão é um store compartilhado em memória (Redis, Memcached) ou o banco de dados: o estado de sessão vira infraestrutura, e a camada web fica stateless — a mesma propriedade que torna arquiteturas JWT atraentes, obtida mantendo a revogação instantânea.
Sessões como funcionalidade de produto
A camada de segurança dobra como UX quando as sessões são visíveis: uma tela de “sessões ativas” listando cada dispositivo com hora e local de login, um botão de “sair de todos os dispositivos” e a revogação automática de todas as sessões na troca de senha ou em suspeita de comprometimento. Usuários leem isso como segurança; engenheiros deveriam ler como um requisito de arquitetura — sessões precisam ser objetos consultáveis com dono, não blobs opacos num cache, que é exatamente onde session stores construídos só para lookup ficam devendo.
Casos de uso comuns
- Estado de login em apps web — o caso canônico: sessões carregadas em cookie com o conjunto completo de flags.
- Carrinhos e fluxos de e-commerce — estado multi-etapa que precisa sobreviver à navegação, mas não à semana.
- Bancos e apps de alto valor — timeouts de inatividade curtos, tetos absolutos, MFA de step-up no meio da sessão para ações sensíveis.
- Gestão de dispositivos — sessões por dispositivo alimentando o “deslogar meu celular roubado”.
- Painéis admin — onde a regeneração na elevação de privilégio e timeouts agressivos pagam o próprio salário.
Você deveria usar sessões ou tokens? Matriz de decisão
| Situação | Escolha |
|---|---|
| App web de domínio único | Sessões — mais simples e revogáveis na hora |
| Bloqueio instantâneo é inegociável | Sessões (ou tokens + o estado que você jurou evitar) |
| Muitos serviços verificam de forma independente | JWTs |
| App mobile num BaaS | Os session tokens da plataforma — revogáveis, prontos |
| Escala horizontal com sessões | Store compartilhado, não sticky routing |
| ”Dispositivos ativos” como feature | Sessões como objetos consultáveis |
Limitações e trade-offs
- O store é infraestrutura de caminho quente. Toda requisição o lê; a latência dele é a sua latência, a queda dele é o logout de todo mundo.
- Cross-domain é desajeitado. Cookies se prendem a origens; APIs consumidas por muitas partes empurram para tokens — o híbrido honesto costuma ser sessões para o app, tokens para a API.
- Timeouts taxam os usuários. Cada logout por inatividade é atrito; os números acima são decisões de risco, não constantes, e merecem aval de produto.
- Revogação precisa de encanamento que o usuário veja. Revogação instantânea só vale alguma coisa se trocas de senha e o “sair de todos os dispositivos” realmente a dispararem — ligue os eventos, não só a capacidade.
- Sessões herdam a política dos cookies. As mudanças nos cookies de terceiros e o trabalho de privacidade dos navegadores seguem mexendo no terreno; cookies de sessão first-party continuam sendo chão firme, mas fique nele de propósito.
Gerenciamento de sessão no Back4app
O Back4app é uma plataforma open-source de Backend as a Service (BaaS) que combina banco de dados gerenciado, APIs REST e GraphQL geradas automaticamente, autenticação, armazenamento de arquivos e funções serverless com Cloud Code. Aqui as sessões são os “objetos consultáveis” que este artigo não para de pedir — literalmente: cada login cria um objeto Session com o token de sessão revogável, seu usuário, o contexto de criação e a expiração, protegido por ACL para que cada usuário veja apenas as próprias sessões. As abas de código mostram as consequências: uma tela de “dispositivos ativos” é uma query; o logout é um destroy server-side que mata o token em todo lugar imediatamente; a troca de senha pode revogar todas as sessões; e os triggers de Cloud Code são o gancho para regras de step-up e trilhas de auditoria. Ciclo de vida, revogação e as funcionalidades de produto se apoiam na mesma primitiva — sessões como dados — com a maquinaria de entropia, armazenamento e validação por conta da plataforma.
Perguntas frequentes
Como funcionam as sessões?
No login, o servidor cria um registro de sessão e emite um ID aleatório num cookie; o navegador devolve esse ID a cada requisição, o servidor busca o estado associado, e o registro é destruído no logout ou na expiração. O ID é a credencial inteira — quem o apresenta é tratado como o usuário.
Qual é a diferença entre autenticação por sessão e por token (JWT)?
Onde o estado mora. Sessões o mantêm no servidor — um lookup por requisição, revogável na hora. JWTs o carregam dentro do próprio token — sem lookup, verificável em qualquer lugar, mas válido até expirar, aconteça o que acontecer. Sessões servem apps de domínio único que precisam de controle; tokens servem APIs e microsserviços que precisam de portabilidade.
O que é session hijacking e como prevenir?
É roubar um ID de sessão válido — via sniffing, XSS ou malware — e apresentá-lo para se passar pelo usuário sem nunca saber a senha. Defesas: HTTPS em tudo, flags HttpOnly e Secure no cookie, IDs de alta entropia, vidas curtas, regeneração a cada mudança de privilégio e monitoramento de anomalias.
O que é session fixation?
O atacante planta um ID de sessão que ele já conhece — via link forjado ou cookie de subdomínio — e espera a vítima fazer login com ele; o ID conhecido vira uma sessão autenticada. A correção completa: emitir um ID novo em folha a cada evento de autenticação e rejeitar IDs que o servidor nunca gerou.
O que fazem as flags do cookie de sessão?
Cada uma bloqueia uma rota de roubo: Secure envia o cookie somente por HTTPS (derrota o sniffing); HttpOnly o esconde do JavaScript (derrota o roubo de cookie via XSS); SameSite o retém em requisições cross-site (derrota o CSRF); e o prefixo __Host- no nome tranca o cookie em uma única origem.
Qual é o timeout de sessão ideal?
Dois relógios, ambos impostos pelo servidor: um timeout de inatividade — minutos para apps de alto valor, 15–30 para os típicos — e um timeout absoluto de poucas horas, independentemente de atividade. As diretrizes federais de identidade digital, no segundo nível de garantia, especificam 30 minutos de inatividade e reautenticação pelo menos a cada 12 horas.
Como o logout deveria funcionar?
Server-side primeiro: destrua o registro de sessão para que o ID morra em todo lugar, e só então limpe o cookie. A falha clássica é o inverso — apagar apenas o cookie deixa a sessão viva para qualquer um que tenha capturado o ID, transformando o "logout" numa animação de interface.
O "manter conectado" (remember me) é seguro?
É uma troca deliberada de segurança por conveniência. Feita com responsabilidade: um token separado de vida longa, de uso único e rotacionado a cada visita, guardado num cookie endurecido, revogável server-side, invalidado na troca de senha — e nunca um substituto para reautenticação antes de ações sensíveis.