RS256 vs HS256: Jaka jest różnica?

254

Używam Auth0 do obsługi uwierzytelniania w mojej aplikacji internetowej. Używam ASP.NET Core v1.0.0 i Angular 2 rc5 i ogólnie nie wiem dużo na temat uwierzytelniania / bezpieczeństwa.

W dokumentach Auth0 dla ASP.NET Core Web Api istnieją dwie możliwości wyboru algorytmu JWT: RS256 i HS256. To może być głupie pytanie, ale:

Jaka jest różnica między RS256 a HS256? Jakie są przypadki użycia (jeśli dotyczy)?

Rico Kahler
źródło
Znalazłem Angular2-JWT z firbase / php-JWT w aplikacji po stronie serwera poradnik freakyjolly.com/...
Code Spy

Odpowiedzi:

437

Obie opcje dotyczą algorytmu, którego dostawca tożsamości używa do podpisywania JWT. Podpisywanie jest operacją kryptograficzną, która generuje „podpis” (część JWT), który odbiorca tokena może sprawdzić, aby upewnić się, że token nie został zmieniony.

  • RS256 (podpis RSA z SHA-256 ) jest algorytmem asymetrycznym i wykorzystuje parę kluczy publiczny / prywatny: dostawca tożsamości ma klucz prywatny (tajny) używany do generowania podpisu, a konsument JWT otrzymuje klucz publiczny aby potwierdzić podpis. Ponieważ klucz publiczny, w przeciwieństwie do klucza prywatnego, nie musi być zabezpieczony, większość dostawców tożsamości zapewnia konsumentom łatwy dostęp do niego i do korzystania (zwykle za pośrednictwem adresu URL metadanych).

  • Z drugiej strony HS256 ( HMAC z SHA-256) obejmuje kombinację funkcji skrótu i ​​jednego (tajnego) klucza, który jest współdzielony przez dwie strony używane do generowania skrótu, który będzie służył jako podpis. Ponieważ ten sam klucz służy zarówno do generowania podpisu, jak i do jego sprawdzania, należy zadbać o to, aby klucz nie został naruszony.

Jeśli będziesz opracowywać aplikację korzystającą z JWT, możesz bezpiecznie używać HS256, ponieważ będziesz mieć kontrolę nad tym, kto używa tajnych kluczy. Jeśli z drugiej strony nie masz kontroli nad klientem lub nie masz możliwości zabezpieczenia tajnego klucza, RS256 będzie lepiej pasował, ponieważ konsument musi znać tylko klucz publiczny (współdzielony).

Ponieważ klucz publiczny jest zwykle udostępniany z punktów końcowych metadanych, klienci mogą zostać zaprogramowani do automatycznego pobierania klucza publicznego. Jeśli tak jest (tak jak w przypadku bibliotek .Net Core), będziesz mieć mniej pracy do wykonania przy konfiguracji (biblioteki będą pobierać klucz publiczny z serwera). Z drugiej strony klucze symetryczne należy wymieniać poza pasmem (zapewniając bezpieczny kanał komunikacyjny) i ręcznie aktualizować, jeśli występuje rolowanie klucza do podpisywania.

Auth0 zapewnia punkty końcowe metadanych dla protokołów OIDC, SAML i WS-Fed, w których można odzyskać klucze publiczne. Możesz zobaczyć te punkty końcowe w „Ustawieniach zaawansowanych” klienta.

Na przykład punkt końcowy metadanych OIDC ma postać https://{account domain}/.well-known/openid-configuration. Jeśli przejdziesz do tego adresu URL, zobaczysz obiekt JSON z odniesieniem do https://{account domain}/.well-known/jwks.json, który zawiera klucz publiczny (lub klucze) konta.

Jeśli spojrzysz na próbki RS256, zobaczysz, że nigdzie nie musisz konfigurować klucza publicznego: jest on pobierany automatycznie przez framework.

Nico Sabena
źródło
46
Uwaga: w przypadku korzystania z rs256 - w wielu bibliotekach istnieje (lub było) zagrożenie bezpieczeństwa, które pozwoliło tokenowi ustalić, którego algorytmu użyć. Zasadniczo atakujący może użyć publicznego klucza rs256 z kodowaniem hs256, aby udawać, że jest to klucz tajny. Upewnij się więc, że Twoja biblioteka nie ma takiego zachowania!
AlexFoxGill
7
Jedna mała korekta, „HS256 (HMAC z SHA-256), z drugiej strony, jest algorytmem symetrycznym” - HMAC nie wykorzystuje algorytmu klucza symetrycznego (który pozwoliłby na szyfrowanie i deszyfrowanie podpisu według jego definicji). Wykorzystuje kryptograficzną funkcję skrótu i ​​tajny klucz kryptograficzny pod HMAC . Co oznacza obliczenie wartości skrótu (funkcji jednokierunkowej) nad komunikatem z dołączonym tajnym kluczem.
Kikoz
1
Przykład z Google: przejdź do accounts.google.com/.well-known/openid-configuration i spójrz na jwks_uri; przekierowuje cię do googleapis.com/oauth2/v3/certs, gdzie można znaleźć klucze. Następnie musisz tylko odzyskać dobry klucz od jego dziecka.
Denis TRUFFAUT
Warto zauważyć, że ponieważ HS256 dzieli klucz między dwiema stronami, co sprawia, że ​​ten algorytm nie jest w stanie obsłużyć wielu odbiorców w jednym tokenie dostępu, podczas gdy RS256 może obsługiwać wielu odbiorców. Ma to znaczenie w przypadku klientów tożsamości, takich jak Auth0, którzy zezwalają na żądanie do punktu końcowego / userinfo przy użyciu tokenu dostępu, jeśli konfiguracja to RS256, ponieważ potrzebują tego tokenu do obsługi domeny api jako audytu, a także domeny auth0.
jezpez
94

W kryptografii stosowane są dwa rodzaje algorytmów:

Algorytmy symetryczne

Pojedynczy klucz służy do szyfrowania danych. Po zaszyfrowaniu kluczem dane można odszyfrować przy użyciu tego samego klucza. Jeśli na przykład Mary zaszyfruje wiadomość przy użyciu klucza „mój-sekret” i wyśle ​​ją do Johna, będzie w stanie poprawnie odszyfrować wiadomość przy użyciu tego samego klucza „mój-sekret”.

Algorytmy asymetryczne

Do szyfrowania i deszyfrowania wiadomości służą dwa klucze. Podczas gdy jeden klucz (publiczny) służy do szyfrowania wiadomości, drugi klucz (prywatny) może być użyty tylko do jego odszyfrowania. Tak więc John może wygenerować klucze publiczne i prywatne, a następnie wysłać tylko klucz publiczny do Mary w celu zaszyfrowania swojej wiadomości. Wiadomość można odszyfrować tylko przy użyciu klucza prywatnego.

Scenariusz HS256 i RS256

Algorytmy te NIE są używane do szyfrowania / usuwania danych. Są one raczej wykorzystywane do weryfikacji pochodzenia lub autentyczności danych. Gdy Mary musi wysłać otwartą wiadomość do Jhon i musi sprawdzić, czy wiadomość z pewnością pochodzi od Mary, można użyć HS256 lub RS256.

HS256 może utworzyć podpis dla danej próbki danych za pomocą jednego klucza. Gdy wiadomość jest przesyłana wraz z podpisem, strona odbierająca może użyć tego samego klucza, aby sprawdzić, czy podpis pasuje do wiadomości.

RS256 używa pary kluczy, aby zrobić to samo. Podpis można wygenerować tylko przy użyciu klucza prywatnego. I klucz publiczny musi być użyty do weryfikacji podpisu. W tym scenariuszu, nawet jeśli Jack znajdzie klucz publiczny, nie może utworzyć fałszywej wiadomości z podpisem podszywającym się pod Mary.

Charlie
źródło
38

Istnieje różnica w wydajności.

Mówiąc wprost, HS256jest o około 1 rząd wielkości szybszy niż w RS256przypadku weryfikacji, ale o około 2 rzędy wielkości szybszy niż w RS256przypadku wystawiania (podpisywania).

 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)

Nie rozłączaj się na faktycznych liczbach, po prostu pomyśl o nich z szacunkiem.

[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
źródło
To są ważne liczby. Dziękuję Ci. Zwykle myślę o szyfrowaniu jako mniej lub bardziej przejrzystej przepustowości wrt, ale twoje badania sugerują, że użycie R256 do podpisania komunikacji między maszynami dodaje 1 ms na przeskok.
Matthew Mark Miller,
1
@MatthewMarkMiller Należy pamiętać, że nie są one równe w użyciu. Mają różne cechy. RS256 jest asymetryczny i dlatego w komunikacji typu klient / serwer, w której udostępniasz tylko klucz publiczny, jest to lepsza opcja. HS256 wymaga współdzielenia klucza, który może zarówno podpisywać, jak i weryfikować - przydatne tylko, jeśli ufasz obu stronom lub nie potrzebujesz żadnej ze stron, aby coś odszyfrować.
Rob Evans
7
@RobEvans tak, nie rozłączaj się z wynikami tutaj. Wybierz właściwe rozwiązanie swojego problemu. To tylko spostrzeżenie, a nie zalecenie faworyzowania HS256 w stosunku do RS256, musisz podjąć decyzję w oparciu o kontekst.
John Leidegren,
1
Kiedy wybór protokołu może mieć taki sam wpływ na opóźnienie jak dodatkowy kilometr kabla, warto o tym wiedzieć, szczególnie w czasach długich łańcuchów połączeń i napiętych TTL.
Matthew Mark Miller
0

krótka odpowiedź, specyficzna dla OAuth2,

  • Sekret klienta użytkownika HS256 do wygenerowania podpisu tokena i ten sam klucz tajny jest wymagany do sprawdzenia poprawności tokena w zapleczu. Powinieneś mieć kopię tego tajnego klucza na swoim serwerze zaplecza, aby zweryfikować podpis.
  • RS256 używa szyfrowania klucza publicznego do podpisywania tokena. Podpis (skrót) utworzy się przy użyciu klucza prywatnego i może zweryfikować przy użyciu klucza publicznego. Tak więc nie trzeba klucza prywatnego ani tajnego klienta do przechowywania na serwerze zaplecza, ale serwer zaplecza pobierze klucz publiczny z adresu URL konfiguracji openid w Twojej dzierżawie ( https: // [tenant] /.well-known/openid -konfiguracja ), aby zweryfikować token. Parametr KID wewnątrz access_toekn użyje do wykrycia poprawnego klucza (publicznego) z konfiguracji openid.
Hiran
źródło