RS256とHS256:違いは何ですか?


254

Webアプリで認証を処理するためにAuth0を使用しています。ASP.NET Core v1.0.0とAngular 2 rc5を使用していますが、認証/セキュリティ一般についてはあまり知りません。

ASP.NET Core Web ApiAuth0ドキュメントでは、JWTアルゴリズムにRS256とHS256の2つの選択肢があります。これは馬鹿げた質問かもしれませんが:

RS256とHS256の違いは何ですか?いくつかのユースケース(該当する場合)は何ですか?


サーバーサイドアプリケーションのチュートリアルfreakyjolly.com/…
Code Spy

回答:


437

どちらの選択肢も、IDプロバイダーがJWT への署名に使用するアルゴリズムを示します。署名は、トークンの改ざんが行われていないことを確認するためにトークンの受信者が検証できる「署名」(JWTの一部)を生成する暗号化操作です。

  • RS256(SHA-256を使用したRSA署名)は非対称アルゴリズムであり、公開鍵と秘密鍵のペアを使用します。ID プロバイダーには署名の生成に使用される秘密(秘密)鍵があり、JWTのコンシューマーは公開鍵を取得します署名を検証します。公開鍵は、秘密鍵とは異なり、安全を保つ必要がないため、ほとんどのIDプロバイダーは、消費者が(通常はメタデータURLを介して)取得して使用できるように簡単に利用できるようにします。

  • 一方、HS256(SHA-256を使用したHMAC)には、ハッシュ関数と、署名として機能するハッシュの生成に使用される2つのパーティ間で共有される1つの(秘密)キーの組み合わせが含まれます。署名の生成と検証の両方に同じキーが使用されるため、キーが危険にさらされないように注意する必要があります。

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オブジェクトが表示されます。

RS256サンプルを見ると、公開鍵をどこにも構成する必要がないことがわかります。公開鍵はフレームワークによって自動的に取得されます。


46
rs256を使用する場合の注意- 多くのライブラリには、使用するアルゴリズムをトークンが決定できるようにするセキュリティリスクがあります(またはありました)。基本的に、攻撃者はhs256エンコーディングを使用して公開rs256キーを使用し、秘密キーであると偽ることができます。そのため、ライブラリにこの動作がないことを確認してください。
AlexFoxGill

7
1つの小さな修正、「HS256(SHA-256を使用したHMAC)は対称アルゴリズムです」-HMACは対称鍵アルゴリズムを使用していません(その定義により署名を暗号化および復号化できます)。暗号化ハッシュ関数とHMACの下の秘密暗号化キーを利用します。これは、秘密鍵が追加されたメッセージのハッシュ(一方向関数)の計算を意味します。
Kikoz

1
Googleの例:accounts.google.com/.well-known/openid-configurationに移動してjwks_uriを確認します。キーを見つけることができるgoogleapis.com/oauth2/v3/certsに転送します。次に、その子供によって適切なキーを取得する必要があります。
Denis TRUFFAUT

HS256は2つのパーティ間でキーを共有するため、このアルゴリズムでは1つのaccess_tokenで複数のオーディエンスをサポートできませんが、RS256は多くのオーディエンスをサポートできることに注意してください。これは、構成がRS256である場合にaccess_tokenを使用した/ userinfoエンドポイントへのリクエストのみを許可するAuth0のようなIdentityクライアントで重要です。
jezpez

94

暗号化では、2種類のアルゴリズムが使用されます。

対称アルゴリズム

単一のキーがデータの暗号化に使用されます。キーで暗号化すると、同じキーを使用してデータを復号化できます。たとえば、メアリーがキー「my-secret」を使用してメッセージを暗号化し、それをジョンに送信した場合、メアリーは同じキー「my-secret」でメッセージを正しく復号化できます。

非対称アルゴリズム

メッセージの暗号化と復号化には2つのキーが使用されます。1つのキー(公開)はメッセージの暗号化に使用されますが、もう1つのキー(秘密)はメッセージの復号化にのみ使用できます。したがって、ジョンは公開キーと秘密キーの両方を生成し、メッセージを暗号化するために公開キーのみをメアリーに送信できます。メッセージは、秘密鍵を使用してのみ復号化できます。

HS256およびRS256シナリオ

これらのアルゴリズムは、データの暗号化/復号化には使用されません。むしろ、それらはデータの出所または信頼性を検証するために使用されます。メアリーがオープンメッセージをジョンに送信する必要があり、メアリーからのメッセージであることを確認する必要がある場合、HS256またはRS256を使用できます。

HS256は、単一のキーを使用して、特定のデータサンプルの署名を作成できます。メッセージが署名とともに送信されると、受信側は同じキーを使用して、署名がメッセージと一致することを確認できます。

RS256は、キーのペアを使用して同じことを行います。署名は、秘密鍵を使用してのみ生成できます。また、署名の検証には公開鍵を使用する必要があります。このシナリオでは、ジャックが公開キーを見つけたとしても、メアリーを偽装するための署名付きのなりすましメッセージを作成することはできません。


39

性能に違いがあります。

簡単に言えば、検証HS256よりも約1 RS256桁高速ですが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.
        }
    }
}

これらは重要な数字です。ありがとうございました。暗号化は多かれ少なかれ透過的なwrtスループットであると考えがちですが、R256を使用してマシン間通信に署名すると、ホップあたり1ミリ秒が追加されることを示唆しています。
マシューマークミラー、

1
@MatthewMarkMiller使用方法が同じではないことに注意してください。彼らは異なる特性を持っています。RS256は非対称であるため、公開鍵のみを共有するクライアント/サーバー形式の通信では、より良いオプションです。HS256では、署名と検証の両方が可能な鍵を共有する必要があります。これは、2つの当事者を信頼する場合、またはいずれかの当事者が何かを復号化する必要がない場合にのみ役立ちます。
Rob Evans

7
@RobEvansはい、ここのパフォーマンスの数値にこだわらないでください。あなたの問題に対する正しい解決策を選んでください。これは単なる観察であり、RS256よりもHS256を優先することを推奨するものではなく、コンテキストに基づいてその決定を行う必要があります。
John Leidegren

1
プロトコルの選択がケーブルの追加のキロメートルと同じようにレイテンシに影響を与える可能性がある場合、特に長いコールチェーンと厳しいTTLの今日では、それは知っておく価値があります。
マシューマークミラー

0

OAuth2に固有の短い回答、

  • トークン署名を生成するためのHS256ユーザークライアントシークレット。バックエンドでトークンを検証するには、同じシークレットが必要です。したがって、署名を検証するために、バックエンドサーバーにそのシークレットのコピーが必要です。
  • RS256は、公開鍵暗号化を使用してトークンに署名します。Signature(hash)は、秘密鍵を使用して作成し、公開鍵を使用して検証できます。そのため、バックエンドサーバーに格納するための秘密鍵やクライアントシークレットは必要ありませんが、バックエンドサーバーはテナントのopenid構成URL(https:// [tenant] /.well-known/openid)から公開鍵をフェッチします-構成)トークンを確認します。access_toekn内のKIDパラメータは、openid-configurationから正しいキー(公開)を検出するために使用します。
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.