RS256 проти HS256: в чому різниця?


254

Я використовую Auth0 для обробки автентифікації у своєму веб-додатку. Я використовую ASP.NET Core v1.0.0 і Angular 2 rc5, і я взагалі не знаю багато про автентифікацію / безпеку.

У документах Auth0 для ASP.NET Core Web Api є два варіанти для алгоритму JWT: RS256 та HS256. Це може бути німим питанням, але:

Яка різниця між RS256 та HS256? Які існують випадки використання (якщо застосовується)?


Я знайшов Angular2-JWT з firbase / php-Jwt у навчальному посібнику для додатків на сервері freakyjolly.com/…
Code Spy

Відповіді:


437

Обидва варіанти посилаються на те, який алгоритм постачальник ідентифікаційних даних використовує для підписання JWT. Підписання - це криптографічна операція, яка генерує "підпис" (частина JWT), яку одержувач жетону може підтвердити, щоб гарантувати, що маркер не був підроблений.

  • RS256 (RSA Signature with SHA-256 ) - це асиметричний алгоритм , і він використовує пара публічних / приватних ключів: постачальник ідентифікаційних даних має приватний (секретний) ключ, який використовується для створення підпису, а споживач JWT отримує відкритий ключ для підтвердження підпису. Оскільки відкритий ключ, на відміну від приватного ключа, не потрібно захищати, більшість постачальників ідентифікаційних даних забезпечує його доступність для споживачів для отримання та використання (зазвичай через URL-адресу метаданих).

  • HS256 ( HMAC з SHA-256), з іншого боку, включає комбінацію хеш-функції та одного (секретного) ключа, який ділиться між двома сторонами, використовуваними для створення хеша, який буде служити підписом. Оскільки один і той же ключ використовується як для генерування підпису, так і для підтвердження його, слід подбати про те, щоб ключ не був порушений.

Якщо ви будете розробляти додаток, що споживає JWT, ви можете сміливо використовувати HS256, оскільки ви будете контролювати, хто використовує секретні ключі. Якщо, з іншого боку, у вас немає контролю над клієнтом, або у вас немає способу закріпити секретний ключ, RS256 буде краще підходити, оскільки споживачеві потрібно знати лише відкритий (загальний) ключ.

Оскільки відкритий ключ зазвичай надається з кінцевих точок метаданих, клієнти можуть бути запрограмовані автоматично отримувати відкритий ключ. Якщо це так (як це відбувається з бібліотеками .Net Core), вам доведеться менше працювати над налаштуванням (бібліотеки отримають відкритий ключ із сервера). З іншого боку, симетричні клавіші потрібно обміняти поза межами діапазону (забезпечуючи захищений канал зв'язку) та оновити вручну, якщо є перехід клавіші підпису.

Auth0 надає кінцеві точки метаданих для протоколів OIDC, SAML та WS-Fed, де відкриті ключі можна отримати. Ви можете побачити ці кінцеві точки у розділі "Розширені налаштування" клієнта.

Наприклад, кінцева точка метаданих OIDC приймає форму https://{account domain}/.well-known/openid-configuration. Якщо перейти до цієї URL-адреси, ви побачите об’єкт JSON із посиланням на https://{account domain}/.well-known/jwks.json, який містить відкритий ключ (або ключі) облікового запису.

Якщо ви подивитеся на зразки RS256, ви побачите, що не потрібно налаштовувати відкритий ключ ніде: він автоматично отримується рамкою.


46
Зверніть увагу, що при використанні rs256 - у багатьох бібліотеках існує (або був) ризик безпеки, який дозволив маркеру визначити, який алгоритм використовувати. По суті, зловмисник може використовувати відкритий ключ rs256 з кодуванням hs256, щоб зробити вигляд, що це секретний ключ. Тому переконайтеся, що у вашій бібліотеці немає такої поведінки!
AlexFoxGill

7
Одне невелике виправлення, "HS256 (HMAC з SHA-256), з іншого боку, є симетричним алгоритмом" - HMAC не використовує алгоритм симетричного ключа (який дозволив би зашифрувати та розшифрувати підпис за його визначенням). Він використовує криптографічну хеш-функцію та секретний криптографічний ключ під HMAC . Що означає розрахунок хеша (функція в одну сторону) над повідомленням із доданим секретним ключем.
Кікоз

1
Приклад з Google: Перейти до accounts.google.com/.well-known/openid-configuration і подивитися на jwks_uri; він пересилає вас на googleapis.com/oauth2/v3/certs, де ви можете знайти ключі. Тоді вам просто потрібно отримати гарний ключ від його дитини.
Денис TRUFFAUT

Варто зазначити, що HS256 ділиться ключем між двома сторонами, що робить цей алгоритм не в змозі підтримувати кілька аудиторій в одному доступі доступу, тоді як RS256 може підтримувати багато аудиторій. Це має значення для клієнтів Identity, таких як Auth0, які дозволяють запит до кінцевої точки / userinfo, використовуючи access_token, якщо конфігурація RS256, оскільки їм потрібен цей маркер для підтримки вашого домену api в якості аудиту, а також їх домену auth0.
jezpez

94

У криптографії використовується два типи алгоритмів:

Симетричні алгоритми

Для шифрування даних використовується один ключ. При зашифрованому ключі дані можна розшифрувати за допомогою того самого ключа. Якщо, наприклад, Мері зашифрує повідомлення за допомогою ключа "моя таємниця" і надішле його Іоану, він зможе правильно розшифрувати повідомлення тим самим ключем "моя таємниця".

Асиметричні алгоритми

Дві клавіші використовуються для шифрування та розшифровки повідомлень. Хоча один ключ (загальнодоступний) використовується для шифрування повідомлення, інший ключ (приватний) може використовуватися лише для його розшифровки. Отже, Джон може генерувати як відкриті, так і приватні ключі, а потім надсилати Марії лише відкритий ключ, щоб зашифрувати її повідомлення. Повідомлення можна розшифрувати лише за допомогою приватного ключа.

Сценарій HS256 та RS256

Ці алгоритми НЕ використовуються для шифрування / дешифрування даних. Вони скоріше використовуються для перевірки походження або достовірності даних. Коли Марії потрібно надіслати відкрите повідомлення Джону, і він повинен переконатися, що повідомлення, безумовно, від Марії, HS256 або RS256 можна використовувати.

HS256 може створити підпис для даного зразка даних за допомогою одного ключа. Коли повідомлення передається разом із підписом, сторона, що отримує, може використовувати той самий ключ, щоб перевірити, чи відповідає підпис цьому підпису.

RS256 використовує пару клавіш, щоб зробити те саме. Підпис можна генерувати лише за допомогою приватного ключа. І відкритий ключ повинен використовуватися для перевірки підпису. У цьому випадку, навіть якщо Джек знайде відкритий ключ, він не може створити підробне повідомлення з підписом, щоб видати себе за Мері.


38

Є різниця у продуктивності.

Простіше кажучи, HS256це приблизно на 1 порядок швидше, ніж RS256для перевірки, але приблизно на 2 порядки швидше, ніж RS256для видачі (підписання).

 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 вимагає спільного використання ключа, який може підписати І підтвердити - корисний лише в тому випадку, якщо ви довіряєте двом сторонам або не потрібно одній із сторін, щоб щось розшифрувати.
Роб Еванс

7
@RobEvans так, не зациклюйтесь на номерах продуктивності тут. Виберіть правильне рішення вашої проблеми. Це лише спостереження, а не рекомендація щодо переваги HS256 над RS256. Ви повинні приймати це рішення залежно від вашого контексту.
Джон Лейдегрен

1
Коли вибір протоколу може мати такий же вплив на затримку, що й додатковий кілометр кабелю, це варто знати, особливо в наші дні довгих ланцюжків дзвінків та щільних TTL.
Меттью Марк Міллер

0

коротка відповідь, характерна для OAuth2,

  • Таємниця клієнта користувача HS256 для генерації підпису токена та така сама таємниця потрібна для перевірки маркерів в бек- енді . Отже, ви повинні мати копію цього секрету на своєму бек-сервері, щоб перевірити підпис.
  • RS256 використовує шифрування відкритого ключа для підписання токена. Підпис (хеш) буде створений за допомогою приватного ключа, і він може перевірити, використовуючи відкритий ключ. Отже, для зберігання на бек-енд-сервері не потрібно закривати приватний ключ або клієнтську таємницю, але бек-сервер отримає відкритий ключ із URL-адреси конфігурації openid у вашого орендатора ( https: // [tenant] /.well-known/openid -конфігурація ) для перевірки маркера. Параметр KID всередині access_toekn буде використовувати для виявлення правильного ключа (public) з конфігурації openid.
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.