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

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

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


当前回答

简而言之,针对OAuth2,

HS256 user client secret to generate the token signature and same secret is required to validate the token in back-end. So you should have a copy of that secret in your back-end server to verify the signature. RS256 use public key encryption to sign the token.Signature(hash) will create using private key and it can verify using public key. So, no need of private key or client secret to store in back-end server, but back-end server will fetch the public key from openid configuration url in your tenant (https://[tenant]/.well-known/openid-configuration) to verify the token. KID parameter inside the access_toekn will use to detect the correct key(public) from openid-configuration.

其他回答

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

RS256 (RSA Signature with SHA-256) is an asymmetric algorithm, and it uses a public/private key pair: the identity provider has a private (secret) key used to generate the signature, and the consumer of the JWT gets a public key to validate the signature. Since the public key, as opposed to the private key, doesn't need to be kept secured, most identity providers make it easily available for consumers to obtain and use (usually through a metadata URL). HS256 (HMAC with SHA-256), on the other hand, involves a combination of a hashing function and one (secret) key that is shared between the two parties used to generate the hash that will serve as the signature. Since the same key is used both to generate the signature and to validate it, care must be taken to ensure that the key is not compromised.

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

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

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

例如,OIDC元数据端点采用https://{account domain}/. famous /openid-configuration的形式。如果您浏览到该URL,您将看到一个JSON对象,其中引用了https://{account domain}/. famous /jwks。json,其中包含帐户的公钥(或密钥),表示为json Web key Set。

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

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

对称算法

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

非对称算法

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

HS256和RS256场景

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

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

RS256使用一对密钥来做同样的事情。签名只能使用私钥生成。并且必须使用公钥来验证签名。在这种情况下,即使Jack找到了公钥,他也不能创建带有签名的欺骗消息来模仿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 user client secret to generate the token signature and same secret is required to validate the token in back-end. So you should have a copy of that secret in your back-end server to verify the signature. RS256 use public key encryption to sign the token.Signature(hash) will create using private key and it can verify using public key. So, no need of private key or client secret to store in back-end server, but back-end server will fetch the public key from openid configuration url in your tenant (https://[tenant]/.well-known/openid-configuration) to verify the token. KID parameter inside the access_toekn will use to detect the correct key(public) from openid-configuration.