RS256 против HS256: какая разница?

255

Я использую 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

Ответы:

435

Оба варианта относятся к тому, какой алгоритм провайдер идентификации использует для подписи JWT. Подписание - это криптографическая операция, которая генерирует «подпись» (часть JWT), которую получатель токена может проверить, чтобы убедиться, что токен не был подделан.

  • RS256 (подпись RSA с 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 разделяет ключ между двумя сторонами, что делает этот алгоритм неспособным поддерживать несколько аудиторий в одном access_token, тогда как RS256 может поддерживать множество аудиторий. Это имеет значение для клиентов Identity, таких как Auth0, которые разрешают запрос к конечной точке / userinfo только с помощью access_token, если конфигурация RS256, поскольку им нужен этот токен для поддержки вашего домена api в качестве aud, а также их домена auth0.
Jezpez
95

В криптографии используются два типа алгоритмов:

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

Один ключ используется для шифрования данных. При шифровании с помощью ключа данные могут быть расшифрованы с использованием того же ключа. Если, например, Мэри зашифрует сообщение с помощью ключа «мой секрет» и отправит его Джону, он сможет правильно расшифровать сообщение с помощью того же ключа «мой секрет».

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

Два ключа используются для шифрования и дешифрования сообщений. В то время как один ключ (открытый) используется для шифрования сообщения, другой ключ (частный) может использоваться только для его расшифровки. Таким образом, Джон может генерировать как открытый, так и закрытый ключи, а затем отправлять только открытый ключ Мэри, чтобы зашифровать ее сообщение. Сообщение может быть расшифровано только с помощью закрытого ключа.

Сценарий HS256 и RS256

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

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

RS256 использует пару ключей, чтобы сделать то же самое. Подпись может быть сгенерирована только с использованием закрытого ключа. И открытый ключ должен быть использован для проверки подписи. В этом случае, даже если Джек найдет открытый ключ, он не сможет создать поддельное сообщение с подписью, чтобы выдать себя за Мэри.

Чарли
источник
39

Есть разница в производительности.

Проще говоря 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.
        }
    }
}
Джон Лейдегрен
источник
Это важные цифры. Спасибо. Я склонен думать о шифровании как о более или менее прозрачном по отношению к пропускной способности, но ваши исследования предполагают, что использование 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 будет использоваться для определения правильного ключа (открытого) из openid-конфигурации.
высокоточная радионавигационная система
источник