RS256 vs HS256: Was ist der Unterschied?

254

Ich verwende Auth0, um die Authentifizierung in meiner Web-App durchzuführen. Ich verwende ASP.NET Core v1.0.0 und Angular 2 rc5 und weiß nicht viel über Authentifizierung / Sicherheit im Allgemeinen.

In den Auth0-Dokumenten für ASP.NET Core Web Api gibt es zwei Möglichkeiten für den JWT-Algorithmus: RS256 und HS256. Dies mag eine dumme Frage sein, aber:

Was ist der Unterschied zwischen RS256 und HS256? Was sind einige Anwendungsfälle (falls zutreffend)?

Rico Kahler
quelle
Ich fand ein Angular2-JWT mit firbase / php-Jwt im serverseitigen Anwendungs-Tutorial freakyjolly.com/…
Code Spy

Antworten:

437

Beide Auswahlmöglichkeiten beziehen sich auf den Algorithmus, den der Identitätsanbieter zum Signieren des JWT verwendet. Das Signieren ist eine kryptografische Operation, die eine "Signatur" (Teil des JWT) generiert, die der Empfänger des Tokens validieren kann, um sicherzustellen, dass das Token nicht manipuliert wurde.

  • RS256 (RSA-Signatur mit SHA-256 ) ist ein asymmetrischer Algorithmus und verwendet ein öffentliches / privates Schlüsselpaar: Der Identitätsanbieter verfügt über einen privaten (geheimen) Schlüssel, der zum Generieren der Signatur verwendet wird, und der Verbraucher des JWT erhält einen öffentlichen Schlüssel um die Unterschrift zu validieren. Da der öffentliche Schlüssel im Gegensatz zum privaten Schlüssel nicht gesichert werden muss, stellen die meisten Identitätsanbieter ihn den Verbrauchern leicht zur Verfügung, um ihn zu erhalten und zu verwenden (normalerweise über eine Metadaten-URL).

  • HS256 ( HMAC mit SHA-256) beinhaltet andererseits eine Kombination aus einer Hashing-Funktion und einem (geheimen) Schlüssel, der von den beiden Parteien gemeinsam genutzt wird, um den Hash zu generieren, der als Signatur dient. Da derselbe Schlüssel sowohl zum Generieren als auch zum Validieren der Signatur verwendet wird, muss darauf geachtet werden, dass der Schlüssel nicht kompromittiert wird.

Wenn Sie die Anwendung entwickeln, die die JWTs verbraucht, können Sie HS256 sicher verwenden, da Sie die Kontrolle darüber haben, wer die geheimen Schlüssel verwendet. Wenn Sie andererseits keine Kontrolle über den Client haben oder keine Möglichkeit haben, einen geheimen Schlüssel zu sichern, ist RS256 besser geeignet, da der Verbraucher nur den öffentlichen (gemeinsam genutzten) Schlüssel kennen muss.

Da der öffentliche Schlüssel normalerweise von Metadatenendpunkten zur Verfügung gestellt wird, können Clients so programmiert werden, dass der öffentliche Schlüssel automatisch abgerufen wird. Wenn dies der Fall ist (wie bei den .Net Core-Bibliotheken), müssen Sie weniger an der Konfiguration arbeiten (die Bibliotheken rufen den öffentlichen Schlüssel vom Server ab). Symmetrische Schlüssel müssen dagegen außerhalb des Bandes ausgetauscht werden (um einen sicheren Kommunikationskanal zu gewährleisten) und manuell aktualisiert werden, wenn ein Signaturschlüssel-Rollover auftritt.

Auth0 bietet Metadatenendpunkte für die Protokolle OIDC, SAML und WS-Fed, an denen die öffentlichen Schlüssel abgerufen werden können. Sie können diese Endpunkte unter den "Erweiterten Einstellungen" eines Clients sehen.

Der OIDC-Metadatenendpunkt hat beispielsweise die Form https://{account domain}/.well-known/openid-configuration. Wenn Sie zu dieser URL navigieren, wird ein JSON-Objekt mit einem Verweis auf angezeigt https://{account domain}/.well-known/jwks.json, das den öffentlichen Schlüssel (oder die öffentlichen Schlüssel) des Kontos enthält.

Wenn Sie sich die RS256-Beispiele ansehen, werden Sie feststellen, dass Sie den öffentlichen Schlüssel nirgendwo konfigurieren müssen: Er wird automatisch vom Framework abgerufen.

Nico Sabena
quelle
46
Hinweis: Bei Verwendung von rs256 besteht (oder bestand) in vielen Bibliotheken ein Sicherheitsrisiko, durch das das Token bestimmen konnte, welcher Algorithmus verwendet werden soll. Im Wesentlichen könnte der Angreifer den öffentlichen rs256-Schlüssel mit einer hs256-Codierung verwenden, um vorzutäuschen, dass es sich um den geheimen Schlüssel handelt. Stellen Sie also sicher, dass Ihre Bibliothek dieses Verhalten nicht aufweist!
AlexFoxGill
7
Eine kleine Korrektur, "HS256 (HMAC mit SHA-256), ist dagegen ein symmetrischer Algorithmus" - HMAC verwendet keinen Algorithmus mit symmetrischem Schlüssel (mit dem Sie die Signatur gemäß ihrer Definition verschlüsseln und entschlüsseln können). Es verwendet eine kryptografische Hash-Funktion und einen geheimen kryptografischen Schlüssel unter HMAC . Dies impliziert die Berechnung des Hash (Einwegfunktion) über die Nachricht mit einem angehängten geheimen Schlüssel.
Kikoz
1
Beispiel mit Google: Gehen Sie zu accounts.google.com/.well-known/openid-configuration und sehen Sie sich jwks_uri an. Sie werden an googleapis.com/oauth2/v3/certs weitergeleitet, wo Sie Schlüssel finden. Dann müssen Sie nur noch den guten Schlüssel von seinem Kind abrufen.
Denis TRUFFAUT
Es ist erwähnenswert, dass HS256 einen Schlüssel zwischen zwei Parteien teilt , wodurch dieser Algorithmus nicht in der Lage ist, mehrere Zielgruppen in einem access_token zu unterstützen, während RS256 viele Zielgruppen unterstützen kann. Dies ist wichtig für Identitätsclients wie Auth0, die eine Anforderung an den Endpunkt / userinfo nur mit einem access_token zulassen, wenn die Konfiguration RS256 ist, da sie dieses Token benötigen, um Ihre API-Domäne als Aud sowie ihre auth0-Domäne zu unterstützen.
Jezpez
94

In der Kryptographie werden zwei Arten von Algorithmen verwendet:

Symmetrische Algorithmen

Ein einzelner Schlüssel wird zum Verschlüsseln von Daten verwendet. Bei der Verschlüsselung mit dem Schlüssel können die Daten mit demselben Schlüssel entschlüsselt werden. Wenn Mary beispielsweise eine Nachricht mit dem Schlüssel "my-secret" verschlüsselt und an John sendet, kann er die Nachricht mit demselben Schlüssel "my-secret" korrekt entschlüsseln.

Asymmetrische Algorithmen

Zwei Schlüssel werden zum Ver- und Entschlüsseln von Nachrichten verwendet. Während ein Schlüssel (öffentlich) zum Verschlüsseln der Nachricht verwendet wird, kann der andere Schlüssel (privat) nur zum Entschlüsseln verwendet werden. John kann also sowohl öffentliche als auch private Schlüssel generieren und dann nur den öffentlichen Schlüssel an Mary senden, um ihre Nachricht zu verschlüsseln. Die Nachricht kann nur mit dem privaten Schlüssel entschlüsselt werden.

HS256- und RS256-Szenario

Diese Algorithmen werden NICHT zum Ver- / Entschlüsseln von Daten verwendet. Sie werden vielmehr verwendet, um den Ursprung oder die Echtheit der Daten zu überprüfen. Wenn Mary eine offene Nachricht an Jhon senden muss und er überprüfen muss, ob die Nachricht sicher von Mary stammt, kann HS256 oder RS256 verwendet werden.

HS256 kann mit einem einzigen Schlüssel eine Signatur für eine bestimmte Datenprobe erstellen. Wenn die Nachricht zusammen mit der Signatur gesendet wird, kann die empfangende Partei denselben Schlüssel verwenden, um zu überprüfen, ob die Signatur mit der Nachricht übereinstimmt.

RS256 verwendet dazu ein Schlüsselpaar. Eine Signatur kann nur mit dem privaten Schlüssel generiert werden. Und der öffentliche Schlüssel muss verwendet werden, um die Signatur zu überprüfen. In diesem Szenario kann Jack, selbst wenn er den öffentlichen Schlüssel findet, keine gefälschte Nachricht mit einer Signatur erstellen, um sich als Mary auszugeben.

Charlie
quelle
38

Es gibt einen Unterschied in der Leistung.

Einfach ausgedrückt HS256ist es ungefähr 1 Größenordnung schneller als RS256bei der Überprüfung, aber ungefähr 2 Größenordnungen schneller als RS256beim Ausstellen (Signieren).

 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)

Lassen Sie sich nicht auf die tatsächlichen Zahlen ein, sondern denken Sie nur respektvoll an sie.

[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
quelle
Das sind wichtige Zahlen. Danke. Ich neige dazu, Verschlüsselung als mehr oder weniger transparenten Durchsatz zu betrachten, aber Ihre Forschung impliziert, dass die Verwendung von R256 zum Signieren der Kommunikation zwischen Maschinen 1 ms pro Hop hinzufügt.
Matthew Mark Miller
1
@MatthewMarkMiller Beachten Sie jedoch, dass sie nicht gleich verwendet werden. Sie haben unterschiedliche Eigenschaften. RS256 ist asymmetrisch und daher in einer Client / Server-Kommunikation, bei der Sie nur den öffentlichen Schlüssel gemeinsam nutzen, eine bessere Option. Für HS256 muss der Schlüssel freigegeben werden, der sowohl signieren als auch überprüfen kann. Dies ist nur nützlich, wenn Sie den beiden Parteien vertrauen oder keine der Parteien zum Entschlüsseln benötigen.
Rob Evans
7
@RobEvans ja, lass dich hier nicht auf die Leistungszahlen ein. Wählen Sie die richtige Lösung für Ihr Problem. Dies ist nur eine Beobachtung, keine Empfehlung, HS256 gegenüber RS256 zu bevorzugen. Sie müssen diese Entscheidung basierend auf Ihrem Kontext treffen.
John Leidegren
1
Wenn die Protokollauswahl die gleiche Auswirkung auf die Latenz haben kann wie ein zusätzlicher Kilometer Kabel, ist dies besonders in Zeiten langer Anrufketten und enger TTLs wissenswert.
Matthew Mark Miller
0

kurze Antwort, spezifisch für OAuth2,

  • HS256- Benutzer-Client-Geheimnis zum Generieren der Token-Signatur und dasselbe Geheimnis ist erforderlich, um das Token im Back-End zu validieren. Sie sollten also eine Kopie dieses Geheimnisses auf Ihrem Back-End-Server haben, um die Signatur zu überprüfen.
  • RS256 verwendet die Verschlüsselung mit öffentlichem Schlüssel, um das Token zu signieren. Die Signatur (Hash) wird mit einem privaten Schlüssel erstellt und kann mit einem öffentlichen Schlüssel überprüft werden. Es ist also kein privater Schlüssel oder Client-Geheimnis erforderlich, um auf dem Back-End-Server zu speichern, aber der Back-End-Server ruft den öffentlichen Schlüssel von der OpenID-Konfigurations-URL in Ihrem Mandanten ab ( https: // [Mandant] /.well-known/openid) -Konfiguration ), um das Token zu überprüfen. Der KID-Parameter in access_toekn erkennt den korrekten Schlüssel (public) aus der openid-Konfiguration.
Hiran
quelle