Wyloguj się: GET czy POST?

434

To pytanie nie dotyczy tego, kiedy ogólnie używać GET lub POST; dotyczy tego, który jest zalecany do obsługi wylogowania z aplikacji internetowej. Znalazłem wiele informacji na temat różnic między GET i POST w sensie ogólnym, ale nie znalazłem jednoznacznej odpowiedzi dla tego konkretnego scenariusza.

Jako pragmatyk mam skłonność do używania GET, ponieważ jego implementacja jest znacznie prostsza niż POST; po prostu upuść prosty link i gotowe. Wydaje się, że tak jest w przypadku większości stron internetowych, o których mogę myśleć, przynajmniej z góry mojej głowy. Nawet przepełnienie stosu obsługuje wylogowanie za pomocą GET.

Waham się z (choć starym) argumentem, że niektóre akceleratory internetowe / serwery proxy wstępnie buforują strony, przechodząc i pobierając każdy link, który znajdują na stronie, więc użytkownik otrzymuje szybszą odpowiedź, gdy je kliknie. Nie jestem pewien, czy nadal tak jest, ale jeśli tak, to teoretycznie użytkownik z jednym z tych akceleratorów zostanie wyrzucony z aplikacji, gdy tylko się zaloguje, ponieważ jej akcelerator znajdzie i wyloguje się link, nawet jeśli nigdy go nie kliknęła.

Wszystko, co przeczytałem do tej pory, sugeruje, że POST powinien być używany do „działań destrukcyjnych”, podczas gdy działania, które nie zmieniają wewnętrznego stanu zapytań podobnych do aplikacji i takie powinny być obsługiwane za pomocą GET . Na tej podstawie prawdziwe pytanie brzmi:

Czy wylogowanie z aplikacji jest uważane za działanie destrukcyjne / czy zmienia wewnętrzny stan aplikacji?

Daniel Liuzzi
źródło
Zakładając, że odwiedzasz stronę po raz pierwszy, a link do wylogowania nie jest obecny, zostaniesz wylogowany podczas logowania. Byłoby dobrze po ponownym zalogowaniu, ponieważ adres URL wylogowania jest już buforowany. Ale można założyć, że każdy przyzwoity akcelerator byłby w stanie odfiltrować większość adresów URL wylogowania.
HyperCas,
2
HyperCas, akceleratory odfiltrowujące wylogowane adresy URL to teoria, którą rozważałem i jeden z powodów, dla których zdecydowałem się opublikować pytanie. Czuję się trochę niechętny zaufaniu logice akceleratora i pewnego dnia użytkownik z kiepskim akceleratorem narzeka, że ​​nie może się zalogować. Czy wiesz, czy są zgodne ze standardem lub czy taki standard istnieje?
Daniel Liuzzi
Każdy akcelerator, który automatycznie przesłał formularz (na przykład), byłby złośliwym oprogramowaniem IMO ... jest całkowicie nielogiczne sądzić, że akcelerator prześle formularz automatycznie. Wyobraź sobie, że odwiedzasz Google. Jak może przesłać formularz wyszukiwania? Nikt nie może uwzględnić złośliwego oprogramowania, ponieważ jest zbyt nieprzewidywalne i nie przestrzega zasad.
Alex,
3
@AlexW - Myślę, że źle zrozumiałeś moje pytanie. Proponowany przeze mnie scenariusz akceleratora polega na pokazaniu możliwego problemu przy korzystaniu z GET, a nie POST, więc nie byłoby żadnej formy do publikowania, tylko zwykłe linki, po których akceleratorach nie byłoby problemów.
Daniel Liuzzi
1
Zdaję sobie sprawę, że jestem o wiele za późno, ale Alex, nie o to pyta Daniel. Mówi, że jeśli użytkownik kliknie link wylogowania, a akcelerator zwróci buforowaną stronę wylogowania bez wchodzenia w aplikację, to użytkownik pozostanie zalogowany. Nie ma to nic wspólnego ze złośliwym oprogramowaniem, chociaż sprawdzenie informacji o łańcuchu User-Agent nie naprawi w każdym razie wszystko.
Rob Grant,

Odpowiedzi:

475

Zastosowanie POST.

W 2010 r. Używanie GETbyło prawdopodobnie akceptowalną odpowiedzią. Ale dzisiaj (w 2013 r.) Przeglądarki pobierają strony, które „myślą”, że odwiedzą w następnej kolejności.

Oto jeden z programistów StackOverflow mówiący o tym problemie na Twitterze:

Chciałbym podziękować mojemu bankowi za wylogowanie się z żądania GET, a zespołowi Chrome za przydatne wstępne pobieranie adresów URL. - Nick Craver ( @Nick_Craver ) 29 stycznia 2013

fajny fakt: StackOverflow służy do obsługi wylogowania za pomocą GET, ale już nie.

David Murdoch
źródło
2
Dzięki za tę aktualizację, Dave. Nawet nie zauważyłem, że SO przeniosło ich wylogowanie na POST i szczerze mówiąc, nie miałem pojęcia, że ​​Chrome ma wbudowane pobieranie wstępne. Wreszcie, cytowany przez ciebie wątek nigdy nie byłby lepszym przykładem problemu opisanego w moim moje pytanie i potwierdza moje podejrzenia. Głosuję za odpowiedzią i przyjmuję ją jako odpowiedź zaakceptowaną.
Daniel Liuzzi
4
W mojej przeglądarce wylogowanie z Stackoverflow wygląda jak <li> <a href="https://stackoverflow.com/users/logout"> wyloguj się </a> </li>, co jest GET, a nie POST
Boatcoder
9
@ Mark0978, kliknij link.
David Murdoch
2
Ciekawy. To prawdopodobnie jedna z moich najmniej ulubionych funkcji, wylogowanie, które pyta mnie, czy jestem pewien. Zgadnij, że powstrzymuje to pobieranie przed wylogowaniem, ale Amazon, Ebay i Gmail używają GET do wylogowania bez tej strony sztuczki pomiędzy tym, co użytkownik mówi, że jest wylogowaniem, a faktycznym zdarzeniem wylogowania. Wyobrażam sobie, że pomiędzy stronami wiele osób błędnie uważa, że ​​zostali wylogowani. Problemy z tym związane z SO są minimalne, nie wiążą się z żadnymi pieniędzmi, a 99% wszystkiego jest publiczne.
Boatcoder
7
@ Red Zgodnie ze standardem HTTP / 1.1 jest to wina serwera, a nie przeglądarki. Oczekuje się, że GET nie będzie miał skutków ubocznych po stronie serwera. Standard mówi nawet „użytkownik nie zażądał skutków ubocznych, dlatego nie można za nie ponosić odpowiedzialności”.
eyuelt
45

W REST nie powinno być sesji, dlatego nie ma nic do zniszczenia. Klient REST uwierzytelnia się na każde żądanie. Zalogowany lub wylogowany, to tylko złudzenie.

Naprawdę pytasz, czy przeglądarka będzie nadal wysyłać informacje uwierzytelniające przy każdym żądaniu.

Prawdopodobnie, jeśli twoja aplikacja wywołuje złudzenie bycia zalogowanym, powinieneś być w stanie „wylogować się” za pomocą javascript. Nie jest wymagana podróż w obie strony.


Rozprawa polowa - sekcja 5.1.3

każde żądanie od klienta do serwera musi zawierać wszystkie informacje niezbędne do zrozumienia żądania i nie może korzystać z żadnego kontekstu przechowywanego na serwerze. Stan sesji jest zatem w całości przechowywany na kliencie

Darrel Miller
źródło
1
Właściwie nie byłem tego świadomy. W takim razie wydaje mi się, że moja aplikacja wcale nie będzie bardzo RESTful, ponieważ korzystam z ASP.NET MVC z FormsAuthentication i opiera się ona na sesjach ...
Daniel Liuzzi
19
ale w praktyce dane logowania są przechowywane w pliku cookie oznaczonym httponlyatrybutem, aby zapobiec niektórym zagrożeniom xss, co oznacza, że ​​można je zresetować tylko z serwera (bez ręcznego czyszczenia pliku cookie)
Remus Rusanu
6
„Ręcznie” jak u użytkownika przechodzi do ustawień przeglądarki i wybiera opcję „Wyczyść pliki cookie”. Trudno zaakceptować sposób wylogowania się z witryny.
Remus Rusanu,
1
@Remus Ahhh, jak znakomita przeglądarka internetowa sprawia, że ​​pisanie aplikacji internetowych jest tak bolesne.
Darrel Miller,
1
@DarrelMiller tak, jednak nieodwołanie JWT po stronie serwera jest zagrożeniem bezpieczeństwa. Nawet jeśli tokeny nie są przechowywane na serwerze, powinny zostać umieszczone na czarnej liście, gdy użytkownik wyloguje się / zmieni hasła / zmieni role / quits / etc, aby zapobiec nadużyciom (przynajmniej do ich wygaśnięcia).
java-addict301
38

Jednym ze sposobów GETmoże być nadużycie w tym miejscu, że osoba (być może konkurent :) umieściła tag internetowy z src="<your logout link>"KAŻDYM w Internecie, a jeśli użytkownik Twojej witryny natknie się na tę stronę, zostanie nieświadomie wylogowany.

raveren
źródło
4
Nie, to nie jest poprawne. Link do wylogowania będzie działał tylko wtedy, gdy zostaną przesłane prawidłowe dane cookie, które nie będą z innej domeny. I nawet jeśli identyfikator sesji jest zapisany w adresie URL, to też nie działałoby, ponieważ zmieniają się dla każdej sesji.
Richard H
4
Wow, nigdy o tym nie myślałem! Jest jeszcze jeden powód, aby nie używać GET i kolejny powód, dla którego nie rozumiem, dlaczego wszyscy to robią. Cholera, teraz kusi mnie, aby dołączyć do mojego postu stackoverflow.com/users/logout „image” i zobaczyć, co się stanie :-D
Daniel Liuzzi
24
src = to proste żądanie przeglądarki, nie pochodzi od strony serwera, ale od klienta. Przenosi wszystkie pliki cookie i pochodzi z adresu IP użytkownika. Właśnie dlatego działają piksele śledzące reklamy. Jedynym sposobem ustalenia takiego exploita byłoby sprawdzenie strony odsyłającej.
raveren
12
SuperLogout.com robi dokładnie to (ładuje /logoutadresy URL w ukrytych obrazach) i działa.
Dan Dascalescu
9
Odp .: SuperLogout ... Nie wiem, dlaczego to kliknąłem.
MI Wright,
21

Aby być poprawnym, GET / POST (lub inne czasowniki) są działaniami na pewnym zasobie (adresowanym przez URL) - więc ogólnie dotyczy stanu zasobu, a nie stanu aplikacji jako takiego. Tak więc w prawdziwych nastrojach powinieneś mieć taki adres URL, jak [host name]\[user name]\session„DELETE” byłby właściwym czasownikiem dla akcji wylogowania.

Używanie [host name]\bla bla\logoutjako adresu URL w rzeczywistości nie jest w pełni REST (IMO), więc po co debata na temat poprawnego użycia GET / POST na nim?

Oczywiście używam GET do wylogowania adresu URL w moich aplikacjach :-)

VinayC
źródło
2
W takim przypadku argumentowałbym, że posiadanie części [nazwa użytkownika] w adresie URL wydaje się niepotrzebne, ponieważ użytkownicy zawsze wylogowują się (tj. USUŃ) z własnej sesji; nigdy innych użytkowników ”:-)
Daniel Liuzzi
1
Nie bardzo - mówimy, że sesja jest zasobem i chcemy ją usunąć. Aby więc jednolicie adresować każdą sesję, musisz mieć nazwę użytkownika jako część adresu URL. Twój argument jest tak dobry, jak powiedzenie wydania akcji PUT w [galeria zdjęć] \ pictures oznacza, że ​​dodajesz do swoich zdjęć (dostępne w [galeria zdjęć] \ [nazwa użytkownika] \ zdjęcia). Należy zająć się wyraźnie różnymi zasobami, nie może być w tym żadnych domniemań. Witryna może umożliwiać innym użytkownikom dodawanie zdjęć do Twojej galerii - będzie to częścią kontroli dostępu, tak jak możesz mieć superużytkownika, który może zabić sesje dowolnej osoby.
VinayC,
1
Z filozoficznego punktu widzenia można nazwać sesje i zdjęcia „zasobami”, ale realistycznie nie traktowałbym ich tak samo. Sesje są zawsze wewnętrznie ograniczone do bieżącego użytkownika (stąd nazwa Sesja) i przynajmniej w ASP.NET nie ma możliwości uzyskania dostępu do sesji innego użytkownika. Nawet twórca aplikacji nie ma bezpośredniego sposobu wyliczenia wszystkich aktywnych sesji ani sposobu zabicia sesji indywidualnie. Możesz zrestartować aplikację, aby zabić wszystkie sesje (InProc), ale nie nazwałbym tej kontroli dostępu. Pomijając adresy URL, wciąż pozostaje pytanie: GET czy POST?
Daniel Liuzzi,
Zasób, stąd jego adres (URL) są ważną częścią REST. Więc jeśli wybierzesz adres URL, jak powiedziałem, DELETE stanie się poprawnym słowem - nie GET ani POST. Ponadto, nawet jeśli ograniczasz się do ASP.NET, zawsze możesz mieć swojego niestandardowego dostawcę stanu, który da ci możliwość wyliczenia sesji i zabicia innych sesji w razie potrzeby. W przypadku nieprofesjonalnych sesji in-proc, trochę majstrowania w global.asax powinno dać ci taką funkcjonalność. To naprawdę pytanie, czy taka funkcjonalność byłaby potrzebna, czy nie. W rzadkich przypadkach ludzie ponownie uruchamiają witrynę, aby wykopać użytkowników z witryny.
VinayC,
To dla mnie najbardziej sensowne. Daj interfejsowi WWW trasę sesji i wywołaj na nim DELETE. Czy to ../session lub ../session/current. Dziękuję @ VinayC
Simon Hooper
16

Wylogowanie nie ma wpływu na samą aplikację. Zmienia stan użytkownika w stosunku do aplikacji. W tym przypadku wydaje się, że twoje pytanie jest bardziej oparte na tym, jak użytkownik powinien zainicjować polecenie, aby rozpocząć tę akcję. Ponieważ nie jest to „działanie destrukcyjne”, sesja zostanie porzucona lub zniszczona, ale ani aplikacja, ani dane nie zostaną zmienione, zezwolenie obu metodom na zainicjowanie procedury wylogowania jest niemożliwe. Post powinien być wykorzystywany przez wszelkie działania inicjowane przez użytkownika (np. - użytkownik klika „Wyloguj się”), podczas gdy get może być zarezerwowany na wylogowanie inicjowane przez aplikację (np. - wyjątek wykrywający potencjalną ingerencję użytkownika wymusza przekierowanie na stronę logowania przy wylogowaniu GET ).

Joel Etherton
źródło
Ciekawy; Nigdy o tym nie myślałem. +1.
strager
Może to zależeć od aplikacji (pewnego rodzaju zachowanie polegające na „usuwaniu kaskadowym”), ale masz rację.
Andres Jaan Tack
@ JoelEtherton Dziękuję Joel, czytałem odpowiedzi zastanawiając się, kiedy trafię na właściwą. :)
Kirill Fuchs
4
Jest to mylące, ponieważ wylogowanie zmienia stan. POST jest czasownikiem zmieniającym stan. GET służy do uzyskiwania danych bezstanowych. Jest to mylące, ponieważ oczekujemy, że żądania POST zawierają ładunki. Jak zauważono poniżej, DELETE byłoby najbardziej poprawne dla obiektu sesji.
Michael Cole
1
@MichaelCole: Zgodziłbym się z reprezentacją trudności między POST a GET. Nie zgodziłbym się jednak na użycie czasownika DELETE. DELETE służy do obsługi zasobu, a sesja nie jest zasobem w tym sensie. Zastanów się, czy możesz go USUNĄĆ, powinieneś także móc go umieścić.
Joel Etherton
16

Witam z mojego punktu widzenia, kiedy logujesz się, sprawdzasz nazwę użytkownika / hasło i jeśli są one zgodne, tworzysz token logowania.

UTWÓRZ token => metoda POST

Kiedy się wylogowujesz, odwracasz tokena, więc dla mnie najbardziej logiczną metodą powinno być USUŃ

DELETE token => metoda DELETE

miorey
źródło
4
Ciekawy kąt.
Drumbeg
1
Używam tej metody w aplikacjach REST Spring Boot.
Please_Dont_Bully_Me_SO_Lords
1
semantycznie poprawne. Zgadzam się ...
DAG
1

Scenariusz buforowania wstępnego jest interesujący. Ale zgaduję, że jeśli wiele witryn i tak NIE martw się o to, to może nie powinieneś.

A może link może być zaimplementowany w javascript?

Edycja: Jak rozumiem, technicznie GET powinien być dla żądań tylko do odczytu, które nie zmieniają stanu aplikacji. POST powinien dotyczyć żądań zapisu / edycji, które zmieniają stan. Jednak inne problemy z aplikacjami mogą preferować GET zamiast POST w przypadku niektórych żądań zmieniających stan, i nie sądzę, aby był z tym problem.

Richard H
źródło
Dzięki. Stan DB nie zostałby zmieniony, ale zmieniłby się stan sesji . Jedyny problem, jaki widzę, to ten, o którym wspomniałem w pytaniu, dotyczący wyrzucenia użytkowników. Nieniszczące, ale raczej denerwujące. Zwykle używam mantry „jeśli duzi faceci to robią, wtedy też musi być OK”. Chciałem tylko wiedzieć, jakie opinie mają na ten temat inni.
Daniel Liuzzi,
0

Cóż, jeśli pozwolisz aplikacji internetowej zrezygnować z sesji za pomocą skryptu wylogowania, zwykle też nie potrzebujesz. Zwykle istnieje zmienna sesji, która jest unikalna dla sesji, którą chcesz porzucić.

Obrabować
źródło
Czy mógłbyś opracować „skrypt wylogowania”? Nie jestem pewien, czy masz na myśli ustawienie wygasania plików cookie (co nie eliminuje potrzeby ręcznego wylogowywania się użytkowników).
Daniel Liuzzi
Skrypt wylogowania zakończyłby sesję wywołania go przez użytkownika (a właściwie: przeglądarkę). W ASP.net sesja jest obiektem po stronie serwera, który można porzucić. PHP ma podobny system. Ponieważ przeglądarka wywołuje skrypt kończący sesję, już wie, który z nich zakończyć, eliminując potrzebę stosowania zmiennych POST lub GET.
Rob
1
Tak, rozumiem cię teraz. Mam już skrypt na swoim miejscu, w szczególności FormsAuthentication.SignOut (), ale moje pytanie dotyczy tego, jak wywołać skrypt, jak w GET lub POST.
Daniel Liuzzi
Och, masz adres URL w formie? Nie ma znaczenia, że ​​nie przekazujesz żadnych informacji. Najgorsze, co może się zdarzyć, to ręczne otwarcie skryptu, wylogowanie się. Nie uczyniłbym go nawet polem formularza, jeśli nie jest to konieczne, link do skryptu też by działał. Jeśli wyślesz informacje do skryptu, prawdopodobnie wybrałbym test POST, aby nie pokazywać żadnych informacji użytkownikowi (chyba że przegląda źródło strony), a jeśli odświeży się, dostanie ostrzeżenie z przeglądarki (strona wygasła), co może być pożądane.
Rob
0

Ostatnio pracowałem nad projektem, którego używam GET do wylogowania Poniżej znajduje się kod w Nodejs Express i działa on doskonale

twój router.js

const express = require("express");
router.get("/signout", signout);

twoja kontroler.js

exports.signout  = (req, res) => {
        res.clearCookie('t'); //clearing cookie, which is 
            //assign to the user during sign in.          
            res.json({message : 'Signout success'});   
        };
xSachinx
źródło
-2

Nie rozumiem, jak wylogowanie (cofnięcie uprawnień użytkownika) jest działaniem dezintegrującym. Jest tak, ponieważ akcja „wylogowania” powinna być dostępna tylko dla użytkowników, którzy są już zalogowani, w przeciwnym razie byłaby przestarzała.

Losowo generowany ciąg znaków zawarty w ciasteczkach przeglądarki oznacza sesję użytkownika. Istnieje wiele sposobów na zniszczenie go, więc skuteczne wylogowanie jest jedynie usługą dla odwiedzających.

jpluijmers
źródło
2
wgetw trybie pająka z poprawnym sesyjnym plikiem cookie na prywatnej wiki było to, co faktycznie musiałem zrobić raz. Oczywiście jednym z pierwszych zaindeksowanych adresów URL był /logout.
Helgi
5
Spróbuj przejść do SuperLogout.com, aby zobaczyć, jak destrukcyjne są żądania GET do /logoutstron. Na przykład musisz ponownie zalogować się do Gmaila, zalogować się ponownie na czacie, znaleźć swoje miejsce w przewijanych rozmowach w Hangouts itp. - dotyczy to tylko Google.com.
Dan Dascalescu