Skip to main content

O Snyk consegue detectar problemas de segurança em JWTs?

Escrito por
blog feature ai green

4 de março de 2025

0 minutos de leitura

JWTs são frequentemente usados por desenvolvedores que querem implementar autenticação em vez das tradicionais sessões baseadas em cookies. Mas o que acontece quando os desenvolvedores não entendem bem a segurança de JWT e criam uma grave vulnerabilidade de autenticação comprometida?

O que é um JWT?

JSON Web Tokens (JWTs) são uma forma compacta e autocontida de transmitir informações com segurança entre partes, como um objeto JSON. Como são assinadas digitalmente, muitas vezes com certificados, essas informações podem ser verificadas e consideradas confiáveis. Para desenvolvedores web, JWTs são uma opção comum para adicionar autenticação às aplicações e evitar os mecanismos tradicionais de segurança de cookies e gerenciamento de sessões no navegador.

Estrutura de um JWT

Como descrito acima, um JWT é um objeto JSON comum que armazena dados. Um JWT é composto por cabeçalho, payload e assinatura. Esses componentes são codificados em Base64 e concatenados com pontos (.) para formar a string do JWT.

1. Cabeçalho: O cabeçalho geralmente tem duas partes: o tipo de token, JWT, e o algoritmo de assinatura usado, como HMAC SHA256 ou RSA.

 {
     "alg": "HS256",
     "typ": "JWT"
   }

2. Payload: O payload contém as declarações (claims), que são afirmações sobre uma entidade (geralmente o usuário) e dados adicionais. No entanto, evite armazenar informações confidenciais ou sensíveis, pois os JWTs muitas vezes não são criptografados e qualquer pessoa pode decodificá-los para acessar os dados. Há três tipos de claims: registradas, públicas e privadas.

{
     "sub": "1234567890",
     "name": "John Doe",
     "admin": true
   }

3. Assinatura: Para criar a parte da assinatura, use o cabeçalho codificado, o payload codificado, um segredo e o algoritmo especificado no cabeçalho para gerar a assinatura.

 HMACSHA256(
     base64UrlEncode(header) + "." +
     base64UrlEncode(payload),
     secret)

O JWT resultante pode ser semelhante a este:

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c

O papel dos JWTs em APIs e microsserviços

JWTs têm um papel importante no trabalho de desenvolvedores frontend e backend ao implementar a autenticação e criar APIs e microsserviços. Ao contrário da autenticação tradicional baseada em sessões no servidor, que exige que ele mantenha o estado de sessão persistente em um banco de dados, os JWTs permitem uma abordagem mais escalável e eficiente por serem stateless. Quando um usuário faz login, o servidor gera um token que codifica as informações do usuário e o assina com uma chave secreta. Em seguida, o token é enviado ao cliente, que o inclui no cabeçalho das solicitações seguintes.

O servidor pode verificar a assinatura do token para autenticar o usuário sem armazenar dados de sessão. Por serem stateless, os JWTs são especialmente adequados a sistemas distribuídos e arquiteturas de microsserviços, nas quais manter um repositório centralizado de sessões poderia se tornar um gargalo ou um ponto único de falha.

Pacotes npm open source populares de JWT para Node.js

Ao trabalhar com JWT em Node.js, desenvolvedores têm à disposição várias bibliotecas open source, mas muitas vezes escolhem o popular pacote npm jsonwebtoken. Essas bibliotecas simplificam a geração, a assinatura e a verificação de tokens. No entanto, entender as diferenças entre os recursos e as considerações de segurança é essencial para evitar o uso incorreto da biblioteca e a introdução de riscos à segurança.

Outros pacotes npm de JSON incluem node-jose e integrações com frameworks web, como passport-jwt e @fastify/jwt.

Riscos de segurança de JWT ao decodificar um token

Para demonstrar um erro clássico no uso inseguro de JWTs para gerenciar a autenticação, vamos escolher as opções populares que costumam atrair desenvolvedores: o framework web Express e a biblioteca de JWT jsonwebtoken.

Você consegue encontrar a vulnerabilidade de segurança no código Node.js a seguir?

const express = require('express');
const jsonWebToken = require('jsonwebtoken');
require('dotenv').config();

const webApp = express();

const securityKey = process.env.JWT_SECRET;

const validateAccess = (request, response, next) => {
  const authorizationHeader = request.headers.authorization;

  if (!authorizationHeader) {
    return response.status(401).json({ error: 'Missing authentication credentials' });
  }

  try {
    const decodedToken = jsonWebToken.decode(authorizationHeader,{complete: true});
    request.userContext = decodedToken;
    next();
  } catch (authError) {
    return response.status(403).json({ error: 'Invalid or expired token' });
  }
};

webApp.get('/privileged-area', validateAccess, (request, response) => {
  const { username } = request.userContext;
  if (username === 'admin') {
    // Access to sensitive data is now available.
    return response.status(200).json({ status: 'Access permitted to admin' });
  }
  response.status(403).json({ status: 'Insufficient permissions' });
});

webApp.get('/issue-token', (request, response) => {
  const userClaims = { username: 'user' };
  const authenticationToken = jsonWebToken.sign(userClaims, securityKey, { expiresIn: '1h' });
  response.status(200).json({ authenticationToken });
});

webApp.listen(3001, () => {
  console.log('Application listening on port 3001');
});

Este código Node.js usa jsonWebToken.decode() para decodificar o JWT. Esse método apenas decodifica o token, sem verificar sua assinatura. Portanto, embora funcione porque decodedToken retorna dados, não há garantia de que esses dados sejam os mesmos definidos pelo servidor nem de que não tenham sido adulterados por terceiros. Isso significa que qualquer pessoa pode adulterar o token e, ainda assim, a aplicação vai aceitá-lo como válido. Em vez disso, use jsonWebToken.verify() para decodificar o token e verificá-lo com a chave secreta.

O Snyk detecta problemas de segurança em JWTs

Execute no Snyk o código Node.js vulnerável acima. Ele identificará o problema de segurança de JWT causado pelo uso do método inseguro jwt.decode() da biblioteca jsonwebtoken:

A Snyk detecta um problema de segurança em JWT que decodifica um token de forma insegura

O Snyk pode identificar o problema, dependendo de como você faz a integração. Na captura de tela acima, importei o repositório de código do GitHub pelo app web do Snyk. Após a importação, o Snyk verifica o repositório em busca de arquivos de manifesto, como requirements.txt, do Python, ou package.json, do npm, para detectar dependências vulneráveis. O Snyk também detecta arquivos de IaC, como os do Terraform, e faz uma análise estática do código-fonte.

Como mostra a captura de tela acima, o Snyk detectou o uso incorreto da biblioteca jsonwebtoken: a função insegura jwt.decode pode levar ao comprometimento da autenticação.

Veja a seguir uma forma recomendada de decodificar um JWT com segurança:

   try {
     const decodedToken = jsonWebToken.verify(authorizationHeader, securityKey);
     request.userContext = decodedToken;
     next();
   } catch (authError) {
     return response.status(403).json({ error: 'Invalid or expired token' });
   }

O exemplo de código Node.js acima também apresenta estas outras lacunas de segurança em JWTs:

  • Dados sensíveis codificados no código: O trecho de código armazena a chave secreta em variáveis de ambiente. Garanta que essas variáveis sejam gerenciadas com segurança, não sejam expostas em sistemas de controle de versão e possam ser rotacionadas e administradas com segurança.

  • Registro insuficiente: Implemente o registro de tentativas e erros de autenticação. Isso pode ajudar a monitorar e responder a possíveis incidentes de segurança.

  • Limitação de taxa: Como controlar tentativas de login por força bruta e outros abusos de APIs de autenticação? Implemente a limitação de taxa para evitar o consumo excessivo de recursos e tentativas de autenticação sem controle.

  • Expiração de tokens: Embora o código defina um prazo de expiração para os tokens, é essencial verificar se eles expiraram em cada solicitação.

Práticas recomendadas de segurança para JWTs

Proteger uma API REST com JWT envolve mais do que apenas emitir e verificar tokens. É preciso considerar cuidadosamente várias práticas de segurança para reduzir possíveis vulnerabilidades. Por exemplo, use sempre uma chave secreta forte para assinar tokens, de preferência chaves assimétricas, e garanta que os tokens sejam transmitidos por HTTPS para evitar interceptações.

Além disso, é essencial implementar estratégias adequadas de expiração e revogação de tokens. Os tokens devem ter uma vida útil curta para minimizar o risco de uso indevido em caso de comprometimento. Tokens de atualização podem ser usados para emitir novos tokens de acesso sem exigir que o usuário faça login novamente, mas também devem ser gerenciados com segurança.

Confira nosso guia mais completo sobre como proteger APIs REST.

SEGURANÇA DE CÓDIGO COM IA

Guia de compra de segurança para código gerado por IA

Saiba como proteger seu código gerado por IA com o Guia de compra de segurança para código gerado por IA da Snyk.