RS256 vs HS256: ¿Cuál es la diferencia?

Resuelto Rico Kahler asked hace 8 años • 5 respuestas

Estoy usando Auth0 para manejar la autenticación en mi aplicación web. Estoy usando ASP.NET Core v1.0.0 y Angular 2 rc5 y no sé mucho sobre autenticación/seguridad en general.

En los documentos de Auth0 para ASP.NET Core Web Api , hay dos opciones para el algoritmo JWT: RS256 y HS256. Esta puede ser una pregunta tonta pero:

¿Cuál es la diferencia entre RS256 y HS256? ¿Cuáles son algunos casos de uso (si corresponde)?

Rico Kahler avatar Aug 31 '16 07:08 Rico Kahler
Aceptado

Ambas opciones se refieren al algoritmo que utiliza el proveedor de identidad para firmar el JWT. La firma es una operación criptográfica que genera una "firma" (parte del JWT) que el destinatario del token puede validar para garantizar que el token no haya sido manipulado.

  • RS256 (firma RSA con SHA-256 ) es un algoritmo asimétrico y utiliza un par de claves pública/privada: el proveedor de identidad tiene una clave privada (secreta) utilizada para generar la firma, y ​​el consumidor del JWT obtiene una clave pública. para validar la firma. Dado que no es necesario mantener segura la clave pública, a diferencia de la clave privada, la mayoría de los proveedores de identidad la ponen fácilmente a disposición de los consumidores para obtenerla y utilizarla (normalmente a través de una URL de metadatos).

  • HS256 ( HMAC con SHA-256), por otro lado, implica una combinación de una función hash y una clave (secreta) que se comparte entre las dos partes y se utiliza para generar el hash que servirá como firma. Dado que se utiliza la misma clave tanto para generar la firma como para validarla, se debe tener cuidado para garantizar que la clave no se vea comprometida.

Si va a desarrollar la aplicación que consume los JWT, puede usar HS256 de manera segura, porque tendrá control sobre quién usa las claves secretas. Si, por otro lado, no tiene control sobre el cliente, o no tiene forma de obtener una clave secreta, RS256 será una mejor opción, ya que el consumidor sólo necesita conocer la clave pública (compartida).

Dado que la clave pública generalmente está disponible desde puntos finales de metadatos, los clientes pueden programarse para recuperar la clave pública automáticamente. Si este es el caso (como ocurre con las bibliotecas .Net Core), tendrá menos trabajo que hacer en la configuración (las bibliotecas obtendrán la clave pública del servidor). Las claves simétricas, por otro lado, deben intercambiarse fuera de banda (lo que garantiza un canal de comunicación seguro) y actualizarse manualmente si hay una transferencia de clave de firma.

Auth0 proporciona puntos finales de metadatos para los protocolos OIDC, SAML y WS-Fed, donde se pueden recuperar las claves públicas. Puede ver esos puntos finales en la "Configuración avanzada" de un cliente.

El punto final de metadatos OIDC, por ejemplo, toma la forma de https://{account domain}/.well-known/openid-configuration. Si navega hasta esa URL, verá un objeto JSON con una referencia a https://{account domain}/.well-known/jwks.json, que contiene la clave (o claves) pública de la cuenta, representada como un conjunto de claves web JSON .

Si observa los ejemplos de RS256, verá que no necesita configurar la clave pública en ningún lugar: el marco la recupera automáticamente.

Nico Sabena avatar Aug 31 '2016 01:08 Nico Sabena

En criptografía se utilizan dos tipos de algoritmos:

Algoritmos simétricos

Se utiliza una única clave para cifrar los datos. Cuando se cifran con la clave, los datos se pueden descifrar utilizando la misma clave. Si, por ejemplo, Mary cifra un mensaje usando la clave "mi-secreto" y se lo envía a John, él podrá descifrar el mensaje correctamente con la misma clave "mi-secreto".

Algoritmos asimétricos

Se utilizan dos claves para cifrar y descifrar mensajes. Mientras que una clave (pública) se utiliza para cifrar el mensaje, la otra clave (privada) sólo se puede utilizar para descifrarlo. Entonces, John puede generar claves públicas y privadas y luego enviar solo la clave pública a Mary para cifrar su mensaje. El mensaje sólo se puede descifrar utilizando la clave privada.

Escenario HS256 y RS256

Estos algoritmos NO se utilizan para cifrar/descifrar datos. Más bien se utilizan para verificar el origen o la autenticidad de los datos. Cuando Mary necesita enviar un mensaje abierto a Jhon y él necesita verificar que el mensaje seguramente sea de Mary, se puede utilizar HS256 o RS256.

HS256 puede crear una firma para una muestra determinada de datos utilizando una sola clave. Cuando el mensaje se transmite junto con la firma, el destinatario puede utilizar la misma clave para verificar que la firma coincida con el mensaje.

RS256 usa un par de claves para hacer lo mismo. Sólo se puede generar una firma utilizando la clave privada. Y se debe utilizar la clave pública para verificar la firma. En este escenario, incluso si Jack encuentra la clave pública, no puede crear un mensaje falso con una firma para hacerse pasar por Mary.

Charlie avatar Jan 23 '2017 08:01 Charlie

Hay una diferencia en el rendimiento.

En pocas palabras, HS256es aproximadamente 1 orden de magnitud más rápido que RS256para la verificación, pero aproximadamente 2 órdenes de magnitud más rápido que RS256para la emisión (firma).

 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)

No se obsesione con los números reales, simplemente piense en ellos con respecto a los demás.

[Programa.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 avatar Mar 02 '2018 12:03 John Leidegren

respuesta corta, específica de OAuth2,

  • Secreto de cliente de usuario HS256 para generar la firma del token y se requiere el mismo secreto para validar el token en el back-end. Por lo tanto, debería tener una copia de ese secreto en su servidor back-end para verificar la firma.
  • RS256 usa cifrado de clave pública para firmar el token. La firma (hash) se creará usando una clave privada y se puede verificar usando una clave pública. Por lo tanto, no es necesario almacenar la clave privada o el secreto del cliente en el servidor back-end, pero el servidor back-end recuperará la clave pública de la URL de configuración de openid en su inquilino ( https://[tenant]/.well-known/openid -configuration ) para verificar el token. El parámetro KID dentro de access_toekn se utilizará para detectar la clave correcta (pública) desde la configuración de openid.
Hiran avatar May 11 '2020 07:05 Hiran