Cookies

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 mówiliśmy sobie w tamtym rozdziale, 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

Podobnie będziesz pobierał wszystkie ciastka. Wpisz w konsoli document.cookie by zobaczyć co uzyskasz.

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"
path

Oznacza zakres ciasteczka, czyli z jakiego adresu będzie do niego dostęp.

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 /pet i potomne.

domain

Z jakiej domeny będzie dostęp do danego ciasteczka. Domyślnie ciasteczka są dostępne tylko z domeny, z której zostały ustawione.

Jeżeli ustawisz ciasteczko na adresie test.com, domyślnie nie będziesz miał do niego dostępu pod adresem auction.test.com. Jeżeli chciałbyś by taki dostęp był możliwy, powinieneś ustawić domenę na domain=test.com:


        document.cookie = "user=John";

        //na auction.test.com
        console.log(document.cookie); //""
        

        document.cookie = "user=John; domain=test.com";

        //na auction.test.com
        console.log(document.cookie); //"user=John"
        
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";
        
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";
        
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.

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.toUTCString();
        }

        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 cookie of cookies) {
            const [ cookieName, cookieVal ] = cookie.split("=");
            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.toUTCString();
}

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