RS256 vs HS256:有什么区别?

我使用Auth0在我的web应用程序中处理身份验证。NET Core v1.0.0和Angular 2 rc5,我不太了解身份验证/安全。

用于ASP的Auth0文档。NET核心Web Api中,JWT算法有两个选择RS256和HS256。这可能是一个愚蠢的问题,但是:

RS256和HS256有什么区别?有哪些用例(如果适用的话)?

240300 次浏览

这两个选项都引用了标识提供程序用于标志 JWT的算法。签名是一种生成“签名”的密码操作。(JWT的一部分),令牌的接收者可以验证,以确保令牌没有被篡改。

  • RS256 (RSA Signature with sha - 256)是一个非对称算法,它使用公钥/私钥对:身份提供者有一个用于生成签名的私有(秘密)密钥,JWT的消费者获得一个公钥来验证签名。由于公钥(与私钥相反)不需要保持安全,因此大多数身份提供者都使消费者可以很容易地获取和使用公钥(通常通过元数据URL)。

  • HS256 (HMAC with SHA-256),另一方面,涉及哈希函数和一个(秘密)密钥的组合,该密钥在用于生成作为签名的哈希的双方之间共享。由于生成签名和验证签名都使用相同的密钥,因此必须注意确保密钥不会泄露。

如果您将开发使用jwt的应用程序,则可以安全地使用HS256,因为您可以控制谁使用密钥。 另一方面,如果您无法控制客户端,或者您没有办法保护密钥,那么RS256将是一个更好的选择,因为消费者只需要知道公共(共享)密钥

由于公钥通常可以从元数据端点获得,因此可以对客户机进行编程以自动检索公钥。如果是这种情况(就像. net Core库一样),您在配置上需要做的工作就会更少(库将从服务器获取公钥)。另一方面,对称密钥需要在带外交换(确保安全的通信通道),如果有签名密钥翻转,则需要手动更新。

Auth0为OIDC、SAML和WS-Fed协议提供元数据端点,可以在其中检索公钥。你可以在“高级设置”下看到这些端点;客户的。

例如,OIDC元数据端点采用https://{account domain}/.well-known/openid-configuration的形式。如果你浏览到那个URL,你会看到一个带有https://{account domain}/.well-known/jwks.json引用的JSON对象,它包含帐户的公钥(或多个密钥),表示为JSON Web密钥集

如果查看RS256示例,就会发现不需要在任何地方配置公钥:它是由框架自动检索的。

在密码学中有两种类型的算法:

对称算法

使用单个密钥对数据进行加密。当使用密钥加密时,数据可以使用相同的密钥解密。例如,如果Mary使用“my-secret”密钥加密消息并将其发送给John,他将能够使用相同的“my-secret”密钥正确解密消息。

非对称算法

两个密钥用于加密和解密消息。虽然一个密钥(公共)用于加密消息,但另一个密钥(私有)只能用于解密消息。因此,John可以同时生成公钥和私钥,然后只将公钥发送给Mary以加密她的消息。该消息只能使用私钥解密。

HS256和RS256场景

这些算法不用于加密/解密数据。相反,它们被用来验证数据的来源或真实性。当Mary需要向Jhon发送一个开放消息时,Jhon需要验证该消息确实来自Mary,可以使用HS256或RS256。

HS256可以使用单个密钥为给定的数据示例创建签名。当消息与签名一起传输时,接收方可以使用相同的密钥来验证签名是否与消息匹配。

RS256使用一对密钥来做同样的事情。签名只能使用私钥生成。并且必须使用公钥来验证签名。在这种情况下,即使Jack找到了公钥,他也不能创建带有签名的欺骗消息来模仿Mary。

在性能上是有区别的。

简单地说,HS256在验证方面比RS256快一个数量级,但在签发(签名)方面比RS256快两个数量级。

 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)

不要拘泥于实际的数字,只要考虑到它们之间的相互尊重。

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

简而言之,针对OAuth2,

  • HS256用户客户端秘密来生成令牌签名,并且需要相同的秘密来在后端验证令牌。因此,您应该在后端服务器中拥有该秘密的副本,以验证签名。
  • RS256使用公钥加密对令牌进行签名。签名(哈希)将使用私钥创建,并且可以使用公钥进行验证。因此,不需要将私钥或客户端秘密存储在后端服务器中,但后端服务器将从租户(https://(租户)/ .well-known / openid-configuration)中的openid配置url中获取公钥来验证令牌。access_toekn中的KID参数将用于从openid-configuration中检测正确的密钥(公共)。