RS256 vs HS256: Apa bedanya?

254

Saya menggunakan Auth0 untuk menangani otentikasi di aplikasi web saya. Saya menggunakan ASP.NET Core v1.0.0 dan Angular 2 rc5 dan saya tidak tahu banyak tentang otentikasi / keamanan secara umum.

Dalam dokumen Auth0 untuk ASP.NET Core Web Api , ada dua pilihan untuk algoritma JWT yaitu RS256 dan HS256. Ini mungkin pertanyaan bodoh tapi:

Apa perbedaan antara RS256 dan HS256? Apa sajakah kasus penggunaan (jika ada)?

Rico Kahler
sumber
Saya menemukan Angular2-JWT dengan firbase / php-Jwt di tutorial aplikasi sisi server freakyjolly.com/...
Code Spy

Jawaban:

437

Kedua pilihan merujuk pada algoritma apa yang digunakan penyedia identitas untuk menandatangani JWT. Penandatanganan adalah operasi kriptografi yang menghasilkan "tanda tangan" (bagian dari JWT) yang dapat divalidasi oleh penerima token untuk memastikan bahwa token tersebut belum dirusak.

  • RS256 (RSA Signature dengan SHA-256 ) adalah algoritma asimetris , dan menggunakan pasangan kunci publik / pribadi: penyedia identitas memiliki kunci pribadi (rahasia) yang digunakan untuk menghasilkan tanda tangan, dan konsumen JWT mendapatkan kunci publik untuk memvalidasi tanda tangan. Karena kunci publik, tidak seperti kunci pribadi, tidak perlu dijaga keamanannya, sebagian besar penyedia identitas membuatnya mudah tersedia bagi konsumen untuk mendapatkan dan menggunakan (biasanya melalui URL metadata).

  • HS256 ( HMAC dengan SHA-256), di sisi lain, melibatkan kombinasi fungsi hashing dan satu kunci (rahasia) yang dibagi antara dua pihak yang digunakan untuk menghasilkan hash yang akan berfungsi sebagai tanda tangan. Karena kunci yang sama digunakan baik untuk menghasilkan tanda tangan dan untuk memvalidasinya, perhatian harus diberikan untuk memastikan bahwa kunci tersebut tidak dikompromikan.

Jika Anda akan mengembangkan aplikasi yang menggunakan JWT, Anda dapat menggunakan HS256 dengan aman, karena Anda akan memiliki kontrol pada siapa yang menggunakan kunci rahasia. Jika, di sisi lain, Anda tidak memiliki kendali atas klien, atau Anda tidak memiliki cara untuk mengamankan kunci rahasia, RS256 akan lebih cocok, karena konsumen hanya perlu mengetahui kunci publik (dibagi).

Karena kunci publik biasanya tersedia dari titik akhir metadata, klien dapat diprogram untuk mengambil kunci publik secara otomatis. Jika ini masalahnya (seperti halnya dengan pustaka .Net Core), Anda akan memiliki lebih sedikit pekerjaan yang harus dilakukan pada konfigurasi (pustaka akan mengambil kunci publik dari server). Kunci simetris, di sisi lain, perlu ditukar keluar dari band (memastikan saluran komunikasi yang aman), dan diperbarui secara manual jika ada rollover kunci penandatanganan.

Auth0 menyediakan titik akhir metadata untuk protokol OIDC, SAML dan WS-Fed, di mana kunci publik dapat diambil. Anda dapat melihat titik akhir tersebut di bawah "Pengaturan Lanjut" dari klien.

Titik akhir metadata OIDC, misalnya, berbentuk https://{account domain}/.well-known/openid-configuration. Jika Anda meramban ke URL itu, Anda akan melihat objek JSON dengan referensi https://{account domain}/.well-known/jwks.json, yang berisi kunci publik (atau kunci) dari akun tersebut.

Jika Anda melihat sampel RS256, Anda akan melihat bahwa Anda tidak perlu mengkonfigurasi kunci publik di mana saja: itu diambil secara otomatis oleh kerangka kerja.

Nico Sabena
sumber
46
NB saat menggunakan rs256 - ada (atau) risiko keamanan di banyak perpustakaan yang memungkinkan token untuk menentukan algoritma yang digunakan. Pada dasarnya penyerang bisa menggunakan kunci rs256 publik dengan pengkodean hs256 untuk berpura-pura itu adalah kunci rahasia. Jadi pastikan perpustakaan Anda tidak memiliki perilaku ini!
AlexFoxGill
7
Satu koreksi kecil, "HS256 (HMAC dengan SHA-256), di sisi lain, adalah algoritma simetris" - HMAC tidak menggunakan algoritma kunci-simetris (yang akan memungkinkan Anda untuk mengenkripsi dan mendekripsi tanda tangan dengan definisinya). Ini menggunakan fungsi hash kriptografi dan kunci kriptografi rahasia di bawah HMAC . Yang menyiratkan perhitungan hash (fungsi satu arah) atas pesan dengan kunci rahasia yang ditambahkan.
Kikoz
1
Misalnya dengan Google: Pergi ke accounts.google.com/.well-known/openid-configuration dan melihat jwks_uri; itu meneruskan Anda ke googleapis.com/oauth2/v3/certs di mana Anda dapat menemukan kunci. Maka Anda hanya perlu mengambil kunci yang baik oleh anaknya.
Denis TRUFFAUT
Perlu dicatat bahwa sebagai HS256 berbagi kunci antara dua pihak yang membuat algoritma ini tidak dapat mendukung banyak audiens dalam satu access_token, sedangkan RS256 dapat mendukung banyak audiens. Ini penting bagi klien Identity seperti Auth0 yang hanya mengizinkan permintaan ke titik akhir / userinfo menggunakan access_token jika konfigurasinya RS256, karena mereka memerlukan token ini untuk mendukung domain api Anda sebagai aud, dan juga domain auth0 mereka.
jezpez
94

Dalam kriptografi ada dua jenis algoritma yang digunakan:

Algoritma simetris

Satu kunci digunakan untuk mengenkripsi data. Saat dienkripsi dengan kunci, data dapat didekripsi menggunakan kunci yang sama. Jika, misalnya, Mary mengenkripsi pesan menggunakan kunci "rahasia saya" dan mengirimkannya kepada John, ia akan dapat mendekripsi pesan dengan benar dengan kunci yang sama "rahasia saya".

Algoritma asimetris

Dua kunci digunakan untuk mengenkripsi dan mendekripsi pesan. Sementara satu kunci (publik) digunakan untuk mengenkripsi pesan, kunci lainnya (pribadi) hanya dapat digunakan untuk mendekripsi pesan itu. Jadi, John dapat menghasilkan kunci publik dan pribadi, kemudian hanya mengirim kunci publik kepada Mary untuk mengenkripsi pesannya. Pesan hanya dapat didekripsi menggunakan kunci pribadi.

Skenario HS256 dan RS256

Algoritma ini TIDAK digunakan untuk mengenkripsi / mendekripsi data. Sebaliknya mereka digunakan untuk memverifikasi asal atau keaslian data. Ketika Mary perlu mengirim pesan terbuka ke Jhon dan ia perlu memverifikasi bahwa pesan tersebut pasti dari Mary, HS256 atau RS256 dapat digunakan.

HS256 dapat membuat tanda tangan untuk sampel data tertentu menggunakan kunci tunggal. Ketika pesan dikirimkan bersama dengan tanda tangan, pihak penerima dapat menggunakan kunci yang sama untuk memverifikasi bahwa tanda tangan cocok dengan pesan.

RS256 menggunakan sepasang tombol untuk melakukan hal yang sama. Tanda tangan hanya dapat dibuat menggunakan kunci pribadi. Dan kunci publik harus digunakan untuk memverifikasi tanda tangan. Dalam skenario ini, bahkan jika Jack menemukan kunci publik, ia tidak dapat membuat pesan palsu dengan tanda tangan untuk meniru Mary.

Charlie
sumber
39

Ada perbedaan kinerja.

Sederhananya HS256adalah sekitar 1 urutan lebih cepat dari pada RS256untuk verifikasi tetapi sekitar 2 urutan lebih cepat dari pada RS256untuk penerbitan (penandatanganan).

 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)

Jangan terpaku pada angka sebenarnya, pikirkan saja mereka dengan hormat satu sama lain.

[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.
        }
    }
}
John Leidegren
sumber
Ini adalah angka penting. Terima kasih. Saya cenderung menganggap enkripsi sebagai throughput wrt yang kurang lebih transparan, tetapi penelitian Anda menyiratkan bahwa menggunakan R256 untuk menandatangani komunikasi antar mesin menambah 1 ms per hop.
Matthew Mark Miller
1
@MatthewMarkMiller Perlu diingat bahwa keduanya tidak sama digunakan. Mereka memiliki karakteristik berbeda. RS256 asimetris dan karenanya dalam komunikasi gaya klien / server di mana Anda hanya berbagi kunci publik, itu adalah pilihan yang lebih baik. HS256 membutuhkan berbagi kunci yang bisa masuk DAN memverifikasi - hanya berguna jika Anda memercayai kedua pihak atau tidak membutuhkan salah satu pihak untuk mendekripsi apa pun.
Rob Evans
7
@RobEvans ya, jangan terpaku pada angka kinerja di sini. Pilih solusi yang tepat untuk masalah Anda. Ini hanya pengamatan, bukan rekomendasi untuk mendukung HS256 daripada RS256 Anda harus membuat keputusan berdasarkan konteks Anda.
John Leidegren
1
Ketika pilihan protokol dapat memiliki dampak yang sama pada latensi sebagai kilometer ekstra kabel, itu perlu diketahui, terutama di hari-hari ini rantai panggilan panjang dan TTL ketat.
Matius Mark Miller
0

jawaban singkat, khusus untuk OAuth2,

  • Rahasia klien pengguna HS256 untuk menghasilkan token signature dan rahasia yang sama diperlukan untuk memvalidasi token di back-end. Jadi, Anda harus memiliki salinan rahasia itu di server back-end Anda untuk memverifikasi tanda tangan.
  • RS256 menggunakan enkripsi kunci publik untuk menandatangani token. Tanda tangan (hash) akan dibuat menggunakan kunci pribadi dan dapat memverifikasi menggunakan kunci publik. Jadi, tidak perlu kunci pribadi atau rahasia klien untuk disimpan di server back-end, tetapi server back-end akan mengambil kunci publik dari url konfigurasi openid di penyewa Anda ( https: // [tenant] /.well-known/openid -configuration ) untuk memverifikasi token. Parameter KID di dalam access_toekn akan digunakan untuk mendeteksi kunci yang benar (publik) dari konfigurasi openid.
Hiran
sumber