
Muitos aplicativos usam JSON Web Tokens (JWT) para permitir que o cliente se identifique para troca de informações adicionais após a autenticação.
O JSON Web Token é um padrão aberto (RFC 7519) que define uma maneira compacta e independente de transferir com segurança informações entre partes como um objeto JSON.

Essas informações são verificadas e confiáveis porque são assinadas digitalmente.
Os JWTs podem ser assinados usando um segredo (usando o algoritmo HMAC) ou pares de chaves pública / privada usando RSA ou ECDSA.
O JSON Web Token é usado para transmitir informações sobre a identidade e as características do cliente. Esse "contêiner" é assinado pelo servidor para que o cliente não interfira com ele e não possa alterar, por exemplo, dados de identificação ou quaisquer características (por exemplo, a função de um usuário simples para um administrador ou alterar o login do cliente).
Esse token é criado em caso de autenticação bem-sucedida e é verificado pelo servidor antes de iniciar a execução de cada solicitação do cliente. O token é usado pelo aplicativo como um “cartão de identidade” do cliente (um contêiner com todas as informações sobre ele). O servidor tem a capacidade de verificar a validade e a integridade do token de maneira segura. Isso permite que o aplicativo seja sem estado (um aplicativo sem estado não salva os dados do cliente gerados em uma sessão para uso na próxima sessão com esse cliente (cada sessão é independente)) e o processo de autenticação é independente dos serviços utilizados (no sentido de que as tecnologias de cliente e servidor pode variar, incluindo até o canal de transporte, embora o HTTP seja mais comumente usado).
Considerações para usar o JWT
Mesmo que o token JWT seja fácil de usar e permita que você forneça serviços (principalmente REST) sem monitoração de estado (sem estado), essa solução não é adequada para todos os aplicativos, pois vem com algumas ressalvas, como a questão de armazenar o token.
Se o aplicativo não precisar ser completamente sem estado, considere o uso do sistema de sessões tradicional fornecido por todas as plataformas da web. No entanto, para aplicativos sem estado, o JWT é uma boa opção se implementado corretamente.
Problemas e ataques do JWT
Usando o algoritmo de hash NONE
Um ataque semelhante ocorre quando um invasor altera o token e também altera o algoritmo de hash (campo "alg") para indicar através da palavra-chave none que a integridade do token já foi verificada. Algumas bibliotecas visualizaram tokens assinados usando o algoritmo none como um token válido com uma assinatura verificada, para que um invasor pudesse alterar a carga útil do token e o aplicativo confiasse no token.
Para impedir um ataque, você deve usar a biblioteca JWT, que não é afetada por esta vulnerabilidade. Além disso, durante a validação do token, você deve solicitar explicitamente o uso do algoritmo esperado.
Exemplo de implementação:
Intercepção de token
O ataque ocorre quando um token é interceptado ou roubado por um invasor e ele o usa para obter acesso ao sistema usando as credenciais de um usuário específico.
A proteção consiste em adicionar um "contexto de usuário" ao token. O contexto do usuário consistirá nas seguintes informações:
- Uma sequência aleatória gerada no estágio de autenticação e incluída no token e também enviada ao cliente como um cookie mais seguro (sinalizadores: prefixos de cookie HttpOnly + Secure + SameSite +).
- O hash SHA256 da cadeia aleatória será armazenado no token, para que qualquer problema XSS não permita que o invasor leia o valor da cadeia aleatória e defina o cookie esperado.
O endereço IP não será usado em contexto, porque há situações em que o endereço IP pode ser alterado durante uma sessão, por exemplo, quando um usuário acessa o aplicativo por meio de seu telefone celular. Então o endereço IP está constantemente mudando legitimamente. Além disso, o uso de um endereço IP pode causar problemas no nível de conformidade com o GDPR europeu.
Se durante a verificação do token, o token recebido não contém o contexto correto, ele deve ser rejeitado.
Exemplo de implementação:Código para criar um token após autenticação bem-sucedida:
Código para verificar a validade do token:
Revogação explícita do token pelo usuário
Como o token se torna inválido somente após sua expiração, o usuário não possui uma função interna que permita cancelar explicitamente o token. Assim, em caso de roubo, o usuário não pode retirar o token sozinho e depois bloquear o atacante.
Um dos métodos de proteção é a introdução de uma lista negra de tokens, que será adequada para simular a função de "logout" existente em um sistema tradicional de sessões.
A coleção (na codificação SHA-256 em HEX) do token com a data de cancelamento, que deve exceder o período de validade do token emitido, será armazenada na lista negra.
Quando o usuário deseja "efetuar logout", ele chama um serviço especial que adiciona o token de usuário fornecido à lista negra, o que leva ao cancelamento imediato do token para uso posterior no aplicativo.
Exemplo de implementação:Repositório da lista negra:Para armazenamento centralizado da lista negra, será utilizado um banco de dados com a seguinte estrutura:
create table if not exists revoked_token(jwt_token_digest varchar(255) primary key, revokation_date timestamp default now());
Gerenciamento de revogação de token:
Divulgação de Token
Esse ataque ocorre quando um invasor obtém acesso a um token (ou um conjunto de tokens) e extrai as informações nele armazenadas (as informações sobre o token JWT são codificadas usando base64) para obter informações sobre o sistema. As informações podem ser, por exemplo, funções de segurança, formato de login etc.
O método de proteção é bastante óbvio e consiste em criptografar o token. Também é importante proteger os dados criptografados contra ataques usando a análise de criptografia. Para atingir todos esses objetivos, é usado o algoritmo AES-GCM, que fornece criptografia autenticada com dados associados (AEAD). A primitiva AEAD fornece funcionalidade de criptografia autenticada simétrica. As implementações dessa primitiva são protegidas contra ataques adaptativos com base no texto cifrado selecionado. Ao criptografar texto sem formatação, você pode opcionalmente especificar dados relacionados que devem ser autenticados, mas não criptografados.
Ou seja, a criptografia com os dados relevantes garante a autenticidade e a integridade dos dados, mas não o sigilo.
No entanto, deve-se observar que a criptografia é adicionada principalmente para ocultar informações internas, mas é muito importante lembrar que a proteção inicial contra a falsificação do token JWT é a assinatura, portanto, a assinatura do token e sua verificação sempre devem ser usadas.
Armazenamento de token do lado do cliente
Se o aplicativo armazena o token para que ocorra uma ou mais das seguintes situações:
- o token é enviado automaticamente pelo navegador (armazenamento de cookies);
- o token é obtido mesmo se o navegador for reiniciado (usando o contêiner localStorage do navegador);
- o token é obtido no caso de um ataque XSS (cookie disponível para código JavaScript ou um token armazenado em localStorage ou sessionStorage).
Para impedir um ataque:
- Armazene o token no navegador usando o contêiner sessionStorage.
- Adicione-o ao cabeçalho de Autorização usando o esquema Portador. O título deve ficar assim:
Authorization: Bearer <token>
- Adicione informações de impressão digital ao token.
Armazenando o token no contêiner sessionStorage, ele fornece um token para roubo no caso do XSS. No entanto, uma impressão digital adicionada ao token impede que um invasor reutilize o token roubado em seu computador. Para fechar as áreas de uso máximo de um invasor, adicione uma Política de Segurança de Conteúdo para limitar o contexto de execução.
Ainda existe um caso em que um invasor usa o contexto de navegação do usuário como um servidor proxy para usar o aplicativo de destino através de um usuário legítimo, mas a Política de Segurança de Conteúdo pode impedir a comunicação com domínios inesperados.
Também é possível implementar um serviço de autenticação para que o token seja emitido dentro de um cookie seguro, mas, nesse caso, a proteção contra o CSRF deve ser implementada.
Usando uma chave fraca para criar um token
Se o segredo usado no caso do algoritmo HMAC-SHA256, necessário para assinar o token, for fraco, ele poderá ser invadido (detectado usando um ataque de força bruta). Como resultado, um invasor pode falsificar um token válido arbitrário em termos de assinatura.
Para evitar esse problema, você deve usar uma chave secreta complexa: alfanumérica (maiúsculas e minúsculas) + caracteres especiais.
Como a chave é necessária apenas para cálculos de computador, o tamanho da chave secreta pode exceder 50 posições.
Por exemplo:
A&'/}Z57M(2hNg=;LE?~]YtRMS5(yZ<vcZTA3N-($>2j:ZeX-BGftaVk`)jKP~q?,jk)EMbgt*kW'
Para avaliar a complexidade da chave secreta usada para sua assinatura de token, você pode aplicar um ataque de dicionário de senha ao token em combinação com a API JWT.