Prawidłowy sposób usuwania plików cookie po stronie serwera

141

Na potrzeby procesu uwierzytelniania tworzę unikalny token, gdy użytkownik loguje się i umieszczam go w pliku cookie, który jest używany do uwierzytelniania.

Więc wysłałbym coś takiego z serwera:

Set-Cookie: token=$2a$12$T94df7ArHkpkX7RGYndcq.fKU.oRlkVLOkCBNrMilaSWnTcWtCfJC; path=/;

Działa we wszystkich przeglądarkach. Następnie, aby usunąć plik cookie, wysyłam podobny plik cookie z expirespolem ustawionym na 1 stycznia 1970 r

Set-Cookie: token=$2a$12$T94df7ArHkpkX7RGYndcq.fKU.oRlkVLOkCBNrMilaSWnTcWtCfJC; path=/; expires=Thu, Jan 01 1970 00:00:00 UTC; 

Działa to dobrze w przeglądarce Firefox, ale nie usuwa pliku cookie w przeglądarce IE lub Safari.

Jaki jest więc najlepszy sposób na usunięcie pliku cookie (najlepiej bez JavaScript)? Metoda „set-the-expires-in-past” wydaje się nieporęczna. A także dlaczego to działa w FF, ale nie w IE czy Safari?

Joshkunz
źródło
Zobacz także stackoverflow.com/a/20320610/212378
Alexis Wilke

Odpowiedzi:

209

Wysłanie tej samej wartości pliku cookie z ; expiresdołączonym nie spowoduje zniszczenia pliku cookie.

Unieważnij plik cookie, ustawiając pustą wartość i dołącz również expirespole:

Set-Cookie: token=deleted; path=/; expires=Thu, 01 Jan 1970 00:00:00 GMT

Pamiętaj, że nie możesz zmusić wszystkich przeglądarek do usunięcia pliku cookie. Klient może skonfigurować przeglądarkę w taki sposób, aby plik cookie trwał, nawet jeśli wygasł. Ustawienie wartości w sposób opisany powyżej rozwiązałoby ten problem.

Lekensteyn
źródło
52
"deleted"
Zalecałbym
8
@raulk Tak, masz rację. Zabawne, że wcześniej nie zostało to zauważone, mam nadzieję, że nie spowodowało to zbyt dużego problemu. yegor256, w większości przypadków powinna działać pusta wartość. Powiązane: niektórzy mogą się zastanawiać, dlaczego ich pliki cookie nie są usuwane nawet po wysłaniu tego nagłówka. W takim przypadku spójrz na pliki cookie z innych domen. Na przykład po usunięciu zostanie użyty foo=bar; domain=www.example.cominny plik cookie foo=qux; domain=.example.com.
Lekensteyn
3
„Klient może skonfigurować przeglądarkę w taki sposób, aby plik cookie był przechowywany, nawet jeśli wygasł. Ustawienie wartości w sposób opisany powyżej rozwiązałoby ten problem”. Czy klient nie mógł skonfigurować przeglądarki tak, aby ignorowała Twoje żądanie ustawienia zawartości pliku cookie na „usunięte”? Nie możesz zmusić klienta do zrobienia czegokolwiek, czego nie chce.
Ajedi32,
@ Ajedi32 Mógłby, ale wtedy musisz wykonać dodatkowy wysiłek, aby to zrobić (jako klient). Zachowanie polegające na ignorowaniu pustej wartości jest znacznie częstsze, nie ma sensu, aby przeglądarka ignorowała takie żądania, szczególnie w przypadku identyfikatorów sesji, które są unieważnione.
Lekensteyn
2
-1, ponieważ nigdy nie widziałem sposobu na skonfigurowanie przeglądarki tak, aby ignorowała wygaśnięcie pliku cookie i nie jestem przekonany, że istnieje jakakolwiek przeglądarka, która oferuje taką opcję. Co więcej, pierwsze zdanie twojej odpowiedzi, po dość śmiałej edycji @ DaveJarvisa, jest teraz całkowicie fałszywe dla każdej większej przeglądarki lub dowolnego klienta użytkownika zgodnego ze specyfikacją. tools.ietf.org/search/rfc6265#section-5.3 stanowi, że Klient użytkownika MUSI usunąć wszystkie wygasłe pliki cookie z magazynu plików cookie, jeśli w dowolnym momencie wygasły plik cookie istnieje w magazynie plików cookie”. i zgodnie z moją najlepszą wiedzą to właśnie robi każda przeglądarka.
Mark Amery
46

W chwili, gdy piszę tę odpowiedź, przyjęta odpowiedź na to pytanie wydaje się wskazywać, że przeglądarki nie muszą usuwać pliku cookie w przypadku otrzymania zastępczego pliku cookie, którego Expireswartość należy do przeszłości. To twierdzenie jest fałszywe. Ustawienie Expiresna przeszłość to standardowy, zgodny ze specyfikacją sposób usuwania pliku cookie, a oprogramowanie użytkownika jest wymagane przez specyfikację, aby go przestrzegać.

Używanie Expiresatrybutu w przeszłości do usuwania pliku cookie jest poprawne i jest sposobem usuwania plików cookie podyktowanym przez specyfikację. W sekcji przykładów dokumentu RFC 6255 podano :

Na koniec, aby usunąć plik cookie, serwer zwraca nagłówek Set-Cookie z datą wygaśnięcia w przeszłości. Serwer pomyślnie usunie plik cookie tylko wtedy, gdy ścieżka i atrybut domeny w nagłówku Set-Cookie są zgodne z wartościami używanymi podczas tworzenia pliku cookie.

Sekcja Wymagania klienta użytkownika zawiera następujące wymagania, które łącznie powodują, że plik cookie musi zostać natychmiast usunięty, jeśli agent użytkownika otrzyma nowy plik cookie o tej samej nazwie, którego data ważności już minęła

  1. Jeśli [podczas otrzymywania nowego pliku cookie] magazyn plików cookie zawiera plik cookie o tej samej nazwie, domenie i ścieżce, co nowo utworzony plik cookie:

    1. ...
    2. ...
    3. Zaktualizuj czas utworzenia nowo utworzonego pliku cookie, aby odpowiadał czasowi utworzenia starego pliku cookie.
    4. Usuń stare pliki cookie ze sklepu plików cookie.
  2. Wstaw nowo utworzony plik cookie do magazynu plików cookie.

Plik cookie „wygasł”, jeśli ma datę ważności w przeszłości.

Klient użytkownika MUSI usunąć wszystkie wygasłe pliki cookie z magazynu plików cookie, jeśli w dowolnym momencie wygasły plik cookie znajduje się w magazynie plików cookie.

Punkty 11-3, 11-4 i 12 powyżej razem oznaczają, że po otrzymaniu nowego pliku cookie o tej samej nazwie, domenie i ścieżce stary plik cookie musi zostać usunięty i zastąpiony nowym. Wreszcie poniższy punkt dotyczący wygasłych plików cookie dodatkowo mówi, że po wykonaniu tej czynności nowy plik cookie również musi zostać natychmiast usunięty. Specyfikacja nie daje w tej kwestii żadnego miejsca dla przeglądarek; gdyby przeglądarka oferowała użytkownikowi opcję wyłączenia wygaśnięcia plików cookie, jak sugeruje to akceptowana odpowiedź w niektórych przeglądarkach, byłoby to niezgodne ze specyfikacją. (Taka funkcja również byłaby mało przydatna i o ile wiem, nie istnieje w żadnej przeglądarce).

Dlaczego więc w PO w tym pytaniu stwierdzono, że podejście to zawodziło? Chociaż nie odkurzyłem kopii Internet Explorera, aby sprawdzić jego zachowanie, podejrzewam, że było to spowodowane Expiresnieprawidłowym sformułowaniem wartości OP ! Użyli tej wartości:

expires=Thu, Jan 01 1970 00:00:00 UTC;

Jednak jest to niepoprawne składniowo z dwóch powodów.

Sekcja składni specyfikacji mówi, że wartością Expiresatrybutu musi być

rfc1123 -date , zdefiniowana w [RFC2616], Sekcja 3.3.1

Podążając za drugim linkiem powyżej, znajdujemy to jako przykład formatu:

Sun, 06 Nov 1994 08:49:37 GMT

i przekonaj się, że definicja składni ...

  1. wymaga, aby daty były zapisywane w formacie dzień miesiąc rok , a nie miesiąc dzień rok , jak jest to używane przez osobę zadającą pytania.

    W szczególności definiuje rfc1123-datew następujący sposób:

    rfc1123-date = wkday "," SP date1 SP time SP "GMT"
    

    i definiuje w date1ten sposób:

    date1        = 2DIGIT SP month SP 4DIGIT
                 ; day month year (e.g., 02 Jun 1982)
    

i

  1. nie zezwala UTCjako strefa czasowa.

    Specyfikacja zawiera następujące stwierdzenie o tym, jakie przesunięcia stref czasowych są dopuszczalne w tym formacie:

    Wszystkie znaczniki daty / czasu HTTP MUSZĄ być przedstawione w czasie Greenwich (GMT), bez wyjątku.

    Co więcej, jeśli będziemy kopać głębiej w oryginalnej specyfikacji tego formatu datetime, okazuje się, że w jego początkowej specyfikacji w https://tools.ietf.org/html/rfc822 , że sekcja składni listy „UT” (czyli „czas uniwersalny” ) jako możliwej wartości, ale robi nie lista UTC (Coordinated Universal Time) jako ważny. O ile wiem, używanie „UTC” w tym formacie daty nigdy nie było ważne; nie była to prawidłowa wartość, kiedy format został po raz pierwszy określony w 1982 r., a specyfikacja HTTP przyjęła bardziej restrykcyjną wersję formatu, zakazując stosowania wszystkich wartości „strefy” innych niż „GMT”.

Jeżeli Pytający pytanie tutaj miał zamiast użył Expiresatrybutu jak to , a następnie:

expires=Thu, 01 Jan 1970 00:00:00 GMT;

to przypuszczalnie by zadziałało.

Mark Amery
źródło
15

Ustawienie „wygasa” na przeszłą datę jest standardowym sposobem usunięcia pliku cookie.

Twój problem prawdopodobnie wynika z nietypowego formatu daty. IE prawdopodobnie oczekuje tylko czasu GMT.

niepodważalny
źródło
2

Użyj Max-Age = -1 zamiast „Expires”. Jest krótszy, mniej wybredny w składni, a Max-Age i tak ma pierwszeństwo przed Expires.

Steven Pemberton
źródło
-1

Dla implementacji GlassFish Jersey JAX-RS rozwiązałem ten problem za pomocą wspólnej metody opisywania wszystkich wspólnych parametrów. Przynajmniej trzy parametry muszą być równe: nazwa (= "nazwa"), ścieżka (= "/") i domena (= null):

public static NewCookie createDomainCookie(String value, int maxAgeInMinutes) {
    ZonedDateTime time = ZonedDateTime.now().plusMinutes(maxAgeInMinutes);
    Date expiry = time.toInstant().toEpochMilli();
    NewCookie newCookie = new NewCookie("name", value, "/", null, Cookie.DEFAULT_VERSION,null, maxAgeInMinutes*60, expiry, false, false);
    return newCookie;
}

I używaj tego powszechnego sposobu ustawiania plików cookie:

NewCookie domainNewCookie = RsCookieHelper.createDomainCookie(token, 60);
Response res = Response.status(Response.Status.OK).cookie(domainNewCookie).build();

i usunąć plik cookie:

NewCookie domainNewCookie = RsCookieHelper.createDomainCookie("", 0);
Response res = Response.status(Response.Status.OK).cookie(domainNewCookie).build();
RoutesMaps.com
źródło
dla mnie, kiedy ustawię maxAge na 0, generuje plik cookie z Max-Age = 0, który Chrome wydaje się ignorować. W RFC 6265 sekcja 4.1.1 określa składnię Max-Age jako „niezerową cyfrę”. To może być powód. Chociaż, jak wspomniał @ JoshC13, sekcja 5.2.2 mówi o interpretowaniu wartości mniejszych lub równych zeru. Więc to w pewnym sensie sobie zaprzecza ...
Matthijs Wessels,
Nie znam szczegółów, ale te wartości w parze naprawdę działają w Chrome i innych przeglądarkach: maxAgeInMinutes * 60, expiry.
RoutesMaps.com
1
@MatthijsWessels Dobry chwyt! Kopałem trochę głębiej i pozorna sprzeczność jest w rzeczywistości zamierzona, jak zauważono w erracie na rfc-editor.org/errata/eid3430 . Aby „zmaksymalizować współdziałanie”, agenci użytkownika muszą interpretować zero lub minus Max-Agejako najwcześniejszą możliwą do przedstawienia datę i godzinę, ale serwery nie mogą wysyłać takiej Max-Agewartości. Wydaje mi się, że autorzy wiedzieli zarówno o istniejących klientach, którzy nie mogli obsługiwać, jak Max-Age=0i serwerach, które wysłały ją w czasie, gdy pisali specyfikację, i próbowali złagodzić problem z obu stron.
Mark Amery,
@ Crimean.us Ja też nie mogę już powtórzyć. Może zrobiłem coś złego
Matthijs Wessels
@MatthijsWessels Problem z ignorowaniem Max-Age = 0 został rozwiązany w moim przykładzie przez ustawienie daty wygaśnięcia na ZonedDateTime.now (). PlusMinutes (maxAgeInMinutes). Dla maxAgeInMinutes = 0 jest to bieżąca data i godzina. Ten kod działa przez długi czas w prawdziwej aplikacji internetowej.
RoutesMaps.com