Wzorzec logowania do interfejsu API REST


181

Tworzę REST api, ściśle przestrzegając sugestii apigee, używając rzeczowników, a nie czasowników, wersji API zapieczętowanej w adresie URL, dwóch ścieżek API na kolekcję, użycie GET POST PUT DELETE itp.

Pracuję nad systemem logowania, ale nie mam pewności co do prawidłowego sposobu logowania użytkowników REST. W tym momencie nie pracuję nad bezpieczeństwem, tylko nad wzorcem logowania lub przepływem. (Później dodamy 2-stopniową OAuth, z HMAC itp.)

Możliwe opcje

  • POST do czegoś w rodzaju https://api...com/v1/login.json
  • PUT na coś takiego https://api...com/v1/users.json
  • Coś, o czym nie pomyślałem ...

Jaki jest właściwy styl REST do logowania użytkowników?


9
To jest format odpowiedzi. .json mówi serwerowi, aby odpowiedział przy użyciu json, .xml mówi serwerowi, aby odpowiedział w formacie xml. Raczej uczynienie go opcjonalnym parametrem za?. blog.apigee.com/detail/…
Scott Roepnack

28
Nigdy nie widziałem negocjacji treści pod adresem URL, tylko w nagłówkach. W przypadku adresu URL oznacza to utratę korzyści z buforowania i nie tylko.
Oded

10
@ScottRoepnack, powinieneś rozważyć Acceptnagłówek HTTP.
Alessandro Vendruscolo

2
@Oded Jeśli użyłeś Acceptnagłówka, miałbyś również znak Vary: Accept, więc nie wpłynie to na buforowanie. Conneg w rozszerzeniu został omówiony wcześniej ; Zgodziłbym się jednak tam z odpowiedzią Shonzilli.
cmbuckley,

2
@Oded - nie rozumiem. Dlaczego miałbyś stracić korzyści z buforowania, jeśli określisz typ zawartości w adresie URL (jako sufiks .json do ścieżki zapytania lub jako parametr zapytania type = json)? A kim jest „ty” w tym przypadku? Kim jest osoba, która traci korzyści z buforowania? wydaje mi się, że wyniki każdego zapytania można przechowywać w pamięci podręcznej, niezależnie od tego, co znajduje się w ścieżce zapytania lub parametrach.
Cheeso

Odpowiedzi:


138

Principled Design of the Modern Web Architecture autorstwa Roya T. Fieldinga i Richarda N. Taylora , czyli sekwencja prac z całej terminologii REST, zawiera definicję interakcji klient-serwer:

Wszystkie interakcje REST są bezpaństwowe . Oznacza to, że każde żądanie zawiera wszystkie informacje niezbędne łącznikowi do zrozumienia żądania, niezależnie od wszelkich żądań, które mogły je poprzedzać .

To ograniczenie spełnia cztery funkcje, pierwsza i trzecia są ważne w tym konkretnym przypadku:

  • Po pierwsze : eliminuje potrzebę zachowania przez łączniki stanu aplikacji między żądaniami , zmniejszając w ten sposób zużycie zasobów fizycznych i poprawiając skalowalność;
  • Po trzecie : umożliwia pośrednikowi przeglądanie i rozumienie żądania oddzielnie , co może być konieczne, gdy usługi są dynamicznie rearanżowane;

A teraz wróćmy do twojego zabezpieczenia. Każde żądanie powinno zawierać wszystkie wymagane informacje, a autoryzacja / uwierzytelnienie nie jest wyjątkiem. Jak to osiągnąć? Dosłownie wysyłaj wszystkie wymagane informacje przez przewody z każdym żądaniem.

Jednym z przykładów, jak to zrobić, jest kod uwierzytelniania wiadomości oparty na skrócie lub HMAC . W praktyce oznacza to dodawanie skrótu aktualnej wiadomości do każdego żądania. Kod skrótu obliczany przez kryptograficzną funkcję skrótu w połączeniu z tajnym kluczem kryptograficznym . Kryptograficzna funkcja skrótu jest predefiniowana lub stanowi część koncepcji REST kodu na żądanie (na przykład JavaScript). Tajny klucz kryptograficzny powinien być dostarczony przez serwer do klienta jako zasób, a klient używa go do obliczenia kodu skrótu dla każdego żądania.

Istnieje wiele przykładów implementacji HMAC , ale chciałbym, abyś zwrócił uwagę na następujące trzy:

Jak to działa w praktyce

Jeśli klient zna tajny klucz, jest gotowy do pracy z zasobami. W przeciwnym razie zostanie tymczasowo przekierowany (kod stanu 307 Tymczasowe przekierowanie) w celu autoryzacji i uzyskania tajnego klucza, a następnie przekierowany z powrotem do oryginalnego zasobu. W tym przypadku nie ma potrzeby wcześniejszej znajomości (tj. Gdzieś na stałe zakodować), jaki jest adres URL do autoryzacji klienta i można z czasem dostosować ten schemat.

Mam nadzieję, że pomoże Ci to znaleźć właściwe rozwiązanie!


23
MAC ma na celu udowodnienie autentyczności wiadomości i ochronę przed manipulacją - nie ma to nic wspólnego z uwierzytelnianiem użytkownika
yrk

1
Dodano jeden z przykładów, jak radzić sobie z uwierzytelniania użytkownika / klienta, nie wiedząc o „ logowania URL ” uprzednich
Akim

Oto kolejne dwa fajne artykuły z przykładami uwierzytelniania bezpaństwowego dla usług REST: blog.jdriven.com/2014/10/... technicalrex.com/2015/02/20/…
Vladimir Rozhkov

41

TL; DR Logowanie dla każdego żądania nie jest wymaganym elementem do implementacji bezpieczeństwa API, ale uwierzytelnianie jest.

Trudno odpowiedzieć na pytanie dotyczące logowania, nie mówiąc ogólnie o bezpieczeństwie. W przypadku niektórych schematów uwierzytelniania nie ma tradycyjnego logowania.

REST nie narzuca żadnych reguł bezpieczeństwa, ale w praktyce najczęściej stosowaną implementacją jest OAuth z uwierzytelnianiem trójstronnym (jak wspomniałeś w swoim pytaniu). Nie ma logowania jako takiego, przynajmniej nie przy każdym żądaniu API. W przypadku uwierzytelniania trójstronnego po prostu używasz tokenów.

  1. Użytkownik zatwierdza klienta API i udziela uprawnień do wysyłania żądań w postaci tokenu o długiej żywotności
  2. Klient API uzyskuje krótkotrwały token przy użyciu długowiecznego.
  3. Klient API wysyła krótkotrwały token z każdym żądaniem.

Ten schemat daje użytkownikowi możliwość cofnięcia dostępu w dowolnym momencie. Praktycznie wszystkie publicznie dostępne interfejsy API RESTful, które widziałem, używają protokołu OAuth do implementacji tego.

Po prostu nie uważam, że powinieneś ująć swój problem (i pytanie) w kategoriach logowania, ale raczej pomyśleć o ogólnym zabezpieczeniu API.

Więcej informacji na temat ogólnego uwierzytelniania interfejsów REST API można znaleźć w następujących zasobach:


Tak, OAuth! Bardzo prosta odpowiedź, powinna być odpowiedzią zaakceptowaną, imho.
Lewita

26

Dużą częścią filozofii REST jest wykorzystanie jak największej liczby standardowych funkcji protokołu HTTP podczas projektowania interfejsu API. Stosując tę ​​filozofię do uwierzytelniania, klient i serwer wykorzystywałyby standardowe funkcje uwierzytelniania HTTP w API.

Ekrany logowania świetnie sprawdzają się w przypadku użytkowników: odwiedź ekran logowania, podaj użytkownika / hasło, ustaw plik cookie, klient zapewnia ten plik cookie we wszystkich przyszłych żądaniach. Nie można oczekiwać, że ludzie używający przeglądarek internetowych będą podawać identyfikator użytkownika i hasło przy każdym indywidualnym żądaniu HTTP.

Jednak w przypadku interfejsu API REST ekran logowania i pliki cookie sesji nie są bezwzględnie konieczne, ponieważ każde żądanie może zawierać poświadczenia bez wpływu na użytkownika; a jeśli klient nie współpracuje w dowolnym momencie, 401można udzielić „nieautoryzowanej” odpowiedzi. RFC 2617 opisuje obsługę uwierzytelniania w protokole HTTP.

TLS (HTTPS) byłby również opcją i pozwoliłby na uwierzytelnianie klienta na serwerze (i odwrotnie) w każdym żądaniu poprzez weryfikację klucza publicznego drugiej strony. Dodatkowo zapewnia to kanałowi premię. Oczywiście, aby to zrobić, konieczna jest wymiana pary kluczy przed komunikacją. (Uwaga: dotyczy to w szczególności identyfikacji / uwierzytelniania użytkownika za pomocą protokołu TLS. Zabezpieczanie kanału za pomocą protokołu TLS / Diffie-Hellman jest zawsze dobrym pomysłem, nawet jeśli nie identyfikujesz użytkownika za pomocą jego klucza publicznego).

Przykład: załóżmy, że token OAuth to Twoje pełne dane logowania. Gdy klient ma token OAuth, można go podać jako identyfikator użytkownika w standardowym uwierzytelnianiu HTTP przy każdym żądaniu. Serwer może zweryfikować token przy pierwszym użyciu i zapisać wynik sprawdzenia w pamięci podręcznej z czasem wygaśnięcia, który jest odnawiany przy każdym żądaniu. Każde żądanie wymagające uwierzytelnienia jest zwracane, 401jeśli nie zostanie podane.


1
„ponieważ każde żądanie może zawierać dane uwierzytelniające bez wpływu na użytkownika”, wymyślono trójstronne uwierzytelnianie i OAuth, ponieważ rzecz w cudzysłowie jest zła. Jeśli podasz poświadczenia przy każdym żądaniu bez mechanizmu na serwerze, aby je odwołać, byłoby to niebezpieczne, gdyby było używane bez SSL.
Slavo

1
Zawsze, gdy pojawia się pojęcie użytkowników, coś musi zostać przekazane od klienta do serwera, aby zidentyfikować użytkownika. Token OAuth może z pewnością służyć jako „poświadczenie” zamiast rzeczywistej kombinacji użytkownika i hasła. Zabezpieczanie kanału za pomocą TLS jest z pewnością zawsze dobrą rzeczą, ale to prawie nie ma znaczenia. Nawet jeśli korzystasz z pliku cookie, z każdym żądaniem do serwera nadal jest wysyłany jakiś rodzaj tokenów, tylko z nagłówkiem pliku cookie zamiast nagłówka uwierzytelniania.
jagoda

A jeśli z jakiegoś powodu nie używasz TLS ani OAuth, czy wysyłanie użytkownika / hasła za każdym razem jest naprawdę gorsze niż wysyłanie go tylko raz? Jeśli osoba atakująca może uzyskać użytkownika / hasło, prawdopodobnie może również uzyskać plik cookie sesji.
jagoda

Różnica między plikiem cookie a nagłówkiem uwierzytelniania będącym poświadczeniami polega na tym, że pliki cookie są zawsze powiązane z określoną domeną. Oznacza to, że kiedy API otrzymuje plik cookie, wie, skąd pochodzi (zostało wcześniej napisane przez tę samą domenę). Z nagłówkiem nigdy nie wiesz i musisz zaimplementować w tym celu określone kontrole. Ogólnie zgadzam się, oba są poświadczeniami, ale myślę, że przekazanie poświadczeń nie oznacza logowania. Logowanie to aktywna czynność otwierania drzwi. W przypadku uwierzytelniania 3-way, tylko pierwsze zatwierdzenie klienta byłoby logowaniem.
Slavo
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.