Czy możesz mi pomóc to zrozumieć? „Typowe błędy REST: sesje są nieistotne”

159

Zastrzeżenie: Jestem nowy w szkole myślenia REST i staram się to ogarnąć.

Tak więc czytam tę stronę, Częste błędy REST i stwierdziłem, że jestem całkowicie zaskoczony tym, że sekcja dotycząca sesji jest nieistotna. Oto, co mówi strona:

Klient nie powinien się „logować” ani „uruchamiać połączenia”. Uwierzytelnianie HTTP odbywa się automatycznie dla każdej wiadomości. Aplikacje klienckie są konsumentami zasobów, a nie usług. Dlatego nie ma się do czego logować! Powiedzmy, że rezerwujesz lot w serwisie internetowym REST. Nie tworzysz nowego połączenia „sesji” z usługą. Zamiast tego należy poprosić „obiekt kreatora trasy” o utworzenie nowego planu podróży. Możesz zacząć wypełniać puste miejsca, ale potem pobierz zupełnie inny komponent z innego miejsca w sieci, aby wypełnić inne puste miejsca. Nie ma sesji, więc nie ma problemu z migracją stanu sesji między klientami. Nie ma również problemu z „koligacją sesji”

OK, rozumiem, że uwierzytelnianie HTTP jest wykonywane automatycznie dla każdej wiadomości - ale jak? Czy nazwa użytkownika / hasło są wysyłane z każdym żądaniem? Czy to nie tylko zwiększa powierzchnię ataku? Czuję, że brakuje mi części układanki.

Czy nie byłoby źle mieć, powiedzmy, usługę REST /session, która akceptuje żądanie GET, w której podałbyś nazwę użytkownika / hasło jako część żądania i zwraca token sesji, jeśli uwierzytelnianie się powiodło, to może być wtedy przekazane wraz z kolejnymi wnioskami? Czy to ma sens z punktu widzenia REST, czy to nie ma sensu?

Obrabować
źródło
każde żądanie jest zawsze uwierzytelniane, przechwytywanie sesji to rzecz. spokojny sprawia, że ​​jest to bardziej oczywiste, ale nie bardziej eksponowane.
Jasen,

Odpowiedzi:

79

Aby było zgodne z REST, każde żądanie HTTP powinno samo w sobie zawierać wystarczającą ilość informacji, aby jego odbiorca mógł je przetworzyć, aby było w pełnej harmonii z bezstanowym charakterem protokołu HTTP.

OK, rozumiem, że uwierzytelnianie HTTP jest wykonywane automatycznie dla każdej wiadomości - ale jak?

Tak, nazwa użytkownika i hasło są wysyłane z każdym żądaniem. Typowe metody to uwierzytelnianie dostępu podstawowego i uwierzytelnianie dostępu skróconego . I tak, podsłuchiwacz może przechwycić dane uwierzytelniające użytkownika. W ten sposób można by szyfrować wszystkie dane wysyłane i odbierane przy użyciu protokołu Transport Layer Security (TLS) .

Czy byłoby źle mieć usługę REST, powiedzmy / session, która akceptuje żądanie GET, w przypadku której przekazałbyś nazwę użytkownika / hasło jako część żądania i zwrócił token sesji, jeśli uwierzytelnianie się powiodło, to mogłoby być przekazywane wraz z kolejnymi wnioskami? Czy to ma sens z punktu widzenia REST, czy to nie ma sensu?

Nie byłoby to RESTful, ponieważ przenosi stan, ale jest jednak dość powszechne, ponieważ jest to wygoda dla użytkowników; użytkownik nie musi się każdorazowo logować.

To, co opisujesz w „tokenie sesji”, jest powszechnie określane jako plik cookie logowania . Na przykład, jeśli spróbujesz zalogować się do swojego konta Yahoo! na koncie jest pole wyboru z napisem „Nie wylogowuj mnie przez 2 tygodnie”. Zasadniczo oznacza to (w twoich słowach) „zachowaj mój token sesji przez 2 tygodnie, jeśli się pomyślnie zaloguję”. Przeglądarki internetowe będą wysyłać takie pliki cookie logowania (i być może inne) z każdym żądaniem HTTP, o które poprosisz.

z8000
źródło
5
Ta odpowiedź nie ma dla mnie sensu. Po pierwsze, mówi, że można podać login i hasło za każdym razem, a więc także raz, co ma sens. Następnie sugerowany jest pomysł, aby zwrócić klientowi stan pomyślnego logowania w postaci tokena. W razie potrzeby token może zakodować czas utworzenia. Z pewnością możemy zwrócić informacje klientowi. Tak więc ta sugestia wydaje mi się dobra. Odpowiedź mówi, że to nie jest w porządku, ponieważ „przenosi stan”, ale czy idea „ST” w „REST”, że stan może być przenoszony między klientem a serwerem?
33

Często zdarza się, że usługa REST wymaga uwierzytelniania dla każdego żądania HTTP. Na przykład Amazon S3 wymaga, aby każde żądanie miało podpis pochodzący z poświadczeń użytkownika, dokładnego żądania do wykonania i aktualnego czasu. Podpis ten jest łatwy do obliczenia po stronie klienta, może być szybko zweryfikowany przez serwer i ma ograniczone zastosowanie dla atakującego, który go przechwyci (ponieważ jest oparty na aktualnym czasie).

Greg Hewgill
źródło
3
+1, czy możesz rozwinąć więcej: ma ograniczone zastosowanie dla atakującego, który je przechwytuje (ponieważ jest oparty na aktualnym czasie) ? czy nie mówisz o pliku cookie, który zawiera zaszyfrowaną nazwę użytkownika i hasło? jak tak robi? (IMHO)
Royi Namir
2
@RoyiNamir: Nie mówię o ciastku. Podpis używany przez S3 jest parametrem żądania HTTP, ale nie jest plikiem cookie, jest obliczany ponownie dla każdego żądania.
Greg Hewgill
Więc jeśli muszę zapisać jakieś informacje o użytkowniku, gdzie mam je zapisać? w db? Nie chcę przechodzić każdej prośby do db .... i nadal chcę użyć reszty .... czy możesz pomóc?
Royi Namir
@RoyiNamir: Jeśli masz konkretne pytania dotyczące tego, jak osiągnąć jakiś cel, zadaj nowe pytanie . Nie mogę tutaj odpowiedzieć na dodatkowe pytania w komentarzach.
Greg Hewgill
10

Wiele osób nie rozumie zasad REST bardzo jasno, używanie tokena sesji nie oznacza, że ​​zawsze jesteś stanowy, powodem wysyłania nazwy użytkownika / hasła przy każdym żądaniu jest tylko uwierzytelnienie i to samo przy wysyłaniu tokena (generowanego przez logowanie procesu) tylko po to, aby zdecydować, czy klient ma pozwolenie na żądanie danych, czy nie, naruszasz konwersję REST tylko wtedy, gdy używasz nazwy użytkownika / hasła lub tokenów sesji, aby zdecydować, jakie dane pokazać! zamiast tego musisz ich używać tylko do uwierzytelniania (aby pokazać dane lub nie pokazać danych)

w twoim przypadku mówię TAK, to jest RESTy, ale staraj się unikać natywnych sesji php w swoim REST API i zacznij generować własne zaszyfrowane tokeny, które wygasają w określonym czasie!

EvilThinker
źródło
1
Dziękuję Ci. dlaczego należy unikać natywnej sesji php i zamiast tego używać własnych tokenów hash?
Matthew
Nie jest to żaden wspaniały powód, który mówię, tylko dla większego bezpieczeństwa i większej kontroli.
EvilThinker
To lepsze niż zaakceptowana odpowiedź. Przynajmniej akceptuje sugestię jako RESTy, co ma sens. Nie rozumiem jednak, dlaczego przekazanych informacji nie można użyć do autoryzacji zależnej od użytkownika. Niektórzy użytkownicy mogą mieć dostęp do niektórych danych, a inni nie. Nie oznacza to, że protokół nie jest zgodny z REST.
8

Nie, to nie mija się z celem. Google ClientLogin działa dokładnie w ten sposób, z godnym uwagi wyjątkiem, że klient otrzymuje polecenie przejścia do „/ session” za pomocą odpowiedzi HTTP 401. Ale to nie tworzy sesji, a jedynie stwarza klientom możliwość (tymczasowego) uwierzytelnienia się bez przekazywania poświadczeń w trybie Clear, a serwerowi kontrolę ważności tych tymczasowych poświadczeń według własnego uznania.

mogsie
źródło
11
@ unforgiven3 Dopóki zwrócony token jest używany tylko do uwierzytelnienia użytkownika i nie jest używany przez serwer do skojarzenia użytkownika z innym stanem przechowywanym na serwerze, nie widzę naruszenia ograniczeń REST.
Darrel Miller
4
@ unforgiven3 Token zwrócony przez serwer jest w rzeczywistości dowodem na to, że użytkownik jest tym, za kogo się podaje. Tak więc zamiast każdego żądania zawierającego nazwę użytkownika i hasło, każde żądanie zawiera token, który jest skonstruowany w taki sposób, że serwer może być pewien jego prawdziwości.
Darrel Miller,
1
@ unforgiven3, Darrel ma rację. Token odsyłany z powrotem musiałby być wysyłany przez klienta przy każdym żądaniu HTTP, podobnie jak w przypadku podstawowego uwierzytelniania skróconego, aż do wygaśnięcia ważności tokena. W takim przypadku klient może powtórzyć logowanie, opcjonalnie prosząc użytkownika o podanie poświadczeń lub cokolwiek innego. Jeśli chcesz, mógłbym uściślić odpowiedź. edycja: (I dzięki za nadążanie za odpowiedziami na stare pytania!)
mogsie
1
Żaden problem, mogsie, zawsze interesujące jest omawianie tego typu rzeczy :-) Myślę, że widzę, do czego zmierzacie, niestety po prostu nie rozumiem wystarczająco dużo o uwierzytelnianiu trawienia, aby naprawdę to zrozumieć (głównie po prostu nie rozumiem zrozumieć, w jaki sposób token jest odsyłany przy każdym żądaniu HTTP, ale wydaje się, że jest to szczegół implementacji). Jednak teraz rozumiem, dlaczego ta metoda nie narusza zasad REST. Dzięki za odpowiedzi!
Rob
6
@ unforgiven3, To może pomóc: token jest podpisaną informacją. Więc jest samowystarczalny. Serwer może zweryfikować token bez sprawdzania wcześniej zapisanego stanu. Jest to więc po prostu stan przechowywany na kliencie i przesyłany tam iz powrotem.
Iravanchi
5

OK, rozumiem, że uwierzytelnianie HTTP jest wykonywane automatycznie dla każdej wiadomości - ale jak?

„Autoryzacja”: nagłówek HTTP wysłany przez klienta. Podstawowy (zwykły tekst) lub skrót.

Czy byłoby źle mieć usługę REST, powiedzmy / session, która akceptuje żądanie GET, w przypadku której przekazałbyś nazwę użytkownika / hasło jako część żądania i zwrócił token sesji, jeśli uwierzytelnianie się powiodło, to mogłoby być przekazywane wraz z kolejnymi wnioskami? Czy to ma sens z punktu widzenia REST, czy to nie ma sensu?

Cała idea sesji polega na tworzeniu aplikacji stanowych przy użyciu protokołu bezstanowego (HTTP) i głupiego klienta (przeglądarki internetowej), utrzymując stan po stronie serwera. Jedną z zasad REST jest „Każdy zasób jest jednoznacznie adresowalny przy użyciu uniwersalnej składni do użytku w linkach hipermedialnych” . Zmienne sesji to coś, do czego nie można uzyskać dostępu za pośrednictwem identyfikatora URI. Prawdziwie RESTful aplikacja utrzymywałaby stan po stronie klienta, wysyłając wszystkie niezbędne zmienne przez HTTP, najlepiej w URI.

Przykład: wyszukiwanie z paginacją. Miałbyś adres URL w formularzu

http://server/search/urlencoded-search-terms/page_num

Ma to wiele wspólnego z adresami URL objętymi zakładkami

vartec
źródło
4
Jednak informacje uwierzytelniające nie są dostępne za pośrednictwem URI - wszyscy mówią o wysyłaniu informacji uwierzytelniających jako części nagłówka żądania. Czym to się różni od dołączenia tokena sesji do żądania? Nie mówię, że użyj tokenu sesji w identyfikatorze URI, ale w danych przekazanych w żądaniu.
Rob
Uwierzytelnianie określa, czy masz uprawnienia do wykonania tej akcji, aw aplikacji RESTful nie wpłynie to na jej wynik.
vartec
4
Token sesji określa również, czy masz uprawnienia do wykonania tej czynności. Co masz na myśli przez to, że nie wpłynęłoby to na wynik? Jeśli dzwoniący nie jest autoryzowany, pojawia się błąd Brak autoryzacji. To samo z tokenem sesji. Naprawdę nie widzę różnicy?
Rob
3
Nie, token sesji to dojście do stanu zapisanego na serwerze. To po prostu nie jest RESTful. Jeśli chodzi o nieautoryzowane, nie widzę tego w rezultacie. Wolałbym traktować to jako wyjątek (jak w try / catch).
vartec
W porządku, vartec - to ma sens. Dzięki za kontynuację!
Rob
3

Myślę, że twoja sugestia jest OK, jeśli chcesz kontrolować czas życia sesji klienta. Myślę, że architektura RESTful zachęca do tworzenia aplikacji bezstanowych. Jak napisał @ 2pence, „każde żądanie HTTP powinno samo w sobie zawierać wystarczającą ilość informacji, aby jego odbiorca mógł je przetworzyć, aby było w pełnej harmonii z bezstanowym charakterem HTTP” .

Jednak nie zawsze tak jest, czasami aplikacja musi informować, kiedy klient loguje się lub wylogowuje i na podstawie tych informacji utrzymywać zasoby, takie jak blokady lub licencje. Przykład takiej sprawy można znaleźć w moim pytaniu uzupełniającym .

LiorH
źródło