RS256 与 HS256:有什么区别?
RS256 vs HS256: What's the difference?
我正在使用 Auth0 处理我的网络应用程序中的身份验证。我正在使用 ASP.NET Core v1.0.0 和 Angular 2 rc5,我对 authentication/security 了解不多。
在Auth0 docs for ASP.NET Core Web Api中,JWT算法有RS256和HS256两种选择。这可能是一个愚蠢的问题,但是:
RS256和HS256有什么区别?有哪些用例(如果适用)?
这两种选择都指的是身份提供者使用什么算法来签署 JWT。签名是一种加密操作,它生成一个“签名”(JWT 的一部分),令牌的接收者可以验证该签名以确保令牌未被篡改。
RS256(带有 SHA-256) is an asymmetric algorithm 的 RSA 签名,它使用 public/private 密钥对:身份提供者有一个用于生成签名的私钥,并且JWT 的消费者得到一个 public 密钥来验证签名。由于 public 密钥,而不是私钥,不需要保持安全,大多数身份提供者都可以轻松获得它供消费者获取和使用(通常通过元数据URL)。
另一方面,HS256(HMAC 与 SHA-256)涉及哈希函数和一个(秘密)密钥的组合,该密钥在双方之间共享,用于生成将用作签名的散列。由于同一密钥用于生成签名和验证签名,因此必须小心确保密钥不被泄露。
如果您要开发使用 JWT 的应用程序,您可以安全地使用 HS256,因为您可以控制谁使用密钥。
另一方面,如果您无法控制客户端,或者您无法保护密钥,RS256 将更适合,因为消费者只需要知道 public(共享) 键。
由于 public 密钥通常可从元数据端点获得,因此可以对客户端进行编程以自动检索 public 密钥。如果是这种情况(与 .Net Core 库一样),您在配置上要做的工作就会更少(这些库将从服务器获取 public 密钥)。另一方面,对称密钥需要带外交换(确保安全的通信通道),并在签名密钥翻转时手动更新。
Auth0 为 OIDC、SAML 和 WS-Fed 协议提供元数据端点,可以在其中检索 public 密钥。您可以在客户端的“高级设置”下看到这些端点。
例如,OIDC 元数据端点采用 https://{account domain}/.well-known/openid-configuration
的形式。如果您浏览到那个 URL,您将看到一个 JSON 对象引用 https://{account domain}/.well-known/jwks.json
,其中包含帐户的 public 键(或键),表示为JSON Web Key Set.
如果您查看 RS256 示例,您会发现不需要在任何地方配置 public 键:它由框架自动检索。
密码学中使用了两种算法:
对称算法
单个密钥用于加密数据。使用密钥加密后,可以使用相同的密钥对数据进行解密。例如,如果 Mary 使用密钥 "my-secret" 加密消息并将其发送给 John,他将能够使用相同的密钥 "my-secret" 正确解密消息。
非对称算法
两个密钥用于加密和解密消息。虽然一个密钥(public)用于加密消息,但另一个密钥(私有)只能用于解密它。因此,John 可以生成 public 和私钥,然后仅将 public 密钥发送给 Mary 以加密她的消息。消息只能使用私钥解密。
HS256和RS256场景
这些算法不用于 encrypt/decryt 数据。相反,它们用于验证数据的来源或真实性。当Mary需要向Jhon发送一条公开消息,而Jhon需要验证消息是否确实来自Mary时,可以使用HS256或RS256。
HS256 可以使用单个密钥为给定的数据样本创建签名。当消息与签名一起传输时,接收方可以使用相同的密钥来验证签名是否与消息匹配。
RS256 使用一对密钥来做同样的事情。只能使用私钥生成签名。并且必须使用 public 密钥来验证签名。在这种情况下,即使 Jack 找到了 public 密钥,他也无法创建带有签名的欺骗消息来冒充 Mary。
性能有差异。
简单的说HS256
在验证上比RS256
快1个数量级左右,在签发(签名)上比RS256
快2个数量级左右。
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 使用 public 密钥加密来签名 token.Signature(hash) 将使用私钥创建并且可以使用 public 进行验证钥匙。因此,不需要将私钥或客户端机密存储在后端服务器中,但后端服务器将从您的租户 (https://[tenant]/.well-known/openid-configuration) 中的 openid 配置 url 中获取 public 密钥验证令牌。 access_toekn 中的 KID 参数将用于从 openid-configuration 中检测正确的密钥 (public)。
我正在使用 Auth0 处理我的网络应用程序中的身份验证。我正在使用 ASP.NET Core v1.0.0 和 Angular 2 rc5,我对 authentication/security 了解不多。
在Auth0 docs for ASP.NET Core Web Api中,JWT算法有RS256和HS256两种选择。这可能是一个愚蠢的问题,但是:
RS256和HS256有什么区别?有哪些用例(如果适用)?
这两种选择都指的是身份提供者使用什么算法来签署 JWT。签名是一种加密操作,它生成一个“签名”(JWT 的一部分),令牌的接收者可以验证该签名以确保令牌未被篡改。
RS256(带有 SHA-256) is an asymmetric algorithm 的 RSA 签名,它使用 public/private 密钥对:身份提供者有一个用于生成签名的私钥,并且JWT 的消费者得到一个 public 密钥来验证签名。由于 public 密钥,而不是私钥,不需要保持安全,大多数身份提供者都可以轻松获得它供消费者获取和使用(通常通过元数据URL)。
另一方面,HS256(HMAC 与 SHA-256)涉及哈希函数和一个(秘密)密钥的组合,该密钥在双方之间共享,用于生成将用作签名的散列。由于同一密钥用于生成签名和验证签名,因此必须小心确保密钥不被泄露。
如果您要开发使用 JWT 的应用程序,您可以安全地使用 HS256,因为您可以控制谁使用密钥。 另一方面,如果您无法控制客户端,或者您无法保护密钥,RS256 将更适合,因为消费者只需要知道 public(共享) 键。
由于 public 密钥通常可从元数据端点获得,因此可以对客户端进行编程以自动检索 public 密钥。如果是这种情况(与 .Net Core 库一样),您在配置上要做的工作就会更少(这些库将从服务器获取 public 密钥)。另一方面,对称密钥需要带外交换(确保安全的通信通道),并在签名密钥翻转时手动更新。
Auth0 为 OIDC、SAML 和 WS-Fed 协议提供元数据端点,可以在其中检索 public 密钥。您可以在客户端的“高级设置”下看到这些端点。
例如,OIDC 元数据端点采用 https://{account domain}/.well-known/openid-configuration
的形式。如果您浏览到那个 URL,您将看到一个 JSON 对象引用 https://{account domain}/.well-known/jwks.json
,其中包含帐户的 public 键(或键),表示为JSON Web Key Set.
如果您查看 RS256 示例,您会发现不需要在任何地方配置 public 键:它由框架自动检索。
密码学中使用了两种算法:
对称算法
单个密钥用于加密数据。使用密钥加密后,可以使用相同的密钥对数据进行解密。例如,如果 Mary 使用密钥 "my-secret" 加密消息并将其发送给 John,他将能够使用相同的密钥 "my-secret" 正确解密消息。
非对称算法
两个密钥用于加密和解密消息。虽然一个密钥(public)用于加密消息,但另一个密钥(私有)只能用于解密它。因此,John 可以生成 public 和私钥,然后仅将 public 密钥发送给 Mary 以加密她的消息。消息只能使用私钥解密。
HS256和RS256场景
这些算法不用于 encrypt/decryt 数据。相反,它们用于验证数据的来源或真实性。当Mary需要向Jhon发送一条公开消息,而Jhon需要验证消息是否确实来自Mary时,可以使用HS256或RS256。
HS256 可以使用单个密钥为给定的数据样本创建签名。当消息与签名一起传输时,接收方可以使用相同的密钥来验证签名是否与消息匹配。
RS256 使用一对密钥来做同样的事情。只能使用私钥生成签名。并且必须使用 public 密钥来验证签名。在这种情况下,即使 Jack 找到了 public 密钥,他也无法创建带有签名的欺骗消息来冒充 Mary。
性能有差异。
简单的说HS256
在验证上比RS256
快1个数量级左右,在签发(签名)上比RS256
快2个数量级左右。
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 使用 public 密钥加密来签名 token.Signature(hash) 将使用私钥创建并且可以使用 public 进行验证钥匙。因此,不需要将私钥或客户端机密存储在后端服务器中,但后端服务器将从您的租户 (https://[tenant]/.well-known/openid-configuration) 中的 openid 配置 url 中获取 public 密钥验证令牌。 access_toekn 中的 KID 参数将用于从 openid-configuration 中检测正确的密钥 (public)。