Dlaczego w OAuth2 istnieje przepływ „Kod autoryzacyjny”, skoro przepływ „Domniemany” działa tak dobrze?

264

Dzięki przepływowi „niejawnemu” klient (prawdopodobnie przeglądarka) otrzyma token dostępu po tym, jak właściciel zasobu (tj. Użytkownik) udzieli dostępu.

Jednak przy przepływie „kodu autoryzacyjnego” klient (zazwyczaj serwer WWW) otrzymuje kod autoryzacyjny dopiero po tym, jak właściciel zasobu (tj. Użytkownik) udzieli dostępu. Za pomocą tego kodu autoryzacji klient wykonuje kolejne wywołanie API przekazując identyfikator_użytkownika i identyfikator_klienta wraz z kodem autoryzacji w celu uzyskania tokena dostępu. Wszystko dobrze opisane tutaj .

Oba przepływy mają dokładnie ten sam wynik: token dostępu. Jednak przepływ „niejawny” jest znacznie prostszy.

Pytanie: Po co zawracać sobie głowę przepływem „Kod autoryzacji”, skoro przepływ „Implikowany” jest w porządku? Dlaczego nie użyć także „Implicit” dla serwera WWW?

To więcej pracy zarówno dla dostawcy, jak i klienta.

Aron Woost
źródło
4
Sprawdź stackoverflow.com/questions/7522831/…
Jon Nylander
1
Dzięki, przeczytaj to już. Nie odpowiada jednak na pytanie.
Aron Woost
1
Dobre pytanie faktycznie i rzadko udzielane :) Patrz poniżej.
Nicolas Garnier
1
@AronWoost Myślę, że źle zrozumiałeś aplikację sieci Web na serwer i przeglądarkę
onmyway133,
@entropy To było moje pytanie; dlaczego nie skorzystać z przepływu przeglądarki również dla serwera.
Aron Woost

Odpowiedzi:

293

tl; dr: To wszystko ze względów bezpieczeństwa.

OAuth 2.0 chciał spełnić te dwa kryteria:

  1. Chcesz zezwolić programistom na używanie identyfikatora URI przekierowania innego niż HTTPS, ponieważ nie wszyscy programiści mają serwer z obsługą SSL, a jeśli tak, nie zawsze jest odpowiednio skonfigurowany (nie podpisane, zaufane certyfikaty SSL, zsynchronizowany zegar serwera ...).
  2. Nie chcesz, aby hakerzy mogli kraść tokeny dostępu / odświeżania, przechwytując żądania.

Szczegóły poniżej:

Domniemany przepływ jest możliwy tylko w środowisku przeglądarki ze względów bezpieczeństwa:

W niejawnym przepływie token dostępu jest przekazywany bezpośrednio jako fragment skrótu (nie jako parametr adresu URL). Jedną ważną rzeczą dotyczącą fragmentu skrótu jest to, że po przejściu do łącza zawierającego fragment skrótu tylko przeglądarka rozpoznaje fragment skrótu. Przeglądarki przekażą fragment skrótu bezpośrednio do docelowej strony internetowej (identyfikator URI przekierowania / strona klienta). Fragment skrótu ma następujące właściwości:

  • Nie są one częścią żądania HTTP, dlatego nie mogą być odczytane przez serwery i dlatego nie mogą zostać przechwycone przez serwery / routery pośredniczące (jest to ważne).
  • Istnieją tylko w przeglądarce - po stronie klienta - więc jedynym sposobem na odczytanie fragmentu skrótu jest użycie JavaScript działającego na stronie.

Umożliwia to przekazanie tokena dostępu bezpośrednio do klienta bez ryzyka przechwycenia go przez serwer pośredniczący. Jest to możliwe tylko dlatego, że jest to możliwe po stronie klienta i wymaga javascript do uruchomienia po stronie klienta, aby użyć tokena dostępu.

Domniemany przepływ ma również problemy z bezpieczeństwem, które wymagają dalszej logiki w celu obejścia / uniknięcia, na przykład:

  • Osoba atakująca może uzyskać token dostępu od użytkownika w innej witrynie / aplikacji (powiedzmy, że jest właścicielem innej witryny / aplikacji), zalogować token w swojej witrynie, a następnie przekazać go jako parametr adresu URL w witrynie dlatego podszywanie się pod użytkownika w Twojej witrynie. Aby tego uniknąć, musisz sprawdzić identyfikator klienta powiązany z tokenem dostępu (na przykład w Google możesz użyć punktu końcowego tokeninfo), aby upewnić się, że token został wydany z twoim własnym identyfikatorem klienta (tj. Przez własną aplikację) lub sprawdź podpis jeśli używasz IDToken (ale wymaga to tajnego klienta).
  • Jeśli żądanie uwierzytelnienia nie pochodzi z Twojej własnej własności (zwanej atakami Session Fixation), aby tego uniknąć, będziesz chciał wygenerować losowy skrót z witryny, zapisz go w pliku cookie i przekaż ten sam skrót w stanie adresu URL parametru żądanie uwierzytelnienia, gdy użytkownik wróci, sprawdzasz parametr stanu z plikiem cookie i musi on być zgodny.

W przepływie kodu autoryzacji nie jest możliwe przekazanie tokena dostępu bezpośrednio w parametrze URL, ponieważ parametry URL są częścią żądania HTTP, dlatego każdy serwer / routery pośredniczące, przez które przeszedłoby twoje żądanie (mogą być setki), mogłyby przeczytaj token dostępu, jeśli nie korzystasz z szyfrowanego połączenia (HTTPS), pozwalającego na tak zwane ataki typu man-in-the-middle.

Przekazywanie tokena dostępu bezpośrednio w parametrze adresu URL mogłoby teoretycznie być możliwe, ale serwer uwierzytelniania musiałby upewnić się, że identyfikator URI przekierowania używa HTTPS z szyfrowaniem TLS i „zaufanym” certyfikatem SSL (zazwyczaj z urzędu certyfikacji, który nie jest bezpłatny) aby upewnić się, że serwer docelowy jest prawidłowy i że żądanie HTTP jest w pełni zaszyfrowane. Nakłonienie wszystkich programistów do zakupu certyfikatu SSL i prawidłowego skonfigurowania protokołu SSL w ich domenie byłoby ogromnym bólem i spowolniłoby jego wdrażanie. Z tego powodu dostarczany jest pośredni jednorazowy „kod autoryzacyjny”, że tylko prawowity odbiorca będzie mógł wymieniać (ponieważ potrzebujesz tajnego klienta) i że kod będzie bezużyteczny dla potencjalnych hakerów przechwytujących żądania za pomocą niezaszyfrowanych transakcji (ponieważ oni nie

Można również argumentować, że domniemany przepływ jest mniej bezpieczny, istnieją potencjalne wektory ataku, takie jak fałszowanie domeny po przekierowaniu - na przykład poprzez przejęcie adresu IP witryny klienta. Jest to jeden z powodów, dla których przepływ niejawny przyznaje tylko tokeny dostępu (które mają mieć ograniczony czas użytkowania) i nigdy nie odświeża tokenów (które są nieograniczone w czasie). Aby rozwiązać ten problem, radzę, aby w miarę możliwości hostować swoje strony internetowe na serwerze obsługującym HTTPS.

Nicolas Garnier
źródło
12
@AndyDufresne Te dwa żądania muszą zostać wykonane przez HTTPS (obowiązkowe), ponieważ są to żądania do serwera OAuth, który musi obsługiwać tylko HTTPS. Tylko klient / serwer żądający nie musi obsługiwać HTTPS, więc tylko Auth Codepotencjalnie przesyłane są jawnie przez HTTP. Ale Auth Codejest bezużyteczne bez identyfikatora klienta / tajnego. Zasadniczo przepływ kodu OAuth polega na tym, że ciężar posiadania serwera obsługującego protokół SSL spoczywa na dostawcy OAuth (Google / Facebook itp.), A nie na użytkownikach interfejsów API (ty, ja).
Nicolas Garnier,
5
Ok, teraz obserwuję, że kod autoryzacji może być przekazywany przez zwykły HTTP i istnieje ryzyko wąchania. Uczyniwszy go jednorazowym kodem i akceptując tajny klucz klienta w celu wymiany go na token dostępu, serwer autoryzacji może zapobiec atakowi Man-in-the-middle. Ale czy nie dotyczy to również tokena dostępu? Ponieważ użytkownik interfejsów API może korzystać z zwykłego protokołu HTTP, czy nie istnieje ryzyko, że haker wykryje token dostępu? PS - Doceniam twoje wysiłki w wyjaśnianiu koncepcji nawet po pewnym czasie, odkąd ten wątek był aktywny. Dzięki !
Andy Dufresne
8
no pb :) Żądania do API - czyli kiedy token dostępu jest wysyłany przewodowo (w celu autoryzacji żądania) - są również obowiązkowo realizowane przez HTTPS. Teoretycznie klient nigdy nie powinien w żadnym momencie wysyłać tokena dostępowego przez zwykły HTTP.
Nicolas Garnier
5
Token dostępu na tym etapie jest częścią odpowiedzi na żądanie HTTPS od klienta do serwera zasobów. Ta odpowiedź jest nadal szyfrowana.
Nicolas Garnier
13
Zasadniczo żądania inicjowane od klienta do serwera zasobów są realizowane za pośrednictwem protokołu HTTPS (ponieważ serwer właściciela zasobów musi obsługiwać protokół HTTPS). To tylko żądania, które są inicjowane z innego miejsca do klienta, które mogą być wykonane przez HTTP (ponieważ serwer klienta może nie obsługiwać HTTPS). Na przykład przekierowanie, które ma miejsce podczas przepływu autoryzacji po tym, jak użytkownik udzieli autoryzacji na stronie gant, jest przekierowaniem zainicjowanym z przeglądarki na serwer klienta i może być wykonane w HTTP.
Nicolas Garnier
8

Niejawny przepływu sprawia, że cały strumień całkiem proste, ale również mniej bezpieczne .
Ponieważ aplikacja kliencka, która zwykle działa w przeglądarce JavaScript, jest mniej zaufana, nie są zwracane żadne tokeny odświeżania dla długotrwałego dostępu.
Z przepływu tego należy korzystać w przypadku aplikacji wymagających tymczasowego dostępu (kilka godzin) do danych użytkownika.
Zwrócenie tokena dostępu do klientów JavaScript oznacza również, że Twoja aplikacja przeglądarki musi zachować szczególną ostrożność - pomyśl o atakach XSS, które mogą wyciec token dostępu do innych systemów.

https://labs.hybris.com/2012/06/05/oauth2-the-implicit-flow-aka-aka-as-the-client-side-flow

jeziora
źródło
Spodziewałbym się, że gdy ktoś ma lukę w XSS, to nawet przepływ kodu autoryzacji niewiele pomaga. Zgadzam się jednak, że ponieważ sposób, w jaki sposób token dostępu jest przekazywany do javascript w przepływie niejawnym jest ustandaryzowany (jako fragment skrótu), a jeśli w witrynie występuje luka w zabezpieczeniach XSS, konstruowanie ataku, który odczytuje token dostępu z skrótu adresu URL fragment jest dość łatwy. Z drugiej strony, przy przepływie kodu autoryzacyjnego może być możliwe fałszowanie żądań w różnych witrynach.
Marcel
Nie chodzi też tylko o skrypty między witrynami. Każda biblioteka JavaScript działająca w Twojej witrynie może próbować ukraść token dostępu (na przykład biblioteki CDN stron trzecich lub biblioteki open source, których używa Twoja platforma javascript).
Marcel
2
XSS nie jest teraz dużym problemem, gdy mamy nagłówki Polityki bezpieczeństwa treści i skróty integralności zasobów (SRI).
Siergiej Ponomariew
4

Ze specyfikacji OAuth :

4.2 Dotacja niejawna

Domniemany typ przydziału służy do uzyskiwania tokenów dostępu (nie obsługuje wydawania tokenów odświeżania) i jest zoptymalizowany dla klientów publicznych, o których wiadomo, że obsługują określony identyfikator URI przekierowania. Klienci ci są zazwyczaj implementowani w przeglądarce za pomocą języka skryptowego, takiego jak JavaScript.

Ponieważ jest to przepływ oparty na przekierowaniu, klient musi mieć możliwość interakcji z klientem użytkownika właściciela zasobu (zazwyczaj przeglądarką internetową) i odbierania przychodzących żądań (poprzez przekierowanie) z serwera autoryzacji.

W przeciwieństwie do typu przyznania kodu autoryzacyjnego, w którym klient wysyła osobne żądania autoryzacji i tokena dostępu, klient otrzymuje token dostępu w wyniku żądania autoryzacji.

Domniemany typ przyznania nie obejmuje uwierzytelnienia klienta i zależy od obecności właściciela zasobu oraz rejestracji identyfikatora URI przekierowania. Ponieważ token dostępu jest zakodowany w identyfikatorze URI przekierowania, może zostać udostępniony właścicielowi zasobu i innym aplikacjom znajdującym się na tym samym urządzeniu.

Co możemy rozważyć:

  1. Odnosi się to do publicznego OAuth, tzn. Gdy klient nie musi być rejestrowany i nie ma swoich własnych tajemnic klienta. Ale jaki serwer uwierzytelniający sprawdza adres URL przekierowania i to w rzeczywistości wystarcza dla bezpieczeństwa.

  2. Token dostępu pojawia się w pasku adresu przeglądarki, więc użytkownik może skopiować adres URL i wysłać go komuś innemu, a także zostaje zalogowany jako użytkownik, tzn. Przypomina to utrwalanie sesji. Ale przeglądarka dokonuje dodatkowego przekierowania, zastępując historię, aby usunąć fragment skrótu z adresu URL. Haker może również ukraść token dostępu, wykrywając ruch HTTP, ale można to łatwo zabezpieczyć za pomocą HTTPS. Niektóre złośliwe rozszerzenia przeglądarki mogą mieć dostęp do adresów URL z paska adresu, ale jest to ostatecznie zła sytuacja, np. Zepsuty certyfikat HTTPS. I nawet przepływ kodu Auth nie może pomóc w tym eterze. Widzę więc, że przekazywanie tokena dostępu przez fragment skrótu adresu URL jest całkowicie bezpieczne.

  3. Rozdzielanie efemerycznych tokenów dostępu i tokenów odświeżania są bezużyteczne, gdy używa się HTTPS i, szczerze mówiąc, nie są tak przydatne nawet na surowym HTTP. Ale fakt, że klient za pośrednictwem niejawnego przepływu nie może odebrać tokenu odświeżania, również jest nonsensem.

Dlatego uważam, że powinniśmy wprowadzić nowy „przepływ ukryty”, który działa ściśle w stosunku do protokołu https, pozwala na token odświeżania (lub w ogóle powinniśmy się go pozbyć) i jest lepszy niż przepływ przydziałów Auth Cose

stokito
źródło
3

Dla nas nasi klienci chcieli móc raz uwierzytelnić się za pomocą naszej aplikacji na swoich telefonach i nie musieli logować się ponownie przez kilka tygodni. Dzięki przepływowi kodu otrzymasz token odświeżania wraz z tokenem dostępu. Niejawny przepływ nie daje tokena odświeżania. Token dostępu ma stosunkowo krótki termin ważności, ale tokeny odświeżania mogą mieć ważność do 90 dni. Za każdym razem, gdy wygasa token dostępu, kod klienta i serwera może użyć tego tokenu odświeżania, aby uzyskać nowy token dostępu i token odświeżania, wszystko za kulisami, bez żadnej interwencji użytkownika. Tokenu odświeżającego można użyć tylko raz. Nie możesz tego zrobić za pomocą Implicit Flow. Jeśli korzystasz z usługi Implicit Flow, a użytkownik nie będzie kontaktował się z Twoją aplikacją przez ponad godzinę, będzie musiał zalogować się ponownie po powrocie. To było nie do przyjęcia w naszym przypadku użycia,

Działa to i jest bezpieczne, ponieważ tokeny odświeżania można odwołać. Jeśli klient powie, że zgubił telefon lub laptop albo haker wszedł na pulpit, możemy po prostu odwołać wszystkie tokeny odświeżania dla tego użytkownika. Podczas całego procesu żadne dane osobowe nigdy nie wpływają na nasz kod - mianowicie hasło użytkownika.

Przepływ kodu jest niesamowity, ale wymaga więcej pracy. MS nie ma obecnie biblioteki Angulara do obsługi tego, więc musiałem napisać jedną. Jeśli jesteś zainteresowany, mogę ci w tym pomóc.

Tim Hardy
źródło
2

Moja odpowiedź brzmi: nie można wdrożyć niejawnego przepływu w bezpieczny i prosty sposób za pomocą serwera aplikacji WWW.

Proces autoryzacji aplikacji internetowej obejmuje interakcję użytkownika, dlatego serwer uwierzytelniania powinien przekierowywać przeglądarkę użytkownika z powrotem na stronę docelową aplikacji internetowej po uwierzytelnieniu użytkownika i wyrażeniu zgody (nie widzę innego sposobu na przekazanie użytkownika z powrotem do aplikacji internetowej po interakcji z Serwer uwierzytelniania).

Więc token powinien zostać przekazany do aplikacji internetowej przy użyciu przekierowującego adresu URL, prawda?

Jak wyjaśnił @NicolasGarnier w swojej odpowiedzi i komentarzach, nie ma możliwości przekazania tokena jako fragmentu adresu URL - nie dotrze on do serwera aplikacji WWW.

Przekazywanie tokena jako parametru adresu URL przekierowania byłoby niebezpieczne nawet w przypadku HTTPS: jeśli strona docelowa (niech to będzie „strona z pozdrowieniami”) zawiera zasoby (obrazy, skrypty itp.), Zasoby te zostaną uzyskane przez przeglądarkę za pośrednictwem serii żądań HTTP (S) (każde z nich ma Referer nagłówek HTTP zawierający dokładny adres URL „strony z pozdrowieniami”, w tym parametry adresu URL). W ten sposób token może wyciekać.

Wygląda więc na to, że nie można przekazać tokena w adresie URL przekierowania. Dlatego potrzebujesz drugiego połączenia (z serwera uwierzytelniania do klienta (ale pod który adres URL?) Lub z klienta do serwera uwierzytelnienia (drugie połączenie w przepływie kodu autoryzacji))

Lu55
źródło