RS256 vs HS256: Quelle est la différence?

J’utilise Auth0 pour gérer l’authentification dans mon application Web. J’utilise ASP.NET Core v1.0.0 et Angular 2 rc5 et je ne connais pas beaucoup l’authentification / la sécurité en général.

Dans les documents Auth0 pour ASP.NET Core Web Api , il existe deux choix pour l’algorithme JWT, à savoir RS256 et HS256. Cela peut être une question stupide mais:

Quelle est la différence entre RS256 et HS256? Quels sont les cas d’utilisation (le cas échéant)?

Les deux choix font référence à l’algorithme utilisé par le fournisseur d’identité pour signer le JWT. La signature est une opération cryptographique qui génère une “signature” (partie de la JWT) que le destinataire du jeton peut valider pour s’assurer que le jeton n’a pas été falsifié.

  • RS256 (signature RSA avec SHA-256 ) est un algorithme asymésortingque et utilise une paire de clés publique / privée: le fournisseur d’identité possède une clé privée (secrète) utilisée pour générer la signature et le consommateur du JWT obtient une clé publique valider la signature. Comme la clé publique, contrairement à la clé privée, n’a pas besoin d’être sécurisée, la plupart des fournisseurs d’identité la rendent facilement disponible et accessible aux consommateurs (généralement via une URL de métadonnées).

  • HS256 ( HMAC avec SHA-256), en revanche, est un algorithme symésortingque , avec une seule clé (secrète) partagée entre les deux parties. Comme la même clé est utilisée à la fois pour générer la signature et pour la valider, il faut veiller à ce que la clé ne soit pas compromise.

Si vous développez l’application utilisant les JWT, vous pouvez utiliser HS256 en toute sécurité, car vous aurez le contrôle sur qui utilise les clés secrètes. Si, par contre, vous n’avez pas le contrôle sur le client ou si vous n’avez aucun moyen de sécuriser une clé secrète, RS256 conviendra mieux, car le consommateur n’a besoin que de connaître la clé publique (partagée).

Comme la clé publique est généralement disponible à partir des points de terminaison de métadonnées, les clients peuvent être programmés pour récupérer automatiquement la clé publique. Si tel est le cas (comme c’est le cas avec les bibliothèques .Net Core), vous aurez moins de travail à faire sur la configuration (les bibliothèques iront chercher la clé publique sur le serveur). Les clés symésortingques, quant à elles, doivent être échangées hors bande (assurant ainsi un canal de communication sécurisé) et mises à jour manuellement s’il ya un changement de clé de signature.

Auth0 fournit des points de terminaison de métadonnées pour les protocoles OIDC, SAML et WS-Fed, où les clés publiques peuvent être récupérées. Vous pouvez voir ces points de terminaison sous les “Paramètres avancés” d’un client.

Le sharepoint terminaison des métadonnées OIDC, par exemple, prend la forme https://{account domain}/.well-known/openid-configuration . Si vous naviguez jusqu’à cette URL, vous verrez un object JSON avec une référence à https://{account domain}/.well-known/jwks.json , qui contient la ou les clés publiques du compte.

Si vous regardez les exemples RS256, vous verrez que vous n’avez pas besoin de configurer la clé publique n’importe où: elle est récupérée automatiquement par le framework.

En cryptographie, il existe deux types d’algorithmes utilisés:

Algorithmes symésortingques

Une seule clé est utilisée pour chiffrer les données. Lorsqu’elles sont chiffrées avec la clé, les données peuvent être déchiffrées à l’aide de la même clé. Si, par exemple, Mary crypte un message en utilisant la clé “mon-secret” et l’envoie à John, il sera capable de décrypter le message correctement avec la même clé “mon secret”.

Algorithmes asymésortingques

Deux clés sont utilisées pour chiffrer et déchiffrer les messages. Alors qu’une clé (publique) est utilisée pour chiffrer le message, l’autre clé (privée) ne peut être utilisée que pour la déchiffrer. Ainsi, John peut générer des clés publiques et privées, puis envoyer uniquement la clé publique à Mary pour chiffrer son message. Le message ne peut être déchiffré qu’à l’aide de la clé privée.

Scénario HS256 et RS256

Ces algorithmes ne sont PAS utilisés pour chiffrer / décrypter les données. Ils servent plutôt à vérifier l’origine ou l’authenticité des données. Lorsque Mary doit envoyer un message ouvert à Jhon et qu’il doit vérifier que le message provient bien de Mary, HS256 ou RS256 peuvent être utilisés.

HS256 peut créer une signature pour un échantillon de données donné en utilisant une seule touche. Lorsque le message est transmis avec la signature, le destinataire peut utiliser la même clé pour vérifier que la signature correspond au message.

RS256 utilise une paire de clés pour faire la même chose. Une signature ne peut être générée qu’à l’aide de la clé privée. Et la clé publique doit être utilisée pour vérifier la signature. Dans ce scénario, même si Jack trouve la clé publique, il ne peut pas créer un message usurpé avec une signature pour usurper l’identité de Mary.

Il y a une différence de performance.

Simplement mettre HS256 est environ 1 ordre de grandeur plus rapide que RS256 pour vérification mais environ 2 ordres de grandeur plus rapide que RS256 pour émettre (signer).

  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) 

Ne vous attardez pas sur les chiffres réels, il suffit de penser à eux avec respect.

[Program.cs]

 class Program { static void Main(ssortingng[] 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. } } }