RS256 vs HS256: Qual a diferença?

254

Estou usando o Auth0 para lidar com a autenticação no meu aplicativo da web. Estou usando o ASP.NET Core v1.0.0 e Angular 2 rc5 e não sei muito sobre autenticação / segurança em geral.

Nos documentos Auth0 para ASP.NET Core Web Api , há duas opções para o algoritmo JWT: RS256 e HS256. Esta pode ser uma pergunta idiota, mas:

Qual é a diferença entre RS256 e HS256? Quais são alguns casos de uso (se aplicável)?

Rico Kahler
fonte
Eu encontrei um Angular2-JWT com firbase / php-Jwt no tutorial do aplicativo do lado do servidor freakyjolly.com/…
Code Spy

Respostas:

437

Ambas as opções se referem a qual algoritmo o provedor de identidade usa para assinar o JWT. A assinatura é uma operação criptográfica que gera uma "assinatura" (parte da JWT) que o destinatário do token pode validar para garantir que o token não tenha sido violado.

  • O RS256 (RSA Signature with SHA-256 ) é um algoritmo assimétrico e usa um par de chaves pública / privada: o provedor de identidade possui uma chave privada (secreta) usada para gerar a assinatura e o consumidor da JWT recebe uma chave pública para validar a assinatura. Como a chave pública, ao contrário da chave privada, não precisa ser mantida em segurança, a maioria dos provedores de identidade facilita a obtenção e o uso pelos consumidores de identidades (geralmente por meio de um URL de metadados).

  • O HS256 ( HMAC com SHA-256), por outro lado, envolve uma combinação de uma função de hash e uma chave (secreta) compartilhada entre as duas partes usadas para gerar o hash que servirá como assinatura. Como a mesma chave é usada para gerar a assinatura e validá-la, é necessário ter cuidado para garantir que a chave não seja comprometida.

Se você estiver desenvolvendo o aplicativo que consome as JWTs, poderá usar o HS256 com segurança, pois terá controle sobre quem usa as chaves secretas. Se, por outro lado, você não tiver controle sobre o cliente ou não tiver como garantir uma chave secreta, o RS256 será mais adequado, pois o consumidor precisa conhecer apenas a chave pública (compartilhada).

Como a chave pública geralmente é disponibilizada nos pontos de extremidade de metadados, os clientes podem ser programados para recuperar a chave pública automaticamente. Se for esse o caso (como acontece com as bibliotecas do .Net Core), você terá menos trabalho a fazer na configuração (as bibliotecas buscarão a chave pública do servidor). As chaves simétricas, por outro lado, precisam ser trocadas fora da banda (garantindo um canal de comunicação seguro) e atualizadas manualmente se houver uma substituição da chave de assinatura.

O Auth0 fornece pontos de extremidade de metadados para os protocolos OIDC, SAML e WS-Fed, onde as chaves públicas podem ser recuperadas. Você pode ver esses pontos de extremidade nas "Configurações avançadas" de um cliente.

O ponto de extremidade de metadados OIDC, por exemplo, assume a forma de https://{account domain}/.well-known/openid-configuration. Se você navegar para esse URL, verá um objeto JSON com uma referência a https://{account domain}/.well-known/jwks.json, que contém a chave pública (ou chaves) da conta.

Se você observar as amostras do RS256, verá que não precisa configurar a chave pública em nenhum lugar: ela é recuperada automaticamente pela estrutura.

Nico Sabena
fonte
46
NB ao usar o rs256 - existe (ou houve) um risco de segurança em muitas bibliotecas que permitiu ao token determinar qual algoritmo usar. Essencialmente, o invasor pode usar a chave pública rs256 com uma codificação hs256 para fingir que é a chave secreta. Portanto, verifique se sua biblioteca não possui esse comportamento!
AlexFoxGill #
7
Uma pequena correção, "HS256 (HMAC com SHA-256), por outro lado, é um algoritmo simétrico" - o HMAC não utiliza um algoritmo de chave simétrica (o que permitiria criptografar e descriptografar a assinatura por sua definição). Ele utiliza uma função hash criptográfica e uma chave criptográfica secreta sob o HMAC . O que implica o cálculo do hash (função unidirecional) sobre a mensagem com uma chave secreta anexada.
Kikoz
1
Exemplo com o Google: Vá para accounts.google.com/.well-known/openid-configuration e veja jwks_uri; ele encaminha para googleapis.com/oauth2/v3/certs, onde você pode encontrar as chaves. Então você só precisa recuperar a chave boa pelo filho.
Denis TRUFFAUT
Vale ressaltar que, como o HS256 compartilha uma chave entre duas partes, esse algoritmo é incapaz de oferecer suporte a vários públicos em um access_token, enquanto o RS256 pode suportar muitos públicos. Isso é importante para clientes do Identity, como o Auth0, que permitem apenas uma solicitação ao terminal / userinfo usando um access_token se a configuração for RS256, pois eles precisam desse token para dar suporte ao seu domínio api como um auditor, bem como ao domínio auth0.
jezpez 15/03
94

Na criptografia, existem dois tipos de algoritmos usados:

Algoritmos simétricos

Uma única chave é usada para criptografar dados. Quando criptografados com a chave, os dados podem ser descriptografados usando a mesma chave. Se, por exemplo, Mary criptografa uma mensagem usando a chave "meu segredo" e a envia para John, ele poderá descriptografar a mensagem corretamente com a mesma chave "meu segredo".

Algoritmos assimétricos

Duas chaves são usadas para criptografar e descriptografar mensagens. Enquanto uma chave (pública) é usada para criptografar a mensagem, a outra chave (privada) só pode ser usada para descriptografá-la. Portanto, John pode gerar chaves públicas e privadas e enviar apenas a chave pública para Mary para criptografar sua mensagem. A mensagem só pode ser descriptografada usando a chave privada.

Cenário HS256 e RS256

Esses algoritmos NÃO são usados ​​para criptografar / descriptografar dados. Em vez disso, são usados ​​para verificar a origem ou a autenticidade dos dados. Quando Mary precisa enviar uma mensagem aberta para Jhon e ele precisa verificar se a mensagem é certamente de Mary, HS256 ou RS256 podem ser usadas.

O HS256 pode criar uma assinatura para uma determinada amostra de dados usando uma única chave. Quando a mensagem é transmitida junto com a assinatura, a parte receptora pode usar a mesma chave para verificar se a assinatura corresponde à mensagem.

O RS256 usa par de chaves para fazer o mesmo. Uma assinatura só pode ser gerada usando a chave privada. E a chave pública deve ser usada para verificar a assinatura. Nesse cenário, mesmo que Jack encontre a chave pública, ele não pode criar uma mensagem de falsificação com uma assinatura para representar Mary.

Charlie
fonte
39

Há uma diferença no desempenho.

Simplificando, HS256é cerca de 1 ordem de magnitude mais rápida que RS256na verificação, mas cerca de 2 ordens de magnitude mais rápida que RS256na emissão (assinatura).

 640,251  91,464.3 ops/s
  86,123  12,303.3 ops/s (RS256 verify)
   7,046   1,006.5 ops/s (RS256 sign)

Não se prenda aos números reais, pense neles com respeito um ao outro.

[Program.cs]

class Program
{
    static void Main(string[] args)
    {
        foreach (var duration in new[] { 1, 3, 5, 7 })
        {
            var t = TimeSpan.FromSeconds(duration);

            byte[] publicKey, privateKey;

            using (var rsa = new RSACryptoServiceProvider())
            {
                publicKey = rsa.ExportCspBlob(false);
                privateKey = rsa.ExportCspBlob(true);
            }

            byte[] key = new byte[64];

            using (var rng = new RNGCryptoServiceProvider())
            {
                rng.GetBytes(key);
            }

            var s1 = new Stopwatch();
            var n1 = 0;

            using (var hs256 = new HMACSHA256(key))
            {
                while (s1.Elapsed < t)
                {
                    s1.Start();
                    var hash = hs256.ComputeHash(privateKey);
                    s1.Stop();
                    n1++;
                }
            }

            byte[] sign;

            using (var rsa = new RSACryptoServiceProvider())
            {
                rsa.ImportCspBlob(privateKey);

                sign = rsa.SignData(privateKey, "SHA256");
            }

            var s2 = new Stopwatch();
            var n2 = 0;

            using (var rsa = new RSACryptoServiceProvider())
            {
                rsa.ImportCspBlob(publicKey);

                while (s2.Elapsed < t)
                {
                    s2.Start();
                    var success = rsa.VerifyData(privateKey, "SHA256", sign);
                    s2.Stop();
                    n2++;
                }
            }

            var s3 = new Stopwatch();
            var n3 = 0;

            using (var rsa = new RSACryptoServiceProvider())
            {
                rsa.ImportCspBlob(privateKey);

                while (s3.Elapsed < t)
                {
                    s3.Start();
                    rsa.SignData(privateKey, "SHA256");
                    s3.Stop();
                    n3++;
                }
            }

            Console.WriteLine($"{s1.Elapsed.TotalSeconds:0} {n1,7:N0} {n1 / s1.Elapsed.TotalSeconds,9:N1} ops/s");
            Console.WriteLine($"{s2.Elapsed.TotalSeconds:0} {n2,7:N0} {n2 / s2.Elapsed.TotalSeconds,9:N1} ops/s");
            Console.WriteLine($"{s3.Elapsed.TotalSeconds:0} {n3,7:N0} {n3 / s3.Elapsed.TotalSeconds,9:N1} ops/s");

            Console.WriteLine($"RS256 is {(n1 / s1.Elapsed.TotalSeconds) / (n2 / s2.Elapsed.TotalSeconds),9:N1}x slower (verify)");
            Console.WriteLine($"RS256 is {(n1 / s1.Elapsed.TotalSeconds) / (n3 / s3.Elapsed.TotalSeconds),9:N1}x slower (issue)");

            // RS256 is about 7.5x slower, but it can still do over 10K ops per sec.
        }
    }
}
John Leidegren
fonte
Estes são números importantes. obrigado. Costumo pensar em criptografia como uma taxa de transferência wrt mais ou menos transparente, mas sua pesquisa implica que o uso do R256 para assinar comunicações entre máquinas adiciona 1 ms por salto.
Matthew Mark Miller
1
@MatthewMarkMiller Lembre-se de que eles não são iguais em uso. Eles têm características diferentes. O RS256 é assimétrico e, portanto, em uma comunicação no estilo cliente / servidor em que você compartilha apenas a chave pública, é uma opção melhor. O HS256 exige o compartilhamento da chave que pode assinar E verificar - útil apenas se você confiar nas duas partes ou não precisar que uma das partes decifre nada.
Rob Evans
7
@ RobEvans sim, não se preocupe com os números de desempenho aqui. Escolha a solução certa para o seu problema. Esta é apenas uma observação, não uma recomendação para favorecer o HS256 sobre o RS256. Você deve tomar essa decisão com base no seu contexto.
John Leidegren 21/03/19
1
Quando a escolha do protocolo pode ter o mesmo impacto na latência que um quilômetro extra de cabo, vale a pena saber, especialmente nesses dias de longas cadeias de chamadas e TTLs estreitos.
Matthew Mark Miller
0

resposta curta, específica para OAuth2,

  • Segredo do cliente do usuário HS256 para gerar a assinatura do token e o mesmo segredo é necessário para validar o token no backend. Portanto, você deve ter uma cópia desse segredo em seu servidor back-end para verificar a assinatura.
  • O RS256 usa criptografia de chave pública para assinar o token. A assinatura (hash) será criada usando a chave privada e pode ser verificada usando a chave pública. Portanto, não há necessidade de chave privada ou segredo do cliente para armazenar no servidor back-end, mas o servidor back-end buscará a chave pública no URL de configuração aberta do seu inquilino ( https: // [inquilino] /.well-known/openid -configuration ) para verificar o token. O parâmetro KID dentro do access_toekn será usado para detectar a chave (pública) correta da configuração openid.
Hiran
fonte