Ao utilizar JWT em nossas APIs é necessário selecionar um algoritmo para emitir os tokens.

Existem várias opções de algoritmos de criptografia para assinar um JWT, pode ser simétrico ou assimétrico, probabilístico ou determinístico. Então vamos falar sobre como fazer?

gray key in person's palm

Ao gerar um JWT, é essencial especificar um algoritmo de criptografia. Veja um exemplo abaixo:

Além do RSA, também é possível utilizar chaves simétricas e ECDSA.

Para escolher o algoritmo adequado, é importante compreender onde cada um se aplica e suas características específicas.

Algoritmo

Um algoritmo de criptografia pode ser comparado a uma fórmula matemática, consiste em um conjunto de procedimentos matemáticos. Através dessa fórmula, temos a capacidade de transformar os dados em texto cifrado (Ciphertext). E só é possivel desfazer o CipherText para obter o conteúdo original através de uma chave que utilizamos no processo.

JWT com chave simétrica

Ao usar um algoritmo simétrico, uma única chave é utilizada tanto para criptografar quanto para descriptografar os dados. Nesse caso os envolvidos no processo de comunicação precisam possuir essa chave, seja para ler as informações ou criar um novo texto criptografado.

symmetric-encryption-1

HMAC

Hash-Based Message Authentication Codes (HMACs) são um grupo de algoritmos que utilizam uma chave simétrica para assinar mensagens. A segurança desses algoritmos está diretamente relacionada à função hash utilizada, como, por exemplo, SHA256.

Quando utilizar uma chave simétrica?

O uso de chaves simétricas é recomendado apenas em cenários onde haverá uma única API. Isso porque outras APIs não poderão validar o JWT a menos que a chave privada seja compartilhada entre elas.

Em equipes pequenas, esse risco pode ser tolerável. Porém, em equipes médias e grandes, isso representa uma potencial brecha de segurança, pois qualquer equipe que tenha acesso à chave privada pode gerar tokens e se passar por outros usuários, obtendo acessos privilegiados nas APIs.

O desafio, no fim das contas, é garantir que a chave seja devidamente armazenada e compartilhada apenas entre entidades confiáveis.

Gerando uma chave simétrica HMAC

Ao gerar uma chave simétrica, é importante se questionar: apenas uma API irá gerar o JWT ou mais serviços terão esse direito? (Não há problema se essa estratégia mudar no futuro).

Por que essa pergunta é importante? Porque o tamanho dos bytes da chave importa. Há recomendações específicas sobre o tamanho da chave.

O NIST publicou um documento Recommendation for Applications Using Approved Hash Algorithms, Security Effect of the HMAC Key Section - 5.3.4 que fornece orientações sobre o tamanho da chave e o algoritmo a ser utilizado.

"alg" Algoritmo Key Size
HS256 HMAC using SHA-256 64 bytes
HS384 HMAC using SHA-384 128 bytes
HS512 HMAC using SHA-512 128 bytes

Assim como o NIST, a própria Microsoft reforça a importância do tamanho da chave. Links para mais informações estão disponíveis ao final.

Com esse conhecimento, é possível gerar uma chave automaticamente usando componentes do .NET. Dessa forma, uma única API pode armazenar a chave em um local seguro e recuperá-la sempre que for necessário assinar um JWT. Isso garante segurança, pois se o registro for removido, uma nova chave aleatória será gerada.

Esse método adiciona uma camada extra de burocracia, pois compartilhar a chave significa compartilhar o JWK, seja por meio de um arquivo físico ou de um banco de dados.

No exemplo acima, quero destacar a utilização do objeto System.Security.Cryptography.RandomNumberGenerator para a geração da chave.

No entanto, essa implementação possui um problema: caso a aplicação seja reiniciada, as chaves serão renovadas, invalidando os tokens gerados anteriormente.

Para resolver esse problema, o objeto JsonWebKey pode ser utilizado para salvar os parâmetros da criptografia. Assim, caso a aplicação seja reiniciada, basta verificar se esse objeto existe e reutilizar a chave criada anteriormente. Caso contrário, cria uma nova chave.

JWT com chave assimétrica

Um algoritmo assimétrico envolve duas chaves: uma chave pública e uma chave privada. A chave privada é utilizada para assinar digitalmente a mensagem, enquanto a chave pública é usada para verificar a autenticidade dessa assinatura.

asymmetric-encryption-1

A RFC 7518 define os algoritmos RSA e ECDsa para assinatura de JWTs. Existem várias variações desses algoritmos. Os exemplos a seguir utilizam as mais recomendadas pela RFC 7518

RSA

RSA é o acrônimo de Rivest–Shamir–Adleman, um método de criptografia criado em 1977 que revolucionou ao introduzir o conceito de chaves assimétricas. Antes disso, todos os modelos de criptografia utilizavam a mesma chave para criptografar e descriptografar as mensagens.

RSA é amplamente utilizado para criar assinaturas digitais. Somente o proprietário da chave privada pode assinar uma mensagem, enquanto a chave pública permite que qualquer entidade verifique a validade dessa assinatura.

A segurança do RSA recae sobre o fato de não haver nenhuma maneira eficiente de fatorar grandes números. Qualquer método atual recae sobre alguma forma de Tentative and Error.

Elliptic Curves - ECDsa

De maneira pratica as Curvas Elipticas são mais eficiente que o RSA. No entanto isso não significa que é mais segura. Diferente do RSA a segurança das curvas elipticas recae no problema do logaritmo discreto.

Seja RSA ou EC, tentar quebrar a chave é necessário recorrer a métodos de brute force. E quando o assunto é criptografia, qualquer solução de brute force nem é considerado uma opção viável. Já que fazer um brute force hoje em uma RSA com o computador mais rápido do mundo levará alguns milhares de anos.

Quando utilizar chave assimétrica?

A melhor resposta é: Sempre que possível. No entanto, em ambientes com uma única API, a simplicidade de um algoritmo simétrico já é o suficiente.

No entanto, se você já está armazenando a chave (JWK) em um local seguro, como um sistema de arquivos, banco de dados ou blob, a utilização de chaves assimétricas adicionará um nível extra de segurança.

Todo sistema que implementa o protocolo OAuth 2.0 faz o uso de chaves assimétricas, uma vez que devido a natureza de seu propósito não faria nenhum sentido ser diferente disso.

Gerando RSASSA-PSS using SHA-256 and MGF1 with SHA-256

Considere o seguinte código:

O tamanho 2048 é o mínimo especificado pela RFC 7518 - seção 3.5.

O uso do RSA com .NET é bastante simples. Utilizando a mesma técnica do exemplo anterior, é possível salvar os dados da chave criada e recarregar a mesma chave quando a aplicação reiniciar.

Simples, não?

Gerando ECDSA using P-256 and SHA-256

Esse é o algoritmo mais recomendado pela RFC para assinar seu JWT. Assim como o RSA, sua utilização é simples.

A curva NIST P-256 é especificada na própria RFC, por isso está sendo utilizada.

Referências

💡
Podemos te ajudar com uma revisão 100% gratuita do seu ambiente cloud.
Share this post