Segurança no gerenciamento de sessões: práticas recomendadas para proteger as sessões dos usuários
11 de julho de 2023
0 minutos de leituraA segurança no gerenciamento de sessões é um componente essencial do desenvolvimento de aplicações web. Ela protege as sessões dos usuários e impede acessos não autorizados. O gerenciamento de sessões protege a confidencialidade, a integridade e a disponibilidade dos dados confidenciais dos usuários. Também protege a privacidade deles em geral — algo essencial para manter a confiança dos usuários na aplicação.
Ao gerenciar sessões com segurança, estabelecemos processos para destruir os tokens de sessão quando os usuários fazem logout ou quando a sessão termina. Essa abordagem impede o acesso não autorizado de quem estiver monitorando a conexão de rede ou quiser se passar pelo usuário.
Neste artigo prático, vamos mostrar como implementar o gerenciamento seguro de sessões e apresentar as práticas recomendadas.
Entenda a segurança no gerenciamento de sessões
Para entender a importância do gerenciamento de sessões no nível do domínio, vamos desenvolver uma aplicação simples em Node.js que implementa funcionalidades básicas de login, logout e gerenciamento de sessões.
Pré-requisitos
Para acompanhar este tutorial, você precisará de:
Node.js e npm instalados localmente na sua máquina
Visual Studio Code como editor de código-fonte
A extensão Snyk para Visual Studio Code (chamada Snyk Security — Code, Open Source Dependencies no Visual Studio Code).
Este exemplo usa o sistema operacional Windows e os comandos correspondentes.
Para ver uma visão geral do projeto completo, confira o código completo.
Implementação de sessões no Node.js
Para começar, abra o prompt de comando (CMD) e use o código abaixo para criar uma pasta chamada sessions, acessá-la e inicializar a aplicação:
A execução dos comandos acima gera automaticamente um arquivo package.json com todas as dependências instaladas no projeto.
Em seguida, precisamos instalar alguns pacotes que permitirão cumprir os objetivos definidos. São eles express, um framework para criar servidores web, e express-session, um framework HTTP do lado do servidor necessário para criar o middleware de sessão. Use o código abaixo para instalar os dois pacotes:
Agora, abra o projeto no Visual Studio Code.
Para incluir a lógica da aplicação, precisamos criar um arquivo index.js. No CMD, use o comando touch index.js para criar o arquivo index.js. Em seguida, atualize o arquivo index.js com o código abaixo:
O trecho de código acima contém o código inicial de uma aplicação Node.js. Ele configura o middleware de sessão para o app Express no corpo do projeto.
O middleware URL-encoded processa as solicitações recebidas com dados de formulário codificados na URL em qualquer aplicação Express.js.
Em seguida, adicione o código abaixo dos middlewares no arquivo index.js para gerenciar as funcionalidades de login e logout do usuário na sessão:
Antes de continuar, vamos revisar rapidamente o que acontece no código acima:
A primeira rota,
app.get('/'), processa as solicitações para a URL raiz da aplicação. Ela dá boas-vindas aos usuários cujo nome de usuário está armazenado na sessão e oferece um link para fazer logout. Caso contrário, solicita que o usuário faça login.A segunda rota,
app.get('/login'), processa as solicitações para a URL de login.A terceira rota,
app.post('/login'), processa o envio do formulário de login.A quarta rota,
app.get('/logout'), processa solicitaçõesGETpara a URL de logout. Ela destrói a sessão do usuário e o redireciona para a URL raiz.
Salve todas as alterações, acesse o terminal e execute a aplicação com este comando:
Como estamos ouvindo na porta 3001, abra http://localhost:3001/ em um navegador. Ao acessar a URL, você verá este link simples de login:

Clique no link de login e informe seu nome. Você será direcionado para a seguinte página inicial:

Agora, confira o terminal. Você verá um objeto de sessão parecido com este:

A primeira propriedade é o caminho. Ela representa o caminho válido do cookie de sessão. Em seguida, vêm o prazo de expiração da sessão, o tempo até o vencimento do cookie e o atributo httpOnly definido como true para impedir ataques do lado do cliente, como cross-site scripting (XSS). O objeto de sessão também exibe o nome de usuário atual.
O gerenciamento de sessões e seu papel nas aplicações web
Agora que preparamos uma aplicação de exemplo, vamos entender como funciona o gerenciamento de sessões e por que ele é tão importante para proteger as sessões.
Nas aplicações web, as interações entre usuários e aplicações geralmente envolvem informações confidenciais — neste caso, uma senha. O gerenciamento de sessões garante que essas interações sejam seguras para usuários autenticados e que as informações fornecidas durante as sessões permaneçam protegidas. Se isso não for feito, podem surgir vulnerabilidades no gerenciamento de sessões.
Entre as vulnerabilidades mais comuns estão:
Sequestro de sessão — O sequestro ocorre quando um invasor compromete um token de sessão, roubando-o ou prevendo-o, para obter acesso não autorizado ao servidor em nome do proprietário. Há várias maneiras de fazer isso. Uma delas é usar XSS. Se o atributo httpOnly estiver definido como false na aplicação web acessada pelo usuário, a exposição ao sequestro de sessão pelo lado do cliente será muito alta, abrindo espaço para ataques XSS.
Ataques man-in-the-middle (MITM) — Esses ataques são outro tipo de sequestro de sessão. Um agente mal-intencionado pode acessar uma sessão interceptando o ID de sessão durante a comunicação entre o usuário e o servidor. Isso acontece quando o ID de sessão está em texto simples e pode ser lido facilmente por quem intercepta o canal de dados.
Fixação de sessão — A fixação ocorre quando um invasor convence o usuário a usar um ID de sessão já existente para acessar o servidor, sequestrando a sessão válida do usuário. Isso ocorre principalmente quando o usuário que acessa a sessão não é validado corretamente pelo ID de sessão. Também pode acontecer quando um invasor envia à vítima um ID de sessão vulnerável em uma URL.
Os riscos associados a processos inseguros de gerenciamento de sessões podem ser significativos. Com os dados confidenciais obtidos, agentes mal-intencionados podem cometer fraudes e roubos, além de acessar informações privilegiadas. Essas violações de segurança são extremamente prejudiciais aos usuários — e podem abalar a confiança deles na aplicação.
Felizmente, podemos adotar várias estratégias para proteger os processos de gerenciamento de sessões. Nas próximas seções, vamos apresentar alguns métodos e mostrar como implementá-los.
Implementação de cookies seguros
O uso de cookies pode ajudar a gerenciar sessões com segurança. No gerenciamento de sessões, os cookies podem vincular os usuários a um objeto de sessão no lado do servidor. Graças ao identificador exclusivo, um cookie reúne todas as atividades associadas ao usuário nas instâncias que ele acessou.
Por exemplo, quando um usuário acessa uma aplicação para fazer login, essa ação cria um objeto de sessão e atribui a ele um ID de sessão. O cookie armazena esse ID e o envia ao navegador como resposta. Quando o usuário faz uma solicitação, o navegador envia o cookie, que valida o ID de sessão e recupera o objeto correspondente. Assim, o servidor pode validar o usuário e manter suas sessões em diferentes páginas e solicitações.
Por isso, desenvolvedores de sistemas, arquitetos de aplicações e administradores devem garantir que os cookies sejam usados da forma mais segura possível.
Uma maneira de proteger cookies é usar o sinalizador secure, que permite solicitações somente por HTTPS. Ele protege o usuário na rede contra ataques MITM no caminho dos dados, pois o pacote enviado não fica em texto simples e, portanto, não pode ser lido.
Além dos ataques MITM, os cookies também são vulneráveis a ataques XSS porque transmitem pacotes de dados pela rede. Para impedir esses ataques, podemos usar o sinalizador HttpOnly, que impede que o JavaScript leia o cookie de sessão.
Para implementar esse sinalizador, precisamos verificar se o atributo HttpOnly do objeto de sessão está definido como o valor booleano true.
Acesse o terminal e instale cookie-parser, o middleware para armazenar cookies, e bcrypt, a versão vulnerável do pacote, usando o comando abaixo:
Em seguida, atualize o código no arquivo index.js da seguinte forma:
Para ver as vulnerabilidades detectadas no seu código no Visual Studio Code, verifique se Snyk Code está habilitado na sua conta. Você pode fazer isso pela extensão do Visual Studio Code ou pelo site da Snyk. Se observar a aba PROBLEMAS no terminal do Visual Studio Code, verá que a Snyk destacou várias vulnerabilidades no código:

A análise mostra que há um segredo codificado diretamente no código, a falsificação de solicitação entre sites (CSRF) está desabilitada, o sinalizador secure está desativado e há um pacote vulnerável.
A Snyk sugere várias maneiras de corrigir esses problemas seguindo as instruções exibidas. Vamos corrigir alguns deles.
Primeiro, a Snyk recomenda o uso de variáveis de ambiente para evitar valores codificados diretamente. Para fazer essa alteração, acesse o terminal e execute os comandos abaixo:
O primeiro comando instala o pacote dotenv para ler as variáveis de ambiente definidas; o segundo cria um arquivo de ambiente para armazenar essas informações confidenciais.
Agora, adicione esta configuração ao arquivo .env:
Em seguida, atualize o middleware de sessão no arquivo index.js com este código:
Com essas atualizações, o segredo será lido da variável de ambiente.
Em seguida, defina o sinalizador secure como true.
Como habilitar a proteção contra CSRF acrescentaria bastante código à nossa aplicação, vamos deixar isso de lado neste exemplo. Mas lembre-se de tratar desse ponto nas suas próprias aplicações usando o pacote csrf.
Para resolver o problema do pacote vulnerável, consulte a documentação oficial do npm e instale uma versão atualizada ou um pacote bcryptjs seguro e mais testado.
Depois que a extensão Snyk analisar sua aplicação com essas atualizações, você verá que a maioria dos erros desapareceu. Se executar a aplicação neste ponto, o localhost não funcionará sem HTTPS e continuará redirecionando você para a URL raiz.
Além de usar o armazenamento local para armazenar dados de solicitações do cliente, você pode guardar os dados da sessão da aplicação em um banco de dados. Isso permite reiniciar o servidor sem perder os dados da sessão, que permanecem associados a um ID de sessão exclusivo. Assim, os usuários podem fazer login sem precisar informar as credenciais todas as vezes. Outra opção é usar caches de memória, como o Redis.
Implementação de tempos limite para sessões
Os tempos limite de sessão ocorrem quando uma sessão do usuário expira, encerrando automaticamente o login no sistema. Isso reduz o período em que um ataque à sessão pode ocorrer e garante que ela seja destruída após um intervalo específico.
Há vários fatores a considerar ao definir a duração dos tempos limite de sessão:
Tipo de aplicação — Defina um tempo limite de sessão adequado aos dados tratados pela aplicação.
Comportamento dos usuários — Evite que os tempos limite prejudiquem a experiência dos usuários.
Implementamos os tempos limite de sessão no middleware de sessão. Atualize o código com o trecho abaixo para definir o tempo limite em uma hora:
Implementação da funcionalidade adequada de logout
A funcionalidade de logout permite que os usuários encerrem explicitamente suas sessões quando terminam de interagir com uma aplicação. Com ela, os usuários controlam o encerramento das sessões de cookies e têm mais autonomia sobre a própria segurança.
No entanto, a funcionalidade de logout ainda exige atenção dos desenvolvedores. Quando um usuário inicia o logout, a sessão no lado do cliente pode ser encerrada. Mas, no servidor, o cookie de sessão pode não ter sido totalmente invalidado. Um impostor pode usar esses tokens de sessão e realizar ações como se fosse o usuário original.
Para evitar essa violação de segurança, precisamos garantir que o token e o ID da sessão do usuário sejam destruídos no servidor. Implemente esta função na aplicação, usando o código abaixo como a última rota no arquivo index.js:
Este código chama destroy() com uma função de callback para excluir uma sessão no servidor quando o usuário faz logout. Ele também chama clearCookie() e exclui connection.sid, que é uma chave atribuída ao valor do usuário conectado.
Se você inspecionar os cookies do usuário conectado no navegador pela opção de inspeção, deverá ver um connection.sid, como mostrado abaixo:

Ao implementar as etapas acima, podemos garantir que os usuários do sistema façam logout sem se preocupar com a segurança online. A extensão Snyk Code permite ver todas as análises de vulnerabilidades feitas no nosso projeto e o status de cada uma, ajudando a garantir que a aplicação não esteja exposta a riscos antes de disponibilizá-la aos usuários.
Ao longo deste artigo, usamos o Snyk para analisar nosso projeto e entender como corrigir problemas de vulnerabilidade, como segredos codificados diretamente no código, problemas relacionados a sessões e o uso de um pacote vulnerável. Agora que corrigimos as vulnerabilidades identificadas pelo Snyk, nosso sistema não apresenta nenhuma, como mostra o relatório abaixo:

Outras práticas recomendadas para o gerenciamento seguro de sessões
Além dos processos abordados neste artigo, veja outras práticas recomendadas para gerenciar sessões com mais segurança:
Use identificadores de sessão seguros — Identificadores de sessão seguros são strings longas de caracteres exclusivos usadas para autenticar sessões de usuários. Podemos gerar esses identificadores automaticamente. A aleatoriedade e a imprevisibilidade dificultam que invasores determinados os adivinhem, mesmo usando técnicas de análise estatística. Além disso, o tamanho da string é suficiente para resistir a ataques de força bruta.
Use o gerenciamento de sessões no servidor — Capturar identificadores de sessão no lado do cliente pode criar uma vulnerabilidade, mesmo quando eles são gerados de forma exclusiva. Podemos usar o gerenciamento de sessões no servidor para armazenar esses identificadores e associá-los aos usuários na aplicação. Com esse tipo de armazenamento de sessão, as credenciais confidenciais dos usuários ficam muito mais seguras, e eles podem usar o sistema sem o risco de serem vítimas de personificação.
Valide os logouts corretamente — Quando um usuário entra em uma instância e depois faz logout, o sistema deve invalidar corretamente a sessão em todas as instâncias que ele acessou. Fazer isso sem sincronizar os dados da sessão entre as instâncias pode ser complicado. Ainda assim, é essencial, pois as instâncias podem se tornar pontos de entrada para impostores roubarem informações dos usuários.
Conclusão
Neste artigo, exploramos várias estratégias para melhorar a segurança do gerenciamento de sessões, proteger ao máximo os visitantes e reduzir o número de ataques. Um gerenciamento seguro de sessões mantém informações pessoais, dados e contas protegidos, mesmo diante dos rastros que os usuários podem deixar.
Ele também protege os usuários enquanto interagem com nossos sites e aplicações web. Ao implementar as práticas recomendadas e as estratégias de segurança apresentadas aqui, podemos ajudar nossos usuários a confiar que suas credenciais e informações confidenciais estão seguras.
Comece a jogar Capture the Flag
Aprenda a resolver desafios de Capture the Flag assistindo à gravação sob demanda do nosso workshop virtual introdutório.


