Cookies

Ostatnia aktualizacja: 02 września 2020

Ciasteczka są to małe ilości danych, które są przechowywane na twoim komputerze za pomocą plików tekstowych i wysyłane są do serwera z żądaniami HTTP. Takie pliki zawierają w sobie króciutkie informacje takie jak np. id usera, jakiś zakodowany numer, ostatnią wizytę, numer aktualnej sesji itp.

Bardzo często ciasteczka służą do komunikacji przeglądarka-serwer, ponieważ zarówno serwer, jak i przeglądarka mogą przesyłać takie krótkie informacje między sobą. Dzięki takiej komunikacji strona może przekazywać informacje między podstronami, pamiętać że dany użytkownik właśnie jest zalogowany, przekazywać sobie jakieś dane o sesji itp.

Jak działa taka komunikacja?
Za pomocą odpowiednich nagłówków. W rozdziale o Ajaxie omawialiśmy sobie protokół HTTP. Jak wiemy z tamtych rozważać, komunikacja między przeglądarką, a serwerem odbywa się podobne do gry w tenisa. Przeglądarka pyta się o zasób, serwer odpowiada. W takiej komunikacji obie strony wysyłają sobie odpowiednie dane, do których dołączane są nagłówki. Przeglądarka wysyłając zapytanie do serwera wysyła z nim request headers. Gdy serwer odpowiada wraz z odpowiedzią wysyła response headers.

Sprawdź sobie w zakładce Network debugera request dla tej strony. Powinien być pierwszy na liście. Wśród nagłówków response powinien znajdować się nagłówek Set-Cookie - oznacza to, że serwer przesyła do nas ciasteczko.

cookies response

Jeżeli przeglądarka natrafi na taki nagłówek, ustawi sobie ciasteczko jakie przesłał jej serwer, a następnie przy każdym requeście do tego serwera będzie je wysyłać w nieco skróconej formie posługując się nagłówkiem Cookie.

Sprawdzimy to w debugerze w zakładce Application, wybierając z bocznego menu Cookies:

Zakładka Application w debugerze

Jak widzisz, przeglądarka otrzymała od serwera informację o ciasteczku, a następnie odpowiednio je sobie zapisała.
Od tej pory każde nowe połączenie z tą domeną sprawi, że takie ciasteczko będzie wysyłane wraz z requestem:

cookies request
Większość skryptów z tego działu będziesz musiał odpalić z serwera lokalnego.
Obostrzenia względem ciasteczek są bardzo podobne do same-origin policy, czyli zabezpieczeń, które nie pozwalają łączyć się asynchronicznie (ajax) gdzie tylko chcemy. Najczęściej ograniczeni jesteśmy do własnej domeny, chyba, że domena z którą się komunikujemy, ustawi odpowiednie nagłówki.

Tak samo jak po stronie serwera możemy tworzyć ciasteczka (np. w PHP za pomocą właściwości $_COOKIES), tak i JavaScript umożliwia nam tworzyć takie ciastka. Poniżej omówimy jak to robić.

Tworzymy pierwsze ciasteczko

Aby utworzyć ciasteczko musimy je utworzyć w odpowiedni sposób ustawiając wartość dla właściwości document.cookie:


document.cookie = "nazwa=wartosc"
console.log(document.cookie); //pokaż wszystkie ciastka na danej stronie

Teoretycznie nazwa i wartość ciastka może zawierać dowolne znaki. Dla zachowania poprawnego formatowania, warto zastosować tutaj funkcję encodeURIComponent():


document.cookie = encodeURIComponent("nazwa użytkownika") + "=" + encodeURIComponent("Karol Nowak");
console.log(document.cookie); //"nazwa%20u%C5%BCytkownika=Karol%20Nowak"

Postać ciasteczka

Każde ciasteczko może składać się z kilku części:


document.cookie = "user=John; path=/; expires=Tue, 19 Jan 2038 03:14:07 GMT; secure"
Parametr path

Oznacza adres z jakiego dane ciasteczko będzie dostępne. Ścieżka taka powinna być absolutna. Domyślnie jest aktualny adres.

Jeżeli dla przykładu ustawimy path=/user, dostęp do tego ciasteczka będzie miała podstrona /user, /user/inventory ale już nie strona /elo-pet.

Dość ważne jest, by nie pomijać tego parametru. Gdy założysz dane ciastko na którejś z podstron, może się okazać później, że inne podstrony nie będą miały do niego dostępu.

Parametr expires i max-age

Po ustawieniu ciasteczka będzie one aktywne do zamknięcia przeglądarki. Parametr expires oznacza datę do której dane ciastko będzie aktywne:


        //plus jeden dzień od teraz
        let date = new Date(Date.now() + 86400e3);
        date = date.toUTCString();
        document.cookie = "user=John; expires=" + date;
        

Ustawienie daty na mniejszą od obecnej spowoduje, że dane ciasteczko zostanie usunięte.

Alternatywnym zapisem dla expires jest max-age, który oznacza liczbe sekund od teraz, po których dane ciastko zostanie usunięte:


        document.cookie = "user=John; max-age=3600";
        
Parametr secure

Domyślnie gdy założymy ciasteczko, dostęp do niego będzie możliwy zarówno z adresu http:// jak i https://. Jeżeli użyjemy parametru secure, dostęp będzie możliwy tylko z https://:


        document.cookie = "user=John; max-age=3600; secure";
        
Parametr path

Oznacza adres z jakiego dane ciasteczko będzie dostępne. Ścieżka taka powinna być absolutna. Domyślnie jest aktualny adres.

Jeżeli dla przykładu ustawimy path=/user, dostęp do tego ciasteczka będzie miała podstrona /user, /user/inventory ale już nie strona /elo-pet.

Dość ważne jest, by nie pomijać tego parametru. Gdy założysz dane ciastko na którejś z podstron, może się okazać później, że inne podstrony nie będą miały do niego dostępu.

Parametr expires i max-age

Po ustawieniu ciasteczka będzie one aktywne do zamknięcia przeglądarki. Parametr expires oznacza datę do której dane ciastko będzie aktywne:


        //plus jeden dzień od teraz
        let date = new Date(Date.now() + 86400e3);
        date = date.toUTCString();
        document.cookie = "user=John; expires=" + date;
        

Ustawienie daty na mniejszą od obecnej spowoduje, że dane ciasteczko zostanie usunięte.

Alternatywnym zapisem dla expires jest max-age, który oznacza liczbe sekund od teraz, po których dane ciastko zostanie usunięte:


        document.cookie = "user=John; max-age=3600";
        
Parametr secure

Domyślnie gdy założymy ciasteczko, dostęp do niego będzie możliwy zarówno z adresu http:// jak i https://. Jeżeli użyjemy parametru secure, dostęp będzie możliwy tylko z https://:


        document.cookie = "user=John; max-age=3600; secure";
        
Parametr httpOnly

Jeżeli serwer wyśle do nas nagłówek Set-Cookie, który będzie zawierał parametr httpOnly, nie będziemy mieli dostępu do tego ciasta z poziomu Javascript.

Parametr samesite

Parametr samesite służy głównie do zabezpieczenia przed atakiem CSRF czy Pixel Perfect.

Funkcje do tworzenia ciastek

Dla ułatwienia tworzenia ciastek wraz z parametrami, możemy utworzyć funkcję:


function setCookie(name, val, days, path, domain, secure) {
    if (navigator.cookieEnabled) { //czy ciasteczka są włączone
        const cookieName = encodeURIComponent(name);
        const cookieVal = encodeURIComponent(val);
        let cookieText = cookieName + "=" + cookieVal;

        if (typeof days === "number") {
            const data = new Date();
            data.setTime(data.getTime() + (days * 24*60*60*1000));
            cookieText += "; expires=" + data.toGMTString();
        }

        if (path) {
            cookieText += "; path=" + path;
        }
        if (domain) {
            cookieText += "; domain=" + domain;
        }
        if (secure) {
            cookieText += "; secure";
        }

        document.cookie = cookieText;
    }
}

setCookie("mojeCiasteczko", "przykladowa wartość");

Odczyt ciasteczka

Aby odczytać dane ciasteczko, także skorzystamy z właściwości document.cookie.

Kolejne ciastka zapisywane są jako jeden duży ciąg danych:


nazwacookie1=wartosccookie1; nazwacookie2=wartosccookie2; nazwacookie3=wartosccookie3;

Aby wydzielić poszczególne cookie do tablicy skorzystamy z funkcji split, która podzieli powyższy ciąg na części i zwróci je w formie tablicy. Aby zabezpieczyć się przed sytuacją, gdyby miedzy ciastkami nie było by spacji, użyjemy tutaj wyrażenia regularnego:


const cookies = document.cookie.split(/; */); //dopasuje "; " ale też ";"

Po podziale dostaniemy fragmenty nazwacookie1=wartosccookie1, które także musimy podzielić.

Napiszmy funkcję, która zrobi to dla nas:


function showCookie(name) {
    if (document.cookie !== "") {
        const cookies = document.cookie.split(/; */);

        for (let i=0; i<cookies.length; i++) {
            const cookiePart = cookies[i].split("=");
            const cookieName = cookiesPart[0];
            const cookieVal = cookiesPart[1];
            if (cookieName === decodeURIComponent(name)) {
                return decodeURIComponent(cookieVal);
            }
        }
    }
    return false;
}

showCookie("mojeCiasteczko")); //"przykładowa wartość"

Usuwanie ciasteczka

Aby usunąć dane ciasteczko musimy ustawić jego parametr expires na wcześniejszy od aktualnej daty. Możemy to zrobić korzystając z poniższej funkcji służącej do usuwania ciastek.


function deleteCookie(name) {
    const data = new Date();
    data.setTime(date.getMonth()-1);
    document.cookie = encodeURIComponent(name) + "=; expires=" + data.toGMTString();
}

Możemy też ustawić max-age na ujemną wartość:


function deleteCookie(name) {
    const cookieName = encodeURIComponent(name);
    document.cookie = cookieName + "=; max-age=-1;";
}

deleteCookie("mojeCiasteczko");

Wszelkie prawa zastrzeżone. Jeżeli chcesz używać jakiejś części tego kursu, skontaktuj się z autorem. Aha - i ta strona korzysta z ciasteczek.

Menu