Análise de ameaças de autenticação corrompida de usuário para tokens JSON Web
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.
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:
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)
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).
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.
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.
Na última parte da verificação, um erro de projeção na comparação pode ocorrer por um de dois motivos (ou ambos):
O cabeçalho e a carga útil foram editados, mas a assinatura não foi
Há uma configuração incorreta do algoritmo correto ou da chave certa
A Figura 9 mostra um ataque de 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.