Home > Blog > Desenvolvimento Web
Desenvolvimento Web
JavaScript
Programação

Sessões Seguras no Node.js

Atualizado em: 29 de agosto de 2026

Rack de servidores processando fluxos de dados no Node.js

Implementar Sessões Seguras no Node.js permite manter o usuário autenticado entre requisições sem expor credenciais em cada chamada. O navegador recebe um identificador aleatório em cookie, enquanto o servidor mantém o estado da sessão em um armazenamento controlado.

Uma sessão insegura pode sofrer fixation, roubo por XSS, uso via CSRF, duração excessiva ou revogação incompleta. A proteção depende de IDs criptográficos, cookies HttpOnly e Secure, rotação após login, expiração, armazenamento compartilhado, revogação e auditoria.

Neste guia, você aprenderá a criar IDs, configurar cookies, usar Redis ou PostgreSQL, impedir fixation, proteger CSRF, renovar sessões, encerrar dispositivos, aplicar step-up e testar o fluxo.

O que é uma sessão?

Uma sessão associa um identificador apresentado pelo cliente a um registro no servidor. A OWASP Session Management Cheat Sheet reúne as principais recomendações. O RFC 6265 sobre cookies HTTP descreve o mecanismo usado pelo navegador.

Para sessões baseadas em tokens, consulte Refresh Tokens no Node.js. Para autenticação forte, veja Passkeys no Node.js e TOTP no Node.js.

ID de sessão

const sessionId = randomBytes(32)
  .toString('base64url');

O valor precisa ser imprevisível, longo e gerado por CSPRNG. Não inclua user ID, horário ou dados pessoais.

Armazenando hash

const sessionHash = createHash('sha256')
  .update(sessionId)
  .digest('hex');

O banco pode armazenar apenas o hash. Se a tabela vazar, os IDs ativos não aparecem em texto claro.

Tabela de sessões

CREATE TABLE user_sessions (
  id UUID PRIMARY KEY,
  session_hash TEXT NOT NULL UNIQUE,
  user_id UUID,
  status TEXT NOT NULL,
  created_at TIMESTAMPTZ NOT NULL,
  authenticated_at TIMESTAMPTZ,
  last_seen_at TIMESTAMPTZ NOT NULL,
  idle_expires_at TIMESTAMPTZ NOT NULL,
  absolute_expires_at TIMESTAMPTZ NOT NULL,
  revoked_at TIMESTAMPTZ,
  mfa_verified_at TIMESTAMPTZ,
  auth_methods TEXT[],
  user_agent TEXT,
  ip_prefix TEXT
);

Sessão anônima

Uma sessão pode existir antes do login para CSRF, carrinho ou challenge. Após autenticar, não transforme o mesmo ID em sessão privilegiada.

Session fixation

Fixation ocorre quando o atacante conhece ou define o ID antes do login e espera que ele ganhe privilégios depois.

Rotação após login

await revokeSession(preAuthSessionId);
const authenticatedSession = await createSession({
  userId,
  authenticatedAt: new Date()
});

Emita um novo cookie e invalide o identificador anterior.

Rotação após step-up

Ao concluir MFA ou passkey para uma ação sensível, rotacione novamente ou atualize o registro de forma atômica.

Set-Cookie: __Host-session=...;
  Path=/;
  HttpOnly;
  Secure;
  SameSite=Lax

O prefixo __Host- exige Secure, Path=/ e ausência de Domain em navegadores compatíveis.

HttpOnly

Impede que JavaScript leia o cookie. Isso reduz roubo direto por XSS, mas um script malicioso ainda pode realizar ações na sessão.

Secure

O cookie só deve ser enviado por HTTPS. Redirecionar HTTP não substitui o atributo.

SameSite

  • Strict: maior proteção, pode afetar links externos.
  • Lax: opção comum para aplicações web.
  • None: necessário em alguns fluxos cross-site e exige Secure.

Domain

Evite compartilhar cookies com todos os subdomínios. Um subdomínio comprometido pode afetar a sessão.

Path

Para uma sessão usada em toda a aplicação, use /. Não dependa de Path como barreira forte entre aplicações da mesma origem.

Max-Age e Expires

Cookies persistentes sobrevivem ao fechamento do navegador. Para sessões sensíveis, avalie cookie sem persistência e expiração no servidor.

Estado no servidor é a fonte

Mesmo que o cookie ainda exista, uma sessão revogada ou expirada deve ser rejeitada pelo backend.

Expiração por inatividade

Atualize o prazo quando houver atividade relevante:

idle_expires_at = now() + interval '30 minutes'

Expiração absoluta

Uma sessão não deve durar para sempre com atividade contínua:

absolute_expires_at = created_at + interval '30 days'

Atualização de last_seen

Gravar em toda requisição aumenta carga. Atualize apenas quando a última gravação ultrapassar uma janela, como cinco minutos.

Sliding expiration

A expiração por inatividade pode deslizar, mas nunca ultrapassar o limite absoluto.

Armazenamento em memória

Um Map local funciona apenas em desenvolvimento. Reinícios apagam sessões e várias réplicas não compartilham estado.

Redis

Redis oferece TTL e acesso rápido:

SET session:{hash} {json} EX 1800

Configure autenticação, TLS, limites e política de persistência conforme o risco.

PostgreSQL

PostgreSQL facilita auditoria, transações e consultas de sessões por usuário. Limpeza e índices precisam ser planejados.

Qual armazenamento escolher?

  • Redis: baixa latência e expiração nativa.
  • PostgreSQL: consistência, consultas e menor número de componentes.

Ambos podem funcionar quando a implementação é segura.

Store de sessão do framework

Bibliotecas como express-session exigem um store de produção. O MemoryStore não é adequado para múltiplas instâncias.

Secret de assinatura

Alguns frameworks assinam o cookie para detectar alteração. Use segredo criptográfico, rotação e armazenamento seguro.

Assinatura não cifra

Um cookie assinado continua legível. Não coloque dados sensíveis dentro dele.

Manter apenas um identificador reduz tamanho e permite revogação central.

Sessões stateless

Um cookie contendo todo o estado assinado elimina lookup, mas dificulta revogação e aumenta exposição. Para privilégios e sessões longas, estado no servidor costuma ser mais controlável.

CSRF

Cookies são enviados automaticamente pelo navegador. Operações de mudança precisam de proteção CSRF.

Token CSRF

Gere um valor aleatório associado à sessão e exija em header ou campo:

X-CSRF-Token: ...

Synchronizer token

O servidor armazena o token na sessão e compara com o valor enviado. Use comparação apropriada e nunca aceite apenas o cookie automático.

Outra estratégia envia um cookie separado e um header. O valor precisa ser vinculado à sessão ou assinado para evitar substituição.

SameSite não é suficiente em todos os casos

Fluxos cross-site, navegadores antigos e ataques dentro da mesma origem exigem proteção adicional.

Métodos seguros

GET, HEAD e OPTIONS não devem modificar estado. Isso reduz exposição a navegação cross-site.

XSS

HttpOnly protege o valor, mas XSS pode executar requisições. Use CSP, escaping e dependências atualizadas.

Consulte Helmet e CSP no Node.js.

Regeneração periódica

Rotacionar o ID em eventos importantes reduz a utilidade de identificadores antigos. Não rotacione em toda requisição, pois isso cria concorrência e perda de estado.

Concorrência entre abas

Duas abas podem fazer requests durante uma rotação. Mantenha um período curto em que o ID anterior aponta para o sucessor, sem permitir uso prolongado.

Race condition no login

Use transação para revogar a sessão pré-login e criar a autenticada. Garanta que apenas o novo cookie seja retornado.

Logout

UPDATE user_sessions
SET status = 'revoked',
    revoked_at = now()
WHERE session_hash = $1
  AND status = 'active';

Depois, expire o cookie no navegador.

Logout global

Revogue todas as sessões do usuário após comprometimento ou a pedido dele.

Lista de sessões

Mostre dispositivo aproximado, criação, último uso e sessão atual. Permita encerrar individualmente.

User agent

User agent ajuda na apresentação, mas pode ser forjado e não deve decidir autenticação sozinho.

IP

IPs mudam em redes móveis e proxies. Use como sinal de risco, não como vínculo rígido que bloqueia usuários legítimos.

Trusted proxies

Leia IP real apenas após configurar corretamente proxies confiáveis. Headers externos podem ser forjados.

Mudança de senha

Uma senha alterada pode revogar todas as sessões, exceto a atual após step-up. Defina a política e avise o usuário.

Recuperação de conta

Revogue todas as sessões e refresh tokens antigos. Uma recuperação não deve preservar acesso de um atacante.

MFA

Registre métodos usados e horário:

auth_methods: ['password', 'totp']
mfa_verified_at: '...'

Step-up authentication

Exija autenticação recente para:

  • alterar e-mail;
  • remover MFA;
  • criar token de API;
  • exportar dados;
  • alterar cobrança;
  • impersonar usuário.

Janela de step-up

const recent = Date.now() - session.mfaVerifiedAt
  < 10 * 60 * 1000;

Use horário do servidor.

Autorização

A sessão identifica o usuário e contexto, mas RBAC ou ABAC decide a ação.

Consulte RBAC no Node.js e ABAC no Node.js.

Multi-tenancy

Uma sessão pode armazenar o tenant ativo, mas a aplicação deve validar que a membership continua existente. Trocar de tenant deve atualizar contexto de forma segura.

Troca de tenant

Rotacione a sessão ou atualize uma versão de contexto, evitando aceitar apenas um tenant ID enviado pelo frontend.

Permissões alteradas

Use authz_version para invalidar decisões cacheadas quando roles mudam.

Cache de sessão

Se houver cache em memória diante do store, use TTL curto e invalidação. Uma sessão revogada não pode continuar válida por minutos.

Disponibilidade do store

Se o armazenamento cai, falhe fechado para rotas autenticadas. Não crie uma sessão sem persistência.

Timeouts

O lookup de sessão precisa de timeout. Uma dependência lenta não deve prender todas as requisições.

Graceful shutdown

Conclua gravações pendentes e feche conexões do store. Sessões já persistidas continuam válidas após reinício.

Auditoria

Registre:

  • login;
  • logout;
  • logout global;
  • rotação;
  • step-up;
  • sessão revogada;
  • recuperação;
  • atividade suspeita.

Nunca registre o ID em texto claro.

Veja Logs de Auditoria no Node.js.

Métricas

Monitore sessões ativas, logins, revogações, expirações, falhas de store, latência e rotações.

Cardinalidade

Não use session ID ou user ID como labels de métricas.

Alertas

Múltiplas sessões novas, mudança rápida de localização, recuperação seguida de uso antigo e falhas de store podem exigir investigação.

Limpeza

Remova sessões expiradas em lotes e preserve apenas metadados necessários para auditoria.

Índices

CREATE INDEX idx_sessions_user_active
ON user_sessions (user_id, last_seen_at DESC)
WHERE status = 'active';

Testes unitários

Teste geração, hash, expiração, rotação e regras de status.

Teste de fixation

test('troca o ID depois do login', async () => {
  const anonymous = await startSession();
  const authenticated = await login(
    anonymous.cookie,
    credentials
  );

  assert.notEqual(
    authenticated.sessionCookie,
    anonymous.cookie
  );
});

Confirme HttpOnly, Secure, SameSite, Path e prefixo configurado.

Teste de CSRF

Uma requisição de mudança sem token válido deve falhar, mesmo com cookie.

Teste de expiração

Use relógio controlado para testar inatividade e limite absoluto.

Teste de revogação

Após logout, o mesmo cookie não pode acessar rotas protegidas.

Teste de múltiplas réplicas

Crie a sessão em uma instância e use em outra. Isso detecta uso acidental de memória local.

Teste de store indisponível

A API deve retornar erro controlado e não considerar o usuário autenticado.

Teste de concorrência

Simule duas abas durante rotação e confirme o comportamento de sucessor sem prolongar o ID anterior.

Teste de remoção de permissão

Altere authz_version e confirme que a sessão antiga reavalia o acesso.

Erros comuns

  • ID previsível: sessões podem ser adivinhadas.
  • Não rotacionar após login: fixation permanece possível.
  • Cookie sem HttpOnly: scripts roubam o ID.
  • Cookie sem Secure: rede expõe a sessão.
  • Sem CSRF: sites externos executam ações.
  • MemoryStore em produção: réplicas divergem.
  • Expiração apenas no cookie: servidor aceita sessão antiga.

Boas práticas

  • Gere IDs criptográficos.
  • Armazene somente hash.
  • Rotacione após login e step-up.
  • Use cookie HttpOnly, Secure e SameSite.
  • Proteja CSRF.
  • Use store compartilhado.
  • Defina inatividade e limite absoluto.
  • Permita revogação por dispositivo.
  • Reavalie autorização.
  • Audite sem registrar IDs.

Conclusão

Implementar Sessões Seguras no Node.js exige mais que salvar um identificador em cookie. O ID precisa ser aleatório, rotacionado após autenticação e validado em um armazenamento compartilhado.

Cookies seguros, proteção CSRF, expiração, revogação e step-up reduzem o impacto de roubo e fixation. Com auditoria, lista de dispositivos e testes entre réplicas, a aplicação mantém a conveniência das sessões sem aceitar credenciais permanentes e invisíveis ao usuário.

10 melhores cursos de programação em 2026

Descubra os melhores cursos de programação. Aprenda a escolher o curso ideal para iniciar ou avançar na carreira de desenvolvedor

POSTS RELACIONADOS

Ver todos

Seta para a direita