JSON Web Tokens (JWTs) podem ser assinados usando muitos algoritmos diferentes: RS256, PS512, ES384, HS1; você pode ver por que alguns desenvolvedores coçam a cabeça quando perguntados qual eles gostariam de usar.

Na minha experiência, muitos dos principais provedores de identidade historicamente só ofereceram RS256 ou pelo menos padrão para ele. No entanto, graças a iniciativas como o Open Banking, esses provedores de identidade estão agora expandindo seu suporte para cobrir mais algoritmos de assinatura, o que significa que você precisará começar a entender quais usar.

Não sou criptógrafo, mas através do meu trabalho com o OpenID Connect e o FIDO2, ganhei a compreensão de um praticante sobre os vários algoritmos de assinatura e os sentimentos gerais das comunidades de criptografia em relação a cada um. Neste artigo, vou armar um pouco desse conhecimento para que você possa entender o que cada valor “alg” significa e escolher o melhor algoritmo de assinatura disponível para você.

EdDSA > ECDSA ou RSASSA-PSS > RSASSA-PKCS1-v1_5 e sabem o que esperar.

Valores do algoritmo (alg)

Antes de olharmos para cada família de algoritmos de assinatura, vamos primeiro esclarecer o que queremos dizer com valores “alg” como rs256. Estes são JSON Web Algorithms (JWA), que fazem parte da família JavaScript Object Signing and Encryption (JOSE). Você verá valores “alg” em cabeçalhos JWT, dizendo-lhe como o JWT foi assinado, e em JSON Web Keys (JWK), dizendo para que algoritmo uma chave é usada.

Como regra geral, um valor “alg” pode ser discriminado como:

RS | 256

algoritmo de assinatura | algoritmo de hashing

  • Família de algoritmos de assinatura: Neste caso, RS significa RSASSA-PKCS1-v1_5.
  • Algoritmo de hashing usado pelo algoritmo de assinatura. Neste caso, 256 significa SHA-256.

A maioria dos algoritmos de assinatura tem variantes para SHA-256, SHA-384 e SHA-512. Em alguns casos, você pode até ter algo como “RS1”, que usa sha-1 🤢 e é necessário para conformidade FIDO2.

Esses algoritmos são tipicamente definidos em RFC 7518,mas você pode encontrar uma lista completa de algoritmos suportados no registro JOSE IANA.

Qual algoritmo de hashing devo usar?

SHA-256, SHA-384 e SHA-512 são todas variações da mesma família de algoritmos de hash: SHA-2.

Como regra geral, o número em um algoritmo refere-se ao tamanho do hash que ele irá gerar. Por exemplo, o SHA-256 produzirá um hash de 256 bits, enquanto o SHA-512 produzirá um hash de 512 bits.

O nível de segurança que cada um lhe dá é de 50% do seu tamanho de saída, então o SHA-256 fornecerá 128 bits de segurança, e o SHA-512 fornecerá 256 bits de segurança. Isso significa que um invasor terá que gerar 2^128 hashes antes de começar a encontrar colisões, graças ao limite de aniversário. É por isso que usamos um mínimo de segurança de 128 bits.

Você não vai precisar de nada melhor do que sha-256 tão cedo. Só não use SHA-1.

Validação: Conheça seu Algoritmo

Todos os aplicativos que validam assinaturas JWT devem saber com antecedência quais algoritmos esperar e exatamente qual chave usar. Você pode fazer isso atribuindo cada chave pública a um algoritmo (por exemplo, esta chave é para RS384, esta para ES256). Quando você tem muitas teclas para um único algoritmo, você pode usar o ID chave () em um cabeçalho JWT para entender qual usar. kid

Basicamente, você quer ter certeza de que os valores em um JWT correspondem ao que você espera. Se eles não correspondem, então alguém não está a par. kidalg

{
    "typ": "JWT",
    "kid": "123", // is this key...
    "alg": "RS256" // ...allowed to be used for this algorithm?
}

Protocolos como o OpenID Connect facilitam isso usando um documento de descoberta e um JSON Web Key Set (JWKS) disponível em um ponto final protegido pelo TLS.

Hoje em dia, você não deve confiar no valor “alg” apenas no cabeçalho JWT, nem deve aceitar JWTs com um algoritmo de “nenhum” ou JWTs com uma chave pública embutida em seu cabeçalho.

RSASSA-PKCS1-v1_5 (por exemplo, RS256)

RS256 = RSASSA-PKCS1-v1_5 usando SHA-256

Embora o RSAES-PKCS1-v1_5 não seja mais seguro para criptografia, o RSASSA-PKCS1-v1_5 ainda é adequado para assinaturas digitais. Como mencionei anteriormente, na minha experiência, o RS256 tem sido historicamente o padrão para a maioria das implementações de JWT,com muitos provedores de identidade SaaS oferecendo apenas este algoritmo de assinatura. É difícil encontrar um sistema que não suporte JWTs assinado com RS256.

JWTs assinados com RSASSA-PKCS1-v1_5 têm uma assinatura determinística, o que significa que o mesmo cabeçalho & carga JWT sempre gerará a mesma assinatura.

RSASSA-PKCS1-v1_5 existe há muito tempo, mas hoje em dia, você geralmente deve preferir RSASSA-PSS (RSA com uma assinatura probabilística). Isso não quer dizer que o RSASSA-PKCS1-v1_5 esteja quebrado, mas sim que o RSASSA-PSS simplesmente tenha características desejáveis que o outro não tem. Na verdade, o RFC 8017 agora considera o RSASSA-PSS um requisito ao usar o RSA para assinar:

“Embora nenhum ataque seja conhecido contra o RSASSA-PKCS1-v1_5, no interesse de maior robustez, o RSASSA-PSS é necessário em novas aplicações.”

Dito isto, ao discutir os ataques de Bleichenbacher contra os padrões de criptografia e assinatura RSA PKCS#1, David Wong em Criptografia de Palavras Reais compartilha uma estatística interessante:

Ao contrário do primeiro ataque que quebrou completamente o algoritmo de criptografia, o segundo ataque é um ataque de implementação [contra a validação de assinaturas]. Isso significa que se o esquema de assinatura for implementado corretamente (de acordo com a especificação), o ataque não funciona.

No entanto, foi demonstrado em 2019 que muitas implementações de código aberto do RSA PKCS #1 v1.5 para assinaturas realmente caíram nessa armadilha e implementaram mal o padrão, o que permitiu que diferentes variantes do ataque de falsificação de Bleichenbacher funcionassem!

Criptografia do Mundo Real

Uma vez que os ataques são contra a validação de assinatura, você terá que estar confiante de que todos os destinatários que validam seus JWTs estão usando uma biblioteca que não é vulnerável ao ataque de Bleichenbacher. Isso seria difícil se você está lidando com muitos terceiros.

O trabalho em torno do Open Banking, como a API de nível financeiro (FAPI) da OpenID, não permite o uso do RSASSA-PKCS1-v1_5. Para meus leitores regulares, este era o único algoritmo disponível no IdentityServer até o IdentityServer4 versão 3.

Leitura suplementar

RSASSA-PSS (por exemplo, PS256)

PS256 = RSASSA-PSS usando SHA-256 com MGF1 com SHA-256

RSASSA-PSS é a versão probabilística do RSA, onde o mesmo cabeçalho JWT e carga útil gerarão uma assinatura diferente a cada vez. Ao contrário de outros algoritmos, isso é probabilístico de uma maneira boa; embora um valor aleatório possa ser usado durante a geração de assinaturas, ele não é fundamental para a segurança. Em geral, é muito mais simples de implementar e, portanto, mais difícil de errar.

Se você quiser usar uma chave RSA, então é recomendável que você use RSASSA-PSS em v1_5 RSASSA-PKCS1, mas felizmente uma chave RSA pode ser usada para qualquer esquema de assinatura. O comprimento da assinatura também é idêntico entre os dois.

O Open Banking do Reino Unido inicialmente determinou o uso do PS256, mas mais tarde abriu-o para o ES256.

Leitura suplementar

ECDSA (por exemplo, ES256)

ES256 = ECDSA usando P-256 e SHA-256

No caso dos Algoritmos de Assinatura Digital da Curva Elíptica (ECDSA), o número no ES256 que se refere ao algoritmo de hashing também se relaciona com a curva. ES256 usa P-256 (secp256r1, também conhecido como prime256v1), ES384 usa P-384 (secp384r1), e, o ímpar fora, ES512 usa P-521 (secp521r1). Sim, 521. Sim, até a Microsoft fez isso.

A criptografia da curva elíptica (ECC) é muito mais difícil de quebrar do que a RSA (ou talvez sejamos muito bons em quebrar RSA). Como resultado, o ECDSA pode usar chaves muito mais curtas que a RSA, juntamente com assinaturas muito mais curtas. Uma pequena tecla Eliptic Curve (EC) de cerca de 256 bits fornece a mesma segurança que uma chave RSA de 3072 bits.

Muitas vezes você verá o ECDSA listado como mais rápido do que seu equivalente na RSA, mas isso só é realmente verdade para a geração de assinaturas; a validação de assinaturas ainda é tipicamente mais rápida com o RSA. Com jwts, é mais provável que você esteja assinando uma vez e verificando muitas vezes.

Os JWTs assinados com a ECDSA têm uma assinatura probabilística, o que significa que o mesmo cabeçalho jwt & payload sempre gerará uma assinatura diferente. Mas, infelizmente, a ECDSA é probabilística de uma forma ruim, onde a geração aleatória é vital para a segurança da assinatura.

A ECDSA usa uma nonce aleatória (não mais de uma vez) que é gerada por assinatura. A falha em usar apenas um valor de nonce uma vez torna a chave privada facilmente recuperável, e isso tem sido visto na natureza tanto com o Playstation 3 da Sony quanto o Bitcoin. Com o Playstation 3, a chave privada foi recuperada devido a uma nonce estática, e com o Bitcoin, usuários de Android foram afetados devido a um bug na classe SecureRandom de Java no Android. Se forem necessários valores aleatórios para a segurança de uma assinatura probabilística, então você deve preferir uma assinatura determinística que não o faça.

Enquanto o RSASSA-PKCS1-v1_5 tem problemas com a validação de assinaturas, o ECDSA tem problemas com a geração de assinaturas, o que é muito mais fácil de lidar quando você é o emissor de tokens.

A ECDSA está ganhando popularidade, mas parece geralmente ser desaprovada pelos criptógrafos devido à forma como a criptografia da curva elíptica foi implementada, com preocupações em torno da dificuldade de implementação devido ao uso de valores aleatórios. Tem uma reputação melhor que a RSA, mas os criptógrafos ainda estão defendendo a migração para a EdDSA.

As curvas JOSE inicialmente utilizadas quando definidas pelo NIST. Se você está preocupado em usar curvas definidas pela NIST, mas quer usar o ECDSA, uma alternativa popular é usar uma curva Koblitz, como secp256k1 (em oposição ao secp256r1). As curvas de Kobiltz são alguns bits mais fracas, mas se você tem preocupações de que os números aleatórios inexplicáveis usados nas curvas NIST indiquem outro backdoor da NSA, então as curvas de Kobiltz oferecem uma alternativa cada vez mais popular. Você pode encontrar usos nessas curvas em Bitcoin, Ethereum e FIDO2. No entanto, você deve usar o EdDSA se quiser usar uma curva não-NIST. Em JOSE, algoritmos usando Kobiltz terminam com um K, por exemplo, ES256K.

Leitura suplementar

EdDSA

EdDSA = um algoritmo de assinatura EdDSA foi usado 🤷 ♂️

EdDSA aposta na tendência dos algoritmos anteriores e usa um único valor. Em vez disso, ele se baseia na curva () definida em uma tecla pré-acordada. algcrv

Por exemplo, um JWK contendo uma chave pública EdDSA se pareceria com o seguinte:

{
  "kty": "OKP",
  "alg": "EdDSA",
  "crv": "Ed25519",
  "x": "60mR98SQlHUSeLeIu7TeJBTLRG10qlcDLU4AJjQdqMQ"
}

Isso força o comportamento moderno de usar a curva atribuída à chave, ao contrário do JWT, e elimina vários ataques relacionados. alg

EdDSA é uma forma de criptografia de curva elíptica que se aproveita das curvas de Edwards torcidas. É uma variante do sistema de assinatura de Schnorr (em vez de DSA). O EdDSA é rápido tanto na assinatura quanto na validação, tem uma assinatura curta e dá passos laterais de classes de vulnerabilidades de segurança.

O RFC 8037 define o suporte jose para as seguintes variantes EdDSA:

  • Ed25519: uma curva curva de 255 bits Curva25519 (chave privada de 32 byte, chave pública de 32 byte, assinatura de 64 byte). A assinatura usa SHA-512. Fornece segurança de 128 bits
  • Ed448: uma curva curva de 448 bits Curve448-Goldilocks (chave privada de 57 byte, chave pública de 57 byte, assinatura de 114 byte). A assinatura usa SHAKE256. Fornece segurança de 224 bits

JWTs assinados com EdDSA têm uma assinatura determinística, o que significa que o mesmo cabeçalho jwt & carga sempre gerará a mesma assinatura. Isso é determinista de uma boa forma, abordando a preocupação de confiar em valores aleatórios de nonce para proteger a chave privada. O EdDSA só usa valores aleatórios durante a criação de chaves privadas. Este é o algoritmo que os críticos da JOSE & JWTs recomendam.

O suporte para EdDSA em bibliotecas JWT é um pouco irregular, mas espere ver mais do EdDSA em breve.

Leitura suplementar

HMAC (por exemplo, HS256)

HS256 = HMAC usando SHA-256

Até agora, temos falado sobre criptografia assimétrica, onde apenas o emissor de tokens tem a chave privada para criar a assinatura, e todos os outros têm a chave pública correspondente que pode ser usada para validar a assinatura. Por exemplo, o provedor de identidade tem a chave privada e os partidos que dependem usam uma chave pública.

No raro caso de você ser a única pessoa que emite e valida tokens, então você pode considerar usar criptografia simétrica com algo como HS256. Isso usa a mesma chave para criar e validar uma assinatura.

Na minha opinião, se você se encontrar nesta posição, então eu não acho que JWTs são a solução certa para você. Se a mesma entidade é ler e escrever, então qual é o requisito para dados estruturados e de texto simples em um JWT? Eu recomendaria armazenar os dados em um banco de dados e passar em torno de uma referência ou usar algo como um token Branca ou JSON Web Encryption (JWE) para garantir que apenas você possa ler os dados.

Geralmente, o uso de HMAC para assinatura JWT é visto como uma espécie de anti-padrão.

Leitura suplementar

Nenhum

nenhum = base64 codificado codificado

Desculpe, não pude resistir. Por favor, não use isso.

Recomendações

Use o EdDSA sempre que possível e use o ECDSA quando não for. Se você for forçado a usar RSA, prefira o RSASSA-PSS em vez do RSASSA-PKCS1-v1_5.

Não acho que seja uma declaração controversa dizer que a RSA está lentamente saindo. No momento, oferecer ECDSA é uma boa alternativa, mas o ideal é que você queira se mudar para a EdDSA sempre que possível.

Mas, não importa qual algoritmo você use, certifique-se de saber com antecedência qual algoritmo esperar e qual chave usar para validação.


Autor: Scott Brady

Artiigo Original