RS256 vs HS256: qual è la differenza?


255

Sto usando Auth0 per gestire l'autenticazione nella mia app Web. Sto usando ASP.NET Core v1.0.0 e Angular 2 rc5 e non so molto sull'autenticazione / sicurezza in generale.

Nei documenti Auth0 per ASP.NET Core Web Api , ci sono due scelte per l'algoritmo JWT: RS256 e HS256. Questa potrebbe essere una domanda stupida ma:

Qual è la differenza tra RS256 e HS256? Quali sono alcuni casi d'uso (se applicabile)?


Ho trovato un Angular2-JWT con firbase / php-Jwt nel tutorial dell'applicazione lato server freakyjolly.com/…
Code Spy

Risposte:


435

Entrambe le scelte si riferiscono all'algoritmo utilizzato dal provider di identità per firmare il JWT. La firma è un'operazione crittografica che genera una "firma" (parte del JWT) che il destinatario del token può convalidare per garantire che il token non sia stato manomesso.

  • RS256 (RSA Signature con SHA-256 ) è un algoritmo asimmetrico e utilizza una coppia di chiavi pubblica / privata: il provider di identità ha una chiave privata (segreta) utilizzata per generare la firma e il consumatore del JWT ottiene una chiave pubblica per convalidare la firma. Poiché la chiave pubblica, a differenza della chiave privata, non ha bisogno di essere protetta, la maggior parte dei provider di identità lo rende facilmente disponibile per i consumatori per ottenere e utilizzare (di solito tramite un URL di metadati).

  • HS256 ( HMAC con SHA-256), d'altra parte, comporta una combinazione di una funzione di hashing e una chiave (segreta) condivisa tra le due parti utilizzate per generare l'hash che servirà da firma. Poiché la stessa chiave viene utilizzata sia per generare la firma sia per convalidarla, è necessario assicurarsi che la chiave non sia compromessa.

Se svilupperai l'applicazione che utilizza i JWT, puoi tranquillamente usare HS256, perché avrai il controllo su chi usa le chiavi segrete. Se, d'altra parte, non hai il controllo sul client o non hai modo di proteggere una chiave segreta, RS256 sarà più adatto, dal momento che il consumatore deve solo conoscere la chiave pubblica (condivisa).

Poiché la chiave pubblica viene generalmente resa disponibile dagli endpoint dei metadati, i client possono essere programmati per recuperare automaticamente la chiave pubblica. Se questo è il caso (come nelle librerie .Net Core), avrai meno lavoro da fare sulla configurazione (le librerie prenderanno la chiave pubblica dal server). Le chiavi simmetriche, d'altra parte, devono essere scambiate fuori banda (garantendo un canale di comunicazione sicuro) e aggiornate manualmente in caso di rollover delle chiavi di firma.

Auth0 fornisce endpoint di metadati per i protocolli OIDC, SAML e WS-Fed, in cui è possibile recuperare le chiavi pubbliche. È possibile visualizzare tali endpoint nelle "Impostazioni avanzate" di un client.

L'endpoint dei metadati OIDC, ad esempio, assume la forma di https://{account domain}/.well-known/openid-configuration. Se si accede a tale URL, verrà visualizzato un oggetto JSON con un riferimento a https://{account domain}/.well-known/jwks.json, che contiene la chiave pubblica (o le chiavi) dell'account.

Se guardi gli esempi RS256, noterai che non è necessario configurare la chiave pubblica da nessuna parte: viene recuperata automaticamente dal framework.


46
NB quando si utilizza rs256 - in molte librerie esiste (o c'era) un rischio per la sicurezza che ha permesso al token di determinare quale algoritmo utilizzare. In sostanza, l'attaccante potrebbe usare la chiave pubblica rs256 con una codifica hs256 per fingere che sia la chiave segreta. Quindi assicurati che la tua libreria non abbia questo comportamento!
AlexFoxGill

7
Una piccola correzione, "HS256 (HMAC con SHA-256), d'altra parte, è un algoritmo simmetrico" - HMAC non utilizza un algoritmo a chiave simmetrica (che consentirebbe di crittografare e decrittografare la firma per definizione). Utilizza una funzione hash crittografica e una chiave crittografica segreta sotto HMAC . Ciò implica il calcolo dell'hash (funzione unidirezionale) sul messaggio con una chiave segreta aggiunta.
Kikoz,

1
Esempio con Google: vai su accounts.google.com/.well-known/openid-configuration e guarda jwks_uri; ti inoltra a googleapis.com/oauth2/v3/certs dove puoi trovare le chiavi. Quindi devi solo recuperare la buona chiave da suo figlio.
Denis TRUFFAUT,

Vale la pena notare che poiché HS256 condivide una chiave tra due parti che rende questo algoritmo incapace di supportare più segmenti di pubblico in un unico access_token, mentre RS256 può supportare molti segmenti di pubblico. Ciò è importante per i client Identity come Auth0 che consentono una richiesta all'endpoint / userinfo utilizzando un access_token se la configurazione è RS256, poiché hanno bisogno di questo token per supportare il dominio api come aud e il loro dominio auth0.
jezpez,

95

Nella crittografia ci sono due tipi di algoritmi utilizzati:

Algoritmi simmetrici

Una singola chiave viene utilizzata per crittografare i dati. Se crittografati con la chiave, i dati possono essere decrittografati utilizzando la stessa chiave. Se, ad esempio, Mary crittografa un messaggio utilizzando la chiave "my-secret" e lo invia a John, sarà in grado di decrittografare correttamente il messaggio con la stessa chiave "my-secret".

Algoritmi asimmetrici

Due chiavi vengono utilizzate per crittografare e decrittografare i messaggi. Mentre una chiave (pubblica) viene utilizzata per crittografare il messaggio, l'altra chiave (privata) può essere utilizzata solo per decrittografarlo. Quindi, John può generare sia chiavi pubbliche che private, quindi inviare solo la chiave pubblica a Mary per crittografare il suo messaggio. Il messaggio può essere decrittografato solo utilizzando la chiave privata.

Scenario HS256 e RS256

Questi algoritmi NON vengono utilizzati per crittografare / decrytare i dati. Piuttosto vengono utilizzati per verificare l'origine o l'autenticità dei dati. Quando Mary deve inviare un messaggio aperto a Jhon e deve verificare che il messaggio provenga sicuramente da Mary, è possibile utilizzare HS256 o RS256.

HS256 può creare una firma per un dato campione di dati usando una sola chiave. Quando il messaggio viene trasmesso insieme alla firma, la parte ricevente può utilizzare la stessa chiave per verificare che la firma corrisponda al messaggio.

RS256 utilizza una coppia di chiavi per fare lo stesso. Una firma può essere generata solo usando la chiave privata. E la chiave pubblica deve essere utilizzata per verificare la firma. In questo scenario, anche se Jack trova la chiave pubblica, non può creare un messaggio di parodia con una firma per impersonare Mary.


39

C'è una differenza nelle prestazioni.

In poche parole, HS256è circa 1 ordine di grandezza più veloce rispetto RS256alla verifica, ma circa 2 ordini di grandezza più veloce rispetto RS256all'emissione (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)

Non rimanere impigliato nei numeri reali, pensa solo a loro l'uno rispetto all'altro.

[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.
        }
    }
}

Questi sono numeri importanti. grazie. Tendo a pensare alla crittografia come ad un throughput wrt più o meno trasparente, ma la tua ricerca implica che l'uso dell'R256 per firmare comunicazioni intermachine aggiunge 1 ms per hop.
Matthew Mark Miller,

1
@MatthewMarkMiller Tieni presente però che non sono uguali in uso. Hanno caratteristiche diverse. RS256 è asimmetrico e quindi in una comunicazione in stile client / server in cui condividi solo la chiave pubblica, è un'opzione migliore. HS256 richiede la condivisione della chiave che può firmare e verificare, utile solo se ti fidi delle due parti o non hai bisogno di una delle parti per decrittografare nulla.
Rob Evans,

7
@RobEvans sì, non lasciarti coinvolgere dai numeri delle prestazioni qui. Scegli la soluzione giusta al tuo problema. Questa è solo un'osservazione, non una raccomandazione per favorire HS256 rispetto a RS256, devi prendere quella decisione in base al tuo contesto.
John Leidegren,

1
Quando la scelta del protocollo può avere lo stesso impatto sulla latenza di un chilometro in più di cavo, vale la pena saperlo, soprattutto in questi giorni di lunghe catene di chiamata e TTL stretti.
Matthew Mark Miller,

0

risposta breve, specifica per OAuth2,

  • Segreto client utente HS256 per generare la firma del token e lo stesso segreto è necessario per convalidare il token nel back-end. Quindi dovresti avere una copia di quel segreto nel tuo server back-end per verificare la firma.
  • RS256 utilizza la crittografia della chiave pubblica per firmare il token. La firma (hash) verrà creata utilizzando la chiave privata e può verificare utilizzando la chiave pubblica. Pertanto, non è necessaria alcuna chiave privata o segreto client da archiviare nel server back-end, ma il server back-end recupererà la chiave pubblica dall'URL di configurazione openid nel tenant ( https: // [tenant] /.well-known/openid -configurazione ) per verificare il token. Il parametro KID all'interno di access_toekn utilizzerà per rilevare la chiave corretta (pubblica) dalla configurazione di openid.
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.