O lado obscuro do JWT: Explorando vulnerabilidades em Tokens.
Muitas aplicações modernas utilizam JSON Web Tokens (JWTs) para autenticar e autorizar usuários em suas funcionalidades. Neste artigo, exploraremos vulnerabilidades em JWTs que podem comprometer o sistema de assinatura, permitindo que um atacante autentique-se e eleve seus privilégios em uma aplicação vulnerável.
Conhecendo o JSON Web Token
Antes de explorar uma vulnerabilidade em um artefato, é fundamental estudá-lo e entender seu funcionamento em detalhes.
Um JWT é formato por três partes (todas com base64url encoding):
- Header – utilizado para armazenar as propriedades do token.
- Payload – utilizado para armazenar os dados.
- Signature – utilizado para garantir a integridade e segurança do token.
A assinatura de um JWT é gerada a partir da combinação do “Header” e do “Payload”, assegurando a integridade dos dados contidos em ambos os campos. No exemplo apresentado, o algoritmo utilizado na assinatura é o “HS256”. No entanto, existem diversos algoritmos disponíveis, que empregam tanto criptografia simétrica quanto assimétrica.
Veja abaixo os algoritmos utilizados na assinatura de um JWT:
Algoritmos com criptografia simétrica:
- HS256
- HS384
- HS512
Algoritmos com criptografia assimétrica:
- RS/ES/PS256
- RS/ES/PS384
- RS/ES/PS512
Algoritmo sem criptografia:
- None
Criando e verificando JWT manualmente
Utilizando o JavaScript para criar um JWT:
const crypto = require('crypto'); // JWT Header const header = btoa(JSON.stringify({ typ: 'JWT', alg: 'HS256' })); // JWT Payload const payload = btoa(JSON.stringify({ id: 1, username: 'guest', roles: ['guest'] })); // JWT Signature const signature = crypto.createHmac('sha256', 'secretKey').update(`${header}.${payload}`).digest('base64url'); const jwt = `${header}.${payload}.${signature}`; console.log(jwt)
Utilizando o JavaScript para verificar a assinatura do JWT:
const crypto = require('crypto'); const jwt = "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpZCI6MSwidXNlcm5hbWUiOiJndWVzdCIsInJvbGVzIjpbImd1ZXN0Il19.7Rli0HzIbFTUtv1uRcJjnjuNzzg0eNjXpqCQfJTd39Y"; // Extracting header, payload and signature from JWT const [header,payload,signature] = jwt.split('.'); // Creating signature using secretKey const signature_verify = crypto.createHmac('sha256', 'secretKey').update(`${header}.${payload}`).digest('base64url'); // Comparing signatures if(signature == signature_verify) { console.log('Valid token'); } else { console.log('Invalid token'); }
Criando e verificando JWT utilizando bibliotecas externas
Utilizando a biblioteca “jsonwebtoken” para criar um JWT:
const jwt = require('jsonwebtoken'); // JWT Payload const payload = { id: 1, username: 'guest', roles: ['guest'] }; console.log(jwt.sign(payload, 'secretKey'));
Utilizando a biblioteca “jsonwebtoken” para verificar a assinatura do JWT:
const jwt = require('jsonwebtoken'); const token = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MSwidXNlcm5hbWUiOiJndWVzdCIsInJvbGVzIjpbImd1ZXN0Il0sImlhdCI6MTcyNTA1MjQ1Nn0.oDaFyyt9k8302zekM6eYR_5B9dGbHKPPzRj7J7-pow8'; // Checking JWT if(jwt.verify(token, 'secretKey')) { console.log('Valid token') } else { console.log('Invalid token') }
Explorando vulnerabilidades em JSON Web Tokens
Agora que compreendemos o funcionamento dos JWTs, podemos proceder ao estudo das vulnerabilidades associadas a eles.
Neste artigo, vamos abordar as seguintes vulnerabilidades:
- Weak secret
- None attack
- KID Header injection
- JKU Header injection
- Algorithm Confusion
Observação: Todos os desafios mostrados no artigo estão disponíveis em nosso github.
https://github.com/hakaioffsec/jwt-vulnerabilities-lab
Weak secret attack
Ao utilizar algoritmos de criptografia simétrica, que empregam a mesma chave para criptografar e descriptografar dados, os tokens JWT (JSON Web Tokens) podem estar suscetíveis a ataques de força bruta.
Se uma aplicação utiliza algoritmos como “HS256”, “HS384” ou “HS512” e possuí uma chave de assinatura fraca, é possível que um atacante descubra essa chave por meio de um ataque de força bruta.
Exemplo de código vulnerável:
const jwt = require('jsonwebtoken'); const payload = { id: 1, username: 'guest', roles: ['guest'] }; const token = jwt.sign(payload, '1234567890'); console.log(token);
Podemos utilizar o hashcat para o ataque de força bruta:
Com a chave de assinatura do JWT em mãos, é possível alterar qualquer dado contido na payload do token, comprometendo assim sua integridade.
Resolvendo desafio – Weak secret attack
Obtendo JWT:
Utilizando o hashcat para realizar o ataque de força bruta:
Com a chave de assinatura em mãos, podemos alterar os dados do token.
Alterando campo “admin” para “true”:
Acessando API utilizando token com permissões de admin:
Mitigando a vulnerabilidade – Weak Secret
Para mitigar a vulnerabilidade de “Weak Secret”, é necessário utilizar uma chave forte ou fazer o uso de algum algoritmo assimétrico. Dessa forma, evita-se que atacantes realizem ataques de força bruta contra o JWT.
None attack
Quando um sistema aceita JWTs com o algoritmo “None”, é possível enviar tokens sem o campo de assinatura, uma vez que esse algoritmo não realiza a validação da assinatura. Isso permite que um atacante autentique-se e escale privilégios dentro da aplicação, mesmo sem o conhecimento da chave utilizada para verificar a integridade do token.
Para uma aplicação estar vulnerável a “None attack”, ela precisa de três requisitos:
- Permitir com que o usuário controle o algoritmo utilizado na verificação do token
- Aceitar o algoritmo “None”
- Não utilizar nenhuma secret durante a verificação do token ou utilizar um valor “undefined”.
Exemplo de código vulnerável:
app.get('/none-attack', async(req,res) => { let secret; const token = req.headers['authorization']; if(!token) { return res.sendStatus(401); } try { const { header } = jwt.decode(token, { complete: true }); const alg = header.alg; if(alg.startsWith('HS')) { secret = "s1m3tr1c_s3cr3t_k333y" } if(alg.startsWith('RS')) { secret = fs.readFileSync('./keys/public.pem'); } const payload = jwt.verify(token, secret, { algorithms: [alg] }) if(payload.admin) { return res.json({ message: 'Challenge completed' }); } return res.json(payload); } catch(e) { return res.sendStatus(500); } });
Ao analisar o código-fonte acima, observa-se que ele utiliza o algoritmo especificado no token durante o processo de validação da assinatura. No entanto, há um erro lógico no código: se o algoritmo definido pelo usuário não começar com “HS” ou “RS”, a variável secret permanecerá sem valor, ou seja, ficará “undefined”. Além disso, a biblioteca “jsonwebtoken” aceita, por padrão, o algoritmo “none”, o que completa os três requisitos necessários para que a aplicação fique vulnerável a um “None attack”.
Resolvendo desafio – None attack
Para explorar a vulnerabilidade do “None attack”, é necessário criar um token JWT utilizando o algoritmo “None” e omitir o campo de assinatura.
Infelizmente, o jwt.io não oferece a opção “None” entre os algoritmos disponíveis, o que nos obriga a gerar o token manualmente. Para isso, podemos utilizar o Bash para gerar o token “malicioso”:
export PART1=$(echo -n '{"typ":"JWT","alg":"none"}' | base64 -w0) export PART2=$(echo -n '{"username":"admin","admin":true}' | base64 -w0) echo "$PART1.$PART2."
JWT Hunter – A ferramenta
Para simplificar o processo durante pentests e operações de red team, desenvolvemos uma ferramenta web que gera tokens com as payloads necessárias para realizar ataques.
Utilizando o jwthunter.io, é possível forjar facilmente um JWT contendo a payload para o “None attack”.
Mitigando a vulnerabilidade – None attack
Para mitigar o “None attack”, é fundamental impedir que o usuário controle o algoritmo utilizado no processo de verificação da assinatura do token. Além disso, é crucial garantir que a chave utilizada na verificação do token tenha um valor definido.
KID Header injection
O cabeçalho “kid” é comumente utilizado para especificar o “id” da chave que será utilizada na verificação da assinatura do token.
Aplicações de grande escala frequentemente utilizam esse cabeçalho, uma vez que podem possuir diversos endpoints que, por questões de segurança, utilizam tokens associados a diferentes chaves.
A duas principais maneiras das aplicações obterem a chave secreta ou chave RSA através do “KID” é:
- Buscando a chave secreta no disco do servidor
- Buscando a chave secreta no banco de dados
Fluxo de verificação do JWT utilizando cabeçalho “KID”:
Database
Storage
Ataques no cabeçalho “KID”
Em cenários onde a aplicação busca a chave com base no “kid” diretamente no sistema de arquivos, é possível explorar vulnerabilidades de path traversal. Dessa forma, podemos especificar outros arquivos cujo conteúdo seja conhecido, permitindo assinar o JWT sem a necessidade de conhecer qualquer chave secreta armazenada no servidor.
Em cenários em que a aplicação busca a chave com base no “kid” diretamente no banco de dados, é possível explorar vulnerabilidades de SQL Injection. Isso permite manipular a resposta do banco de dados ou até mesmo extrair as chaves secretas armazenadas nele.
Path traversal no cabeçalho “KID”
Como mencionado anteriormente, se a aplicação estiver vulnerável a path traversal no cabeçalho “kid”, é possível especificar arquivos cujo conteúdo conhecemos e utilizá-los como chave secreta para assinar o token.
No sistema de arquivos do Linux, existem alguns arquivos cujo conteúdo é conhecido:
- /proc/sys/kernel/randomize_va_space (seu valor é o número “2”)
- /proc/sys/kernel/timer_migration (seu valor é o número “1”)
Veja abaixo um exemplo de código que apresenta a vulnerabilidade de path traversal no cabeçalho “kid”:
app.get('/path-traversal', async(req,res) => { const token = req.headers['authorization']; if(!token) { return res.sendStatus(400); } try { const { header } = jwt.decode(token, { complete: true }); if(!header.kid) { return res.sendStatus(401); } // PATH TRAVERSAL HERE const publicKey = fs.readFileSync(__dirname + '/keys/' + header.kid); const payload = jwt.verify(token, publicKey, { algorithms: ['HS256'] }); if(payload.admin) { return res.json({ message: 'Challenge completed' }); } return res.json(payload); } catch(e) { return res.sendStatus(500); } })
Resolvendo desafio – KID Path traversal
Enviando o seguinte JWT, conseguimos nos autenticar na aplicação:
Ao enviar uma payload de path traversal no cabeçalho “kid”, conseguimos retroceder diretórios no sistema e especificar o arquivo “/proc/sys/kernel/randomize_va_space”. Dessa forma, podemos assinar o token com a chave secreta “2”. No entanto, há um detalhe importante: o conteúdo do arquivo é “2” seguido por uma quebra de linha.
Para assinarmos o token, vamos utilizar o “base64 encoding” na assinatura.
Observação: perceba a quebra de linha.
Enviando payload para a aplicação:
Resolvendo desafio utilizando JWT Hunter – KID Path traversal
Acessando o jwthunter.io, conseguimos resolver o desafio rapidamente, pois a ferramenta já adiciona automaticamente o cabeçalho “kid” com a payload e realiza a assinatura.
Mitigando vulnerabilidade – Path Traversal no cabeçalho “KID”
Para mitigar a vulnerabilidade, é essencial realizar uma verificação no cabeçalho “kid”, como a sanitização do mesmo, a fim de impedir que um usuário possa retroceder diretórios. Além disso, é recomendável implementar uma whitelist para restringir os “kid” aceitos.
SQL Injection no cabeçalho “KID”
Como mencionado anteriormente, se a aplicação obtém a chave secreta do banco de dados a partir do cabeçalho “kid”, ela pode estar vulnerável a SQL Injection.
Explorando essa vulnerabilidade, é possível extrair todas as informações armazenadas no banco de dados. Além disso, podemos manipular a resposta da query executada pela aplicação utilizando “UNION SELECT”, o que nos permite forjar uma chave secreta falsa e assinar o token com ela.
Veja abaixo um exemplo de código que apresenta a vulnerabilidade de sql injection no cabeçalho “kid”:
app.get('/sql-injection', async(req,res) => { const token = req.headers['authorization']; if(!token) { return res.sendStatus(401); } try { const { header } = jwt.decode(token, { complete: true }); if(!header.kid) { return res.sendStatus(401); } // SQL INJECTION HERE const [results, metadata] = await sequelize.query(`SELECT * FROM secrets WHERE uuid = '${header.kid}'`); if(results.length <= 0) { return res.sendStatus(401); } const secretKey = results[0].secret; const payload = jwt.verify(token, secretKey, { algorithms: ['HS256'] }); if(payload.admin) { return res.json({ message: 'Challenge completed' }); } return res.json(payload); } catch(e) { return res.sendStatus(500); } })
Como mencionado anteriormente, é possível extrair dados do banco de dados por meio de SQL Injection. No entanto, como este artigo se concentra em contornar o sistema de verificação da assinatura do token, apenas a técnica do “UNION SELECT” será abordada.
Antes de prosseguirmos com a exploração da vulnerabilidade, vamos analisar o funcionamento do “UNION SELECT”:
Observamos que o “UNION SELECT” adiciona um item ao resultado da query, permitindo a manipulação da resposta do banco de dados. Com isso, podemos forjar uma chave secreta “falsa” e utilizá-la na assinatura do JWT.
Resolvendo desafio – KID SQL Injection
Enviando o seguinte JWT, conseguimos nos autenticar na aplicação:
Ao enviar uma payload de SQL Injection no cabeçalho “kid”, conseguimos manipular a resposta da query utilizando “UNION SELECT” e forjar uma chave secreta “falsa”. Dessa forma, é possível alterar a payload do token e definir o valor “true” no campo “admin”.
Enviando token para a aplicação:
Infelizmente, a ferramenta JWT Hunter não pode nos auxiliar com esse tipo de ataque, pois ele é específico para cada cenário.
Mitigando vulnerabilidade – SQL Injection no cabeçalho “KID”
Para mitigar essa vulnerabilidade, é essencial sanitizar o valor do cabeçalho “kid”, impedindo que um atacante execute SQL Injection. Outra recomendação é implementar uma whitelist, controlando os valores permitidos nesse cabeçalho.
Criptografia assimétrica em JWTs
Antes de prosseguirmos com as próximas vulnerabilidades, é fundamental compreender o conceito de criptografia assimétrica.
A criptografia assimétrica utiliza um par de chaves: uma para criptografar e outra para descriptografar. Em cada par, temos uma chave privada e uma chave pública.
Quando criptografamos um valor utilizando a chave privada, a única forma de descriptografá-lo é com a chave pública, e vice-versa.
Veja abaixo uma imagem de exemplo:
Em cenários onde permitimos que o cliente realize a criptografia dos dados, geralmente a chave pública é enviada para ele, enquanto o servidor faz a descriptografia utilizando a chave privada. Um exemplo disso é o HTTPS: nesse protocolo, o cliente criptografa a requisição web usando a chave pública e a envia para o servidor, que descriptografa os dados com a chave privada, protegendo contra ataques de Man-in-the-Middle (MITM).
Em cenários onde não permitimos que o cliente realize a criptografia dos dados, a chave pública deve ser utilizada no servidor durante o processo de descriptografia. Dessa forma, o cliente só poderá criptografar os dados se estiver em posse da chave privada.
Dessa forma, ao utilizarmos criptografia assimétrica no JWT, devemos usar a chave pública para verificar a assinatura. Assim, o cliente só poderá assinar o token se estiver em posse da chave privada, o que, normalmente, não ocorre.
JKU Header
O cabeçalho “JKU” (JSON Key URL) é utilizado para especificar a URL de uma JSON Web Key (JWK). Um JSON Web Key (JWK) é uma lista de chaves RSA, geralmente chaves públicas, no formato JSON. Esse formato facilita a hospedagem das chaves em endpoints quando necessário, como no processo de verificação da assinatura de um JWT usando o cabeçalho “JKU”.
Veja o fluxo de uma aplicação quando o cabeçalho JKU é utilizado:
Basicamente, o fluxo funciona assim: o usuário envia o JWT para a aplicação, que busca o cabeçalho “JKU” no campo “header”. Em seguida, é feita uma requisição para a URL especificada nesse cabeçalho, e o JWK obtido na resposta é utilizado para validar a assinatura do JWT.
Exemplo de JWT com cabeçalho “JKU”:
Exemplo de chave pública em formato de JSON Web Key (JWK):
JKU Header Injection – O ataque
À primeira vista, muitas pessoas podem pensar em ataques de SSRF, já que a aplicação realiza uma requisição HTTP para a URL especificada no cabeçalho “JKU”. Isso permitiria especificar URLs de aplicações internas. No entanto, esse tipo de ataque seria extremamente limitado e dificilmente teria um impacto significativo.
O que muitos não consideram é que podemos gerar um par de chaves RSA, hospedar a chave pública em um JWK, especificar a URL desse JWK no cabeçalho “JKU” e, em seguida, usar a chave privada para assinar o JWT.
Observação: Se este ataque pareceu confuso e complexo, não se preocupe, pois ele realmente é! Recomendo que você releia a seção “Criptografia assimétrica em JWTs” e analise novamente o fluxo da aplicação demonstrado nas imagens acima.
Veja abaixo o fluxo do ataque de “JKU Header Injection”:
Exemplo de código vulnerável:
app.get('/jku-header', async(req,res) => { const token = req.headers['authorization']; if(!token) { return res.sendStatus(401); } try { const { header } = jwt.decode(token, { complete: true }); const jku = header.jku; // Step 2: Make HTTP request to JKU const jkuRequest = await fetch(jku); const jwks = await jkuRequest.json(); // Step 3: Extract RSA from JWK (using external library) const publicKey = jwkToPem(jwks[0]); // Step 4: Verify JWT using RSA extracted from JWK const payload = jwt.verify(token, publicKey, { algorithms: ['RS256'] }); if(payload.admin) { return res.json({ message: 'Challenge completed' }); } return res.json(payload); } catch(e) { return res.sendStatus(500); } });
Resolvendo desafio – JKU Header Injection
Os primeiros passos nesse desafio é criar o par de chaves, gerar um JWK derivado da chave pública e hospedá-lo.
Para gerar o par de chaves, podemos utilizar os seguintes comados:
openssl genrsa -out private.pem 2048 openssl rsa -in private.pem -outform PEM -pubout -out public.pem
Com o par de chaves em mãos, vamos gerar o JWK derivado da chave pública utilizando a ferramenta “pem-jwk”:
sudo npm install -g pem-jwk cat public.pem | pem-jwk > jwk.json
Observação: Ao analisar o código, vemos que ele baixa uma lista de JWK (conhecida como JWKS) e obtém o primeiro item dessa lista. Portanto, precisamos definir um array e inserir o JWK dentro desse array.
Hospedando JWK em um servidor web utilizando python3:
sudo python3 -m http.server 80
No último passo, devemos criar um JWT com o cabeçalho “JKU” que especifica a URL do JWK hospedado em nosso servidor e assinar o token utilizando a chave privada.
Enviando requisição utilizando o JWT malicioso:
Curiosidade: Se voltarmos ao terminal onde nosso servidor web está em execução, veremos que recebemos uma requisição HTTP proveniente do servidor onde a aplicação alvo está hospedada.
Infelizmente, no jwthunter.io não há uma funcionalidade para explorar essa vulnerabilidade de forma “automática”. No entanto, futuramente lançaremos novas funcionalidades, e a exploração de JKU Header Injection será uma delas!
Mitigando a vulnerabilidade – JKU Header Injection
Para mitigar essa vulnerabilidade, basta criar uma whitelist de domínios e endpoints confiáveis. Assim, um usuário ou atacante não poderá especificar outras URLs cujos domínios ou endpoints não sejam confiáveis.
Algorithm Confusion
Se você compreendeu bem a diferença entre criptografia simétrica (que utiliza uma chave secreta) e criptografia assimétrica (que utiliza um par de chaves), entenderá melhor este ataque.
A vulnerabilidade de “Algorithm Confusion” ocorre quando a aplicação espera que o JWT utilize um algoritmo de criptografia assimétrica, mas ao invés disso, um algoritmo de criptografia simétrica é usado.
Como vimos anteriormente, quando a aplicação utiliza criptografia assimétrica, a verificação da assinatura é feita com a chave pública (caso não tenha entendido, releia a seção “Criptografia Assimétrica”). Se conseguirmos enviar um JWT com um algoritmo de criptografia simétrica, podemos assiná-lo usando a chave pública ao invés da chave privada, já que a criptografia simétrica requer que as chaves sejam idênticas.
Fluxo esperado pela aplicação:
Fluxo do ataque de Algorithm Confusion:
Você deve estar se perguntando: como ter acesso à chave pública?
Muitas aplicações disponibilizam suas chaves públicas em formato JWK nos endpoints de API (como vimos no ataque “JKU Header Injection”), o que permite obter essas chaves públicas com facilidade para realizar o ataque de “Algorithm Confusion”.
Veja abaixo os requisitos para uma aplicação estar vulnerável ao ataque de “Algorithm Confusion”:
- A aplicação espera um JWT com algoritmo de criptografia assimétrica.
- O sistema permite que o usuário controle o algoritmo utilizado na validação do JWT.
Exemplo de código vulnerável:
app.get('/algorithm-confusion', async(req,res) => { const token = req.headers['authorization']; if(!token) { return res.sendStatus(401); } try { const { header } = jwt.decode(token, { complete: true }); // JKU Header injection patch const jku_whitelist = ['localhost']; const jku_url = new URL(header.jku); if(!jku_whitelist.includes(jku_url.hostname)) { return res.sendStatus(401); } // Downloading remote JWK const request = await fetch(header.jku); const jwk = (await request.json())[0]; // Extract public key from JWK const publicKey = jwkToPem(jwk) // Verify JWT using public key const payload = jwt.verify(token, publicKey, { algorithms: [header.alg] }); if(payload.admin) { return res.json({ message: 'Challenge completed' }); } return res.json(payload); } catch(e) { return res.sendStatus(500); } });
Resolvendo desafio – Algorithm Confusion
Ao enviar o seguinte JWT, conseguimos nos autenticar na aplicação:
O primeiro passo deste ataque é obter a chave pública utilizada para verificar a assinatura do JWT. Analisando o código, notamos que ele obtém a chave pública de um JWK (não está vulnerável a JKU Header Injection). Portanto, podemos baixar esse JWK e extrair a chave pública dele.
Para essa etapa, podemos criar um código JavaScript que utiliza a função fetch para fazer o download do JWK e a biblioteca “jwk-to-pem” para extrair a chave pública.
(async () => { const jwkToPem = require('jwk-to-pem'); const request = await fetch('http://localhost:8000/jwks.json'); const jwk = (await request.json())[0]; const publicKey = jwkToPem(jwk); console.log(publicKey); })();
Com a chave pública em mãos, podemos criar um JWT utilizando um algoritmo simétrico, como o “HS256”, e assinar o token usando a chave pública como se fosse uma chave secreta.
Primeiro, vamos fazer a codificação em Base64 da chave pública (isso é necessário para garantir que todos os caracteres, incluindo espaços e quebras de linha, sejam incluídos):
Com a chave pública em Base64, podemos assinar nosso JWT utilizando um algoritmo de criptografia simétrica (H256):
Enviando esse JWT para a aplicação, conseguimos solucionar o desafio:
Resolvendo desafio utilizando JWT Hunter – Algorithm Confusion
Como esse ataque envolve etapas complexas, como converter um JWK para uma chave pública e assinar o token com essa chave, desenvolvemos uma funcionalidade no jwthunter.io para realizar esse ataque de forma “automática”.
Criando JWT malicioso utilizando JWT Hunter:
Observação: Caso você não tenha o JWK, mas apenas a chave pública, pode desmarcar a opção “Use JWK to sign token” e colar a chave pública no mesmo campo de texto.
Implementação de segurança na biblioteca “jsonwebtoken”
No dia 21 de dezembro de 2022, os desenvolvedores da biblioteca “jsonwebtoken” implementaram uma nova camada de segurança contra o ataque de “Algorithm Confusion”. Essa implementação impede que um JWT seja assinado ou verificado utilizando uma chave PEM quando seu algoritmo é de criptografia simétrica. Essa alteração foi realizada na versão “9.0.0”.
Observação: No laboratório de Algorithm Confusion foi utilizado a biblioteca “jsonwebtoken” na versão “8.5.1”.
Mitigando a vulnerabilidade – Algorithm Confusion
Para mitigar essa vulnerabilidade, é necessário definir o algoritmo utilizado durante o processo de validação da assinatura do JWT diretamente no código, evitando que o usuário tenha controle sobre isso. Além disso, é importante manter as bibliotecas atualizadas para suas últimas versões estáveis.
Conclusão
Neste artigo, vimos que existem diversas vulnerabilidades em JWTs; no entanto, a maioria delas decorre da má manipulação dos dados obtidos dos cabeçalhos. Portanto, mesmo que você utilize a melhor biblioteca do mundo, a mais segura, ainda pode estar vulnerável a ataques como KID Header Injection, JKU Header Injection, entre outros, devido à má manipulação dos dados na aplicação.
Referências
-
- https://portswigger.net/web-security/jwt
- https://owasp.org/www-project-web-security-testing-guide/latest/4-Web_Application_Security_Testing/06-Session_Management_Testing/10-Testing_JSON_Web_Tokens
- https://portswigger.net/web-security/jwt/lab-jwt-authentication-bypass-via-jku-header-injection
- https://jwthunter.io/
- https://github.com/hakaioffsec/jwt-vulnerabilities-lab