Este artigo aborda superficialmente tokens JWT e o seu uso no gerenciamento de sessão. Ele aponta uma razão para esse uso, os seus riscos e os ataques já sofridos por conta do uso de tokens JWT. Por fim, ele aponta uma abordagem que permite usar tokens JWT em combinação com tokens opacos para mitigar os riscos de segurança previamente listados.
1. O que é JSON Web Token?
JSON Web Token é um padrão aberto, especificado na RFC-7519, que define uma forma compacta e autocontida de transmitir com segurança informações entre interlocutores de comunicação (serviços e APIs, por exemplo) como objeto JSON. Neste artigo, apenas o token JWT estruturado será considerado.
2. Estrutura do token JWT
O token JWT é composto por três partes codificadas em base64 separadas por pontos. O trecho em cor vermelha é o cabeçalho do token. O trecho em cor roxa é o conteúdo do token. Por fim, o trecho em cor azul é a assinatura do token.
* Cabeçalho
O cabeçalho contém informações sobre o tipo de token, typ, e o algoritmo usado para assinar os seus cabeçalho e o conteúdo, alg. No caso da figura abaixo, o token é do tipo JWT e o algoritmo usado para assiná-lo combina o algoritmo de assinatura baseada em chave secreta HMAC com a função de hash criptográfico SHA256.
* Conteúdo
O conteúdo contém as informações a compartilhar transmitidas por meio do token JWT. Essas informações são associadas a atributos, chamados claims, do objeto JSON. Esses atributos podem ser reservados, públicos ou privados. No caso da figura abaixo, o identificador da entidade sobre a qual JWT trata, sub, é 1234567890, o nome dessa entidade, name, é John Doe e o instante no qual o token foi gerado, iat, é representado por 1516239022, segundos desde o epoch time.
* Assinatura
A assinatura é usada para validar a confiabilidade do token. Ela permite checar a sua integridade (se o token foi ou não foi alterado) e, no caso de tokens assinados usando chave privada, também permite verificar se o emissor é quem afirma ser. No caso da foto abaixo, a assinatura é calculada a partir da concatenação do cabeçalho e do conteúdo codificados em base64 separados por um ponto ‘.’ e de uma chave secreta.
3. Uso do token JWT
O token JWT é usado na troca de informação entre serviços, no processo de autenticação de usuário e no gerenciamento de sessão.
O fato de o token ser assinado permite ao seu destinatário ter certeza de que as informações não foram corrompidas ou alteradas durante o seu trânsito e o token foi gerado pelo remetente da comunicação. Portanto, o uso de token JWT é uma boa alternativa para transmitir informações.
Quando um usuário é autenticado com sucesso usando a sua credencial, um token ID é retornado. Segundo a especificação do OpenID Connect (OIDC), o token ID sempre é um token JWT.
O seu uso mais comum e mais debatido é o uso no gerenciamento de sessão de usuário. A sua aplicação nesse caso de uso tenta reduzir o tempo de resposta de requisição ao eliminar uma consulta ao banco de dados de sessão.
4. Por que o token JWT é usado no gerenciamento de sessão?
No caso tradicional de gerenciamento de sessão, após se autenticar, o cliente recebe um token de sessão opaco, identificador de sessão sem significado. A partir desse momento, ele é enviado ao servidor a cada requisição feita a ele.
Ao receber a requisição, o servidor usa o token de sessão para consultar as informações do usuário no banco de dados. Desse modo, o servidor será capaz de verificar se o token é válido, de validar se o usuário tem permissão para realizar a ação e, em caso positivo, realizá-la. Como essa consulta deve ser feita a cada requisição enviada pelo cliente e ela é lenta, o tempo de resposta às requisições acaba sendo alongado.
Por outro lado, usando um token JWT estruturado, contendo as informações do usuário como conteúdo, não há mais necessidade de se realizar a consulta ao banco de dados por essas informações a cada requisição enviada pelo cliente. Essa redução do tempo de resposta dá vantagem ao uso de JWT no gerenciamento de sessão.
5. Será que tudo são flores?
Apesar dessa redução do consumo de recursos do banco de dados e da consequente redução do tempo de resposta, o uso de JWT no gerenciamento de sessão traz alguns riscos. O uso de tokens JWT adiciona complexidade e cria oportunidade para exploração de falhas de segurança no seu código de implementação. Alguns ataques bem sucedidos contra o JWT exploraram falhas no seu algoritmo de manipulação, a falta de validação da assinatura e o vazamento de informações sensíveis.
Como os tokens JWT só se tornam inválidos após o seu vencimento, o token continua válido, mesmo que o usuário feche a sua sessão na aplicação ou tenha o seu acesso bloqueado. A confiança nas informações do usuário contidas no token permanece, mesmo que elas tenham sido atualizadas no respectivo banco de dados, o que pode representar um risco de segurança. Caso a permissão de acesso de um usuário seja reduzida da permissão de administração para a permissão de usuário comum, o token garantirá a primeira permissão, enquanto ele for válido, caso essa alteração tenha ocorrido durante o seu período de validade.
6. Qual é a recomendação da OWASP sobre token de sessão
Além dos problemas enumerados previamente, o uso de token JWT com informações do usuário vai de encontro à recomendação da OWASP. Essa organização sugere que os identificadores de sessão não tenham sentido para evitar ataques de vazamento de informação. Caso alguma informação sensível faça parte das informações contidas no conteúdo do token, o envio dele para o cliente após a autenticação permitirá o abuso da informação sensível por atores maliciosos.
7. O "token fantasma"
Felizmente, não é necessário escolher apenas entre usar token opaco, sem sentido, apesar do prejuízo no tempo de resposta às requisições, ou usar token JWT com informações do usuário para ter melhor tempo de resposta, mas assumir os riscos enumerados previamente.
A abordagem do "token fantasma" combina a segurança do token opaco com a conveniência do token JWT. A ideia central é inserir um middleware (proxy reverso, por exemplo) com mecanismo de cache entre o cliente e o servidor. Nesse cenário, o cliente recebe um token opaco a ser enviado ao servidor a cada requisição e o middleware intermedeia a comunicação entre o cliente e o servidor. Ele passa a ser responsável por substituir o token opaco pelo token JWT estruturado, antes de encaminhar a requisição ao servidor destino.
Como o cliente recebe um token opaco, os riscos de vazamento de informações sensíveis e de exploração de falhas de implementação do JWT são mitigados. Como o servidor recebe o token JWT, ele não precisará consultar os dados do usuário a cada requisição e terá melhor tempo de resposta.
8. Conclusão
O artigo citou dois tipos de tokens e apontou as suas vantagens e desvantagens. Ele também apresentou uma abordagem combinada que tenta se aproveitar das vantagens desses tipos.
Apesar de a abordagem do “token fantasma” parecer bem efetiva, não existe "bala de prata". Portanto, no momento de escolher entre usar tokens opacos, tokens JWT, abordagem combinada ou abordagem diferente das elencadas no artigo, avalie os ganhos e os riscos de cada decisão. Por fim, decida pela que lhe oferecer maior ganho com riscos aceitáveis para a sua situação.
Boa sorte na sua jornada e desejo que a trilhe sempre levando em conta os riscos associados a cada opção disponível!
Seja atento e vá em segurança.
Fontes:
https://jwt.io/introduction
https://auth0.com/docs/security/tokens/json-web-tokens/
https://datatracker.ietf.org/doc/html/rfc7519
https://apisecurity.io/issue-56-common-jwt-attacks-owasp-api-security-top-10-cheatsheet/
https://insomniasec.com/blog/auth0-jwt-validation-bypass
https://auth0.com/blog/critical-vulnerabilities-in-json-web-token-libraries/
https://redis.com/blog/json-web-tokens-jwt-are-dangerous-for-user-sessions/
http://cryto.net/~joepie91/blog/2016/06/13/stop-using-jwt-for-sessions/
https://cheatsheetseries.owasp.org/cheatsheets/Session_Management_Cheat_Sheet.html
https://curity.io/resources/learn/phantom-token-pattern/
- 4
- 1