Webアプリで認証を処理するためにAuth0を使用しています。ASP.NET Core v1.0.0とAngular 2 rc5を使用していますが、認証/セキュリティ一般についてはあまり知りません。
ASP.NET Core Web ApiのAuth0ドキュメントでは、JWTアルゴリズムにRS256とHS256の2つの選択肢があります。これは馬鹿げた質問かもしれませんが:
RS256とHS256の違いは何ですか?いくつかのユースケース(該当する場合)は何ですか?
Webアプリで認証を処理するためにAuth0を使用しています。ASP.NET Core v1.0.0とAngular 2 rc5を使用していますが、認証/セキュリティ一般についてはあまり知りません。
ASP.NET Core Web ApiのAuth0ドキュメントでは、JWTアルゴリズムにRS256とHS256の2つの選択肢があります。これは馬鹿げた質問かもしれませんが:
RS256とHS256の違いは何ですか?いくつかのユースケース(該当する場合)は何ですか?
回答:
どちらの選択肢も、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サンプルを見ると、公開鍵をどこにも構成する必要がないことがわかります。公開鍵はフレームワークによって自動的に取得されます。
暗号化では、2種類のアルゴリズムが使用されます。
対称アルゴリズム
単一のキーがデータの暗号化に使用されます。キーで暗号化すると、同じキーを使用してデータを復号化できます。たとえば、メアリーがキー「my-secret」を使用してメッセージを暗号化し、それをジョンに送信した場合、メアリーは同じキー「my-secret」でメッセージを正しく復号化できます。
非対称アルゴリズム
メッセージの暗号化と復号化には2つのキーが使用されます。1つのキー(公開)はメッセージの暗号化に使用されますが、もう1つのキー(秘密)はメッセージの復号化にのみ使用できます。したがって、ジョンは公開キーと秘密キーの両方を生成し、メッセージを暗号化するために公開キーのみをメアリーに送信できます。メッセージは、秘密鍵を使用してのみ復号化できます。
HS256およびRS256シナリオ
これらのアルゴリズムは、データの暗号化/復号化には使用されません。むしろ、それらはデータの出所または信頼性を検証するために使用されます。メアリーがオープンメッセージをジョンに送信する必要があり、メアリーからのメッセージであることを確認する必要がある場合、HS256またはRS256を使用できます。
HS256は、単一のキーを使用して、特定のデータサンプルの署名を作成できます。メッセージが署名とともに送信されると、受信側は同じキーを使用して、署名がメッセージと一致することを確認できます。
RS256は、キーのペアを使用して同じことを行います。署名は、秘密鍵を使用してのみ生成できます。また、署名の検証には公開鍵を使用する必要があります。このシナリオでは、ジャックが公開キーを見つけたとしても、メアリーを偽装するための署名付きのなりすましメッセージを作成することはできません。
性能に違いがあります。
簡単に言えば、検証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.
}
}
}
OAuth2に固有の短い回答、