Precisa de computação em nuvem? Comece agora mesmo

Análise de ameaças de autenticação corrompida de usuário para tokens JSON Web

Nitzan Namer

escrito por

Nitzan Namer

June 07, 2023

Nitzan Namer

escrito por

Nitzan Namer

Nitzan Namer é pesquisador de segurança da Akamai.

O controle de contas, o escalonamento de privilégios e os vazamentos de dados são três grandes riscos potenciais que os usuários e organizações de JWT enfrentam ao escolher um JWT como token de API.

Resumo executivo

  • Os pesquisadores da Akamai analisaram os tokens JSON Web (JWTs) como um vetor para ataques de autenticação corrompida de usuário, que está no Top 10 em Segurança de APIs do Open Web Application Security Project (OWASP)e descobriram diferentes cenários em que ocorrem ameaças e tendências de JWT. 

  • JWTs são responsáveis por proteger APIs emitindo tokens (geralmente entre clientes e servidores) para verificar os usuários com segurança. Esses tokens são um dos formatos de verificação mais comuns usados e contêm informações a serem compartilhadas na forma de objetos JSON.  

  • Embora o token não seja criptografado, é codificado e tem uma assinatura de verificação. Examinamos algumas das muitas ameaças aos JWTs devido à implementação inadequada ou a chaves secretas curtas e de baixa entropia.  

  • O controle de contas, o escalonamento de privilégios e os vazamentos de dados são três grandes riscos potenciais que os usuários e organizações de JWT enfrentam ao escolher um JWT como token de API. Observamos em nosso tráfego que a maioria dos JWTs usa um algoritmo simétrico, embora seja, teoricamente, menos seguro.

  • Nesta postagem, oferecemos práticas recomendadas sobre como lidar com essas ameaças de JWT.

Introdução

JWTs são um esquema de token amplamente empregado e relativamente fácil de executar, o que oculta muitos riscos. Esses riscos devem ser considerados na implementação e proteção de JWTs. Um dos riscos mais proeminentes para JWTs, que aparece no OWASP API Security Top 10é a autenticação corrompida de usuário. 

A autenticação corrompida de usuário ocorre quando uma API não verifica corretamente as credenciais e a identidade do usuário que está fazendo a solicitação. Infelizmente, essa é uma vulnerabilidade comum em JWTs e pode permitir que um invasor se passe por outra pessoa ou acesse a conta de outro usuário, causando o escalonamento de privilégios e vazamentos de dados.

Proteção do pipeline

Um JWT é um token de autenticação comumente usado em APIs e aplicativos da Web. Observamos em nosso tráfego que os aplicativos da Web estão adotando mais APIs e expondo-as ao cliente, aumentando a necessidade de uma autenticação contínua em diferentes pontos de extremidade da API. 

A API é o principal pipeline de uma organização, mantendo mecanismos de autenticação e autorização, consultando bancos de dados e expondo a maioria das funções da organização. Por isso, as ameaças de JWT são mais perigosas no campo da API. Nesta postagem do blog, apresentaremos os fundamentos dos JWTs, seis ameaças de JWTs e como lidar com essas ameaças.

Os fundamentos dos JWTs

JWT É um formato usado no envio de dados JSON assinados para transmitir dados em aplicativos da Web, aplicativos móveis e APIs, principalmente para autenticação somente. A estrutura do JWT consiste em três elementos: o cabeçalho (também conhecido como cabeçalho JOSE), a carga útil e a assinatura, todos separados por um ponto (Figura 1).

  eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiIiLCJpYXQiOjE2NzYyMTc5NTAsImV4cCI6MTcwNzc1Mzk1MCwiYXVkIjoiYWthbWFpLWJsb2ciLCJzdWIiOiIiLCJjb21wYW55IjoiQWthbWFpIiwidXNlciI6IkFrYW1haS1yZWFkZXIiLCJhZG1pbiI6Im5vIn0.kMPz3Z7BSlBTJKijD8bcrpzTZejX7VCZ77w5oQwJO6I

Fig. 1: Este é um exemplo dos três elementos de uma estrutura de JWT

Cabeçalho e carga útil

Tanto o cabeçalho quanto a carga útil são recomendações de campos Base64, seguros para URL, codificados e especificados pela IETF (Figura 2). "Codificado" significa que não são legíveis diretamente pelo olho humano, mas são facilmente decodificados pelo servidor. O objetivo é garantir a integridade e a usabilidade dos dados, mantendo-os "seguros para URL". Dessa forma, não haverá os caracteres sobrepostos que são usados por navegadores da Web.

O cabeçalho JOSE é usado para criptografia da Web JWT e JSON (JWE), que é basicamente um JWT criptografado que ajuda a evitar os ataques de JWT mais comuns. O campo que especifica o método de token escolhido é “typ” (typ:JWT/JWE). A carga útil pode conter campos registrados (reivindicados pela Internet Assigned Numbers Authority) ou campos personalizados, dependendo da implementação.

O cabeçalho JOSE é usado para criptografia da Web JWT e JSON (JWE)

Fig. 2: JWT codificado

Assinatura

O objetivo da assinatura é verificar o token, o que significa que o servidor forjou o token e os dados não foram alterados desde que o token foi criado.

Há duas etapas principais na criação de uma assinatura:

  1. Aplicar um algoritmo de criptografia (por exemplo, MAC) no cabeçalho e na carga útil, separado por um ponto (o algoritmo está usando uma chave secreta)

  2. Aplicar um algoritmo de hash (por exemplo, SHA256) no cabeçalho criptografado e na carga útil

Quando um JWT é usado, o servidor verifica a assinatura para validar o próprio token. (Mais adiante neste post, explicaremos os diferentes algoritmos usados para validação.)

JWTs são amplamente empregados na autenticação de aplicativos da Web, devido à facilidade de uso (inclusive em larga escala), facilidade de implementação e porque os dados necessários do servidor são salvos no lado do cliente. Mas há riscos associados aos JWTs, mesmo que estejam assinados. Um JWT usa texto sem formatação e cada implementação consiste em diferentes campos de carga útil. Assim, há uma ampla superfície para ataque e muito espaço para erros.

Ao explorar algumas das ameaças mais comuns e interessantes que os JWTs enfrentam, ficamos mais cientes das vulnerabilidades, detectamos comportamentos mal-intencionados com mais facilidade, reduzimos melhor os riscos e preparamos medidas de segurança necessárias para proteção contra possíveis incursões. 

Nosso objetivo é proporcionar aos usuários uma abordagem mais segura do trabalho com JWTs e oferecer aos profissionais e administradores de segurança as ferramentas e recomendações necessárias para nos requisitos de "due diligence". 

Seis ameaças de JWTs

1. Permitir que o servidor use um token sem validação

Como um JWT é assinado em vez de criptografado, uma validação deve ser feita antes de qualquer uso. No cenário de ameaça mais básico, no qual um aplicativo não é validado, um invasor pode editar a carga útil (por exemplo, escalonamento de privilégio) e manter a assinatura intacta, ou até mesmo excluí-la e obter permissões mais altas.

Outro método é usar o parâmetro "alg" no cabeçalho, que representa o algoritmo que foi usado para assinar o token. "None" é um valor legítimo (e o JWT é chamado de JWT não seguro), para que qualquer pessoa possa assinar facilmente o token. No back-end, também existe uma possível implementação da verificação do JWT.

Comece essa abordagem procurando o campo "alg" no cabeçalho. Depois disso, use o algoritmo especificado para verificar o token. O algoritmo "None" indica falta de necessidade de assinatura e verificação para esse token. Editar a carga útil do token, o cabeçalho (para alg:none) e a "autoassinatura" (excluindo a assinatura) levará a um ataque bem-sucedido.

Exemplo

A Figura 3 mostra um exemplo de JWT decodificado.

  eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYW1lIjoiZXhhbXBsZSBuYW1lIiwiaWF0Ij 
  oxNjU5MjM5MDIyfQ.PrhAp2DUWXoL01_odyLATuzrwn5rMtY1IVsP8y4LH5E
  decoded:
{
  "alg": "HS256",
  "typ": "JWT"
}
.{
  "name": "example name",
  "iat": 1659239022
}

Fig. 3: Exemplo de JWT decodificado

Presumimos que o ponto de extremidade da API usa o campo "alg" na carga útil como sendo o algoritmo escolhido para verificação.

Mas gostaríamos de editar o JWT (Figura 4). Dessa forma, conseguimos forjar um JWT válido de outro usuário.

  eyJhbGciOiJub25lIiwidHlwIjoiSldUIn0.eyJuYW1lIjoiZXhhbXBsZSBuYW1lIiwiaWF0Ijo 
  xNjU5MjM5MDIyfQ.
  decoded:
{
  "alg": "none",
  "typ": "JWT"
}
.{
  "name": "other person's name",
  "iat": 1659239022
}

Fig. 4: JWT editado para explorar alg:none.

Prática recomendada: Esta é simples: Sempre valide usando um algoritmo predefinido codificado antes de usar o token. Não aponte o parâmetro alg para o algoritmo de verificação.

2. Usar a mesma chave privada para diferentes aplicativos

Há muitas empresas que optam por ter registro separado para diferentes aplicativos. Usar a mesma chave privada criará um token válido em ambos os aplicativos, mas com um ID de usuário diferente. Nesse caso, basta fazer uma solicitação para um segundo aplicativo com o token do primeiro aplicativo e assumir o controle de uma conta (não de sua escolha) (Figura 5).

Usando a captura de tela do JWT de um segundo aplicativo Fig. 5: Uso do JWT de um segundo aplicativo em outro aplicativo, resultando em uma aquisição de conta

Prática recomendada: Esta é outra regra prática simples: Ao separar IDs de usuário, use chaves privadas diferentes.

 3. Usar um algoritmo de assinatura fraco

Existem duas famílias principais de algoritmos: simétrico (HSXXX) e assimétrico (RSXXX,ESXXX,PSXXX). Um algoritmo simétrico requer um segredo compartilhado; um algoritmo assimétrico requer chaves privadas e públicas (Tabela 1).

Simétrico

HSXXX

HMAC + SHA

Algoritmo relativamente fraco

Usa segredo compartilhado

Assimétrico

RSXXX

RSA + SHA

Algoritmo mais seguro

Usa chaves privadas e públicas

ESXXX

ECDSA + SHA

O algoritmo mais seguro dos três

Usa chaves privadas e públicas

Tabela 1: As duas principais famílias de algoritmos

Do ponto de vista do invasor, usar um algoritmo simétrico é mais fácil do que usar força bruta, pois não há necessidade de coletar chaves públicas e o tempo de computação é o mais eficiente possível. Observamos em nosso tráfego que algoritmos simétricos são mais amplamente utilizados do que  algoritmos assimétricos (Figura 6).

Teoricamente, algoritmos simétricos exigem menos computação e, sendo assim, quando em grande escala, podem ter melhor desempenho do que algoritmos assimétricos.

Uma pesquisa de captura de tela de algoritmos de JWT Fig. 6: Uma pesquisa de algoritmos de JWT no tráfego da Akamai mostra que algoritmos simétricos são mais comuns

Prática recomendada: Use algoritmos assimétricos. Recomendamos o uso do algoritmo ECDSA, que é atualmente a opção mais segura (criptograficamente). Uma chave simétrica adequadamente protegida é aceitável se o segredo for de alta entropia e suficientemente longo.

4. Usar uma chave privada curta e/ou de baixa entropia

Uma chave privada curta e/ou de baixa entropia pode ser rompida por força bruta rapidamente e com baixo custo. Há software de "cracking" que pode ser instalado facilmente em ambientes de nuvem de alto desempenho com GPU (Graphics Processing Unit, unidade de processamento gráfico). O desempenho das GPUs vem crescendo rapidamente e tem um efeito sobre os recursos de "cracking". As placas gráficas de última geração processam rotinas de "cracking" quase 2,5 vezes mais rápido do que três anos atrás. 

Uma comparação entre quantos dias levaria para decifrar uma chave privada de oito caracteres (independentemente de sua entropia) há três anos e hoje é mostrada na Tabela 2.

Placa gráfica avançada


Dias para decifrar

Há três anos

10,5 dias

Hoje

4,5 dias

Tabela 2: Número de dias que levaria para decifrar uma chave privada de oito caracteres

Uma chave particular de sete caracteres, que levaria cerca de 24 horas para ser decifrada há alguns anos, pode ser decifrada em menos de 90 minutos. O que torna esse ataque singular é ser executado offline, sem nenhuma chance de defesa do lado da organização, ou mesmo qualquer conhecimento de que esteja havendo algum tipo de ataque. 

Imagine que você é um invasor trabalhando para um governo e que criaria um sistema orquestrado para esse fim. Manter a chave privada do JWT significa que o invasor pode forjar um token assinado e passar por qualquer outro usuário apenas sabendo seu ID.

Prática recomendada: Escolha uma chave privada longa (pelo menos 10 caracteres) e de alta entropia. Recomendamos usar a RSA como um gerador secreto.

5. Manter dados confidenciais em uma carga útil de JWT

JWTs são codificados em URL Base64 para que a carga útil não seja criptografada. Armazenar nomes de bancos de dados, IDs incrementais (de todos os tipos) ou quaisquer campos e dados internos do servidor cria exposição excessiva de dados, o que pode ajudar um invasor em outros vetores de ataque (por exemplo, autorização de nível de objeto quebrado).

Prática recomendada: Não armazene dados confidenciais em JWT. Se precisar armazenar dados confidenciais, use JWE.

6. Confundir as chaves

Com algoritmos assimétricos, uma chave privada é usada para forjar o JWT (a parte de assinatura) e uma chave pública é usada para validar o JWT. Um invasor pode alterar o algoritmo especificado no cabeçalho para um simétrico (por exemplo, HS256) e criar uma assinatura usando a chave pública que é legitimamente usada pelo servidor para verificação. 

Nesse cenário, um back-end não implementado corretamente usará a chave pública e executará o algoritmo simétrico (como o invasor especificado no cabeçalho) para verificar com êxito o JWT que foi forjado pelo invasor.

Exemplo

A Figura 7 mostra o processo de criação de um novo JWT pelo servidor e a Figura 8 ilustra o processo de verificação do JWT do servidor.

A Figura 7 mostra o processo do servidor de forjar um novo JWT Fig. 7: O processo para forjar um JWT no lado do servidor
A Figura 8 ilustra o processo de verificação do JWT do servidor Fig. 8: O processo de validação do JWT no lado do servidor

Na última parte da verificação, um erro de projeção na comparação pode ocorrer por um de dois  motivos (ou ambos): 

  1. O cabeçalho e a carga útil foram editados, mas a assinatura não foi 

  2. Há uma configuração incorreta do algoritmo correto ou da chave certa

A Figura 9 mostra um ataque de confusão de chaves.

Processo para forjar um JWT mal-intencionado Fig. 9: O processo de um invasor mal-intencionado para forjar um JWT com confusão de chaves

A etapa final: O servidor verificará o token com o processo ilustrado na Figura 8, no qual o servidor confia no campo alg. O servidor verificará o token executando o algoritmo HS256 com a chave pública como um segredo, que é exatamente o que o invasor planejou.

Prática recomendada: Use algoritmos predefinidos no processo de verificação e não confie na entrada do usuário.

Conclusão

JWT é o token de autenticação mais comum. Ele permite o uso de muitos aplicativos da Web e APIs enquanto está sendo autenticado, sem fazer login com frequência. No entanto, há muitas ameaças associadas aos JWTs, já que não são criptografados nem implementados com a segurança em mente. 

  • A potência dos computadores está evoluindo rapidamente, o que coloca em risco chaves secretas fracas, pois passam a ser quebradas em dias em dias em vez de anos. No caso de JWTs, esse tipo de ataque pode ser feito offline, sem o conhecimento da organização sobre os ataques. 

  • Algoritmos simétricos são o tipo mais comum de algoritmo, o que facilita a vida dos invasores. 

  • Também existem ameaças mais complexas, como ataques de autenticação, mas é difícil para os invasores automatizarem ataques de autenticação. No entanto, vetores de ataque de JWT simples podem ser automatizados e amplamente explorados.

Por essas razões (e muitas outras), é fundamental que os usuários estejam cientes das vulnerabilidades dos JWTs e das melhores práticas de segurança a serem implementadas na proteção contra possíveis invasões. Esperamos que esta análise sirva como um guia prático para proteger JWTs contra a autenticação corrompida do usuário, uma das 10 principais ameaças em segurança de APIs OWASP.



Nitzan Namer

escrito por

Nitzan Namer

June 07, 2023

Nitzan Namer

escrito por

Nitzan Namer

Nitzan Namer é pesquisador de segurança da Akamai.