Przejdź do głównej zawartości

Ciasteczka w 2026: SameSite działa inaczej w każdej przeglądarce

· 12 min aby przeczytać
Przemysław Majdak
Full-Stack Developer, Automation Engineer & Web Security Specialist

Powszechnie powtarzana zasada „brak atrybutu SameSite oznacza Lax" jest prawdziwa tylko w Chromium. Firefox nigdy nie wdrożył tego domyślnego zachowania w kanale stabilnym, Safari blokuje ciasteczka cross-site niezależnie od deklaracji, a dokument, na który wszyscy się powołują — „RFC 6265bis" — po piętnastu latach wciąż jest Internet-Draftem bez numeru RFC. Poniżej: co przeglądarki naprawdę robią z ciasteczkami we wrześniu 2026, gdzie mechanizm Lax+POST cicho maskuje błędy konfiguracji, dlaczego limit 400 dni jest mniej istotny niż siedmiodniowy cap Safari, i jak wygląda poprawna konfiguracja z prefiksami __Host- oraz atrybutem Partitioned.

Stan standardu: co jest normą, a co wciąż projektem

Dokument potocznie nazywany „RFC 6265bis" nie jest jeszcze RFC. To Internet-Draft grupy roboczej IETF HTTP (draft-ietf-httpbis-rfc6265bis), którego najnowsza wersja została opublikowana 31 sierpnia 2026 roku i wygasa 4 marca 2027 (datatracker.ietf.org). Ma status Standards Track i — jeśli zostanie zatwierdzony — zastąpi RFC 6265 z 2011 roku. Do tego czasu jest to projekt, który od kilkunastu lat opisuje raczej to, co przeglądarki już robią, niż to, co dopiero zrobią.

Ta kolejność jest kluczowa dla architekta: źródłem prawdy o zachowaniu ciasteczek nie jest draft, tylko konkretne implementacje przeglądarek, a te w 2026 roku rozjeżdżają się między sobą mocniej niż kiedykolwiek. Projektowanie warstwy sesyjnej wyłącznie na podstawie lektury specyfikacji prowadzi do systemu, który działa w Chromie i cicho gubi sesje w Safari.

Zmienił się też kontekst, w którym te decyzje zapadają. 22 kwietnia 2025 roku Google wycofał się z wieloletniego planu usunięcia ciasteczek third-party z Chrome'a, a 17 października 2025 wygasił większość inicjatywy Privacy Sandbox — odeszły między innymi Topics, Protected Audience, Attribution Reporting, IP Protection i Related Website Sets. Przetrwały trzy elementy: CHIPS, FedCM i Private State Tokens (consenteo.com). Chrome utrzymuje ciasteczka third-party domyślnie włączone, z przełącznikiem po stronie użytkownika w ustawieniach prywatności.

Praktyczny wniosek jest odwrotny do intuicji z lat 2020–2024: presja na migrację nie zniknęła, ale przesunęła się z „third-party cookies umrą" na „third-party cookies są partycjonowane i blokowane wybiórczo, w każdej przeglądarce inaczej".

SameSite w 2026: trzy przeglądarki, trzy różne domyślne zachowania

Powszechnie powtarzana teza, że „nowoczesne przeglądarki traktują brak atrybutu SameSite jako Lax", jest prawdziwa wyłącznie dla silnika Chromium. Rzeczywisty rozkład wygląda tak:

  • Chromium (Chrome, Edge) — brak atrybutu SameSite jest interpretowany jako Lax. To zachowanie wdrożone w 2020 roku i obowiązujące do dziś.
  • Firefoxnie stosuje Lax-by-default w kanale stabilnym. Preferencja network.cookie.sameSite.laxByDefault jest włączona tylko w Nightly; próba wdrożenia jej szerzej została wycofana ze względu na skalę uszkodzeń stron (bugzilla.mozilla.org). Ciasteczka bez atrybutu podlegają zamiast tego mechanizmowi Total Cookie Protection, który partycjonuje wszystkie ciasteczka third-party po stronie najwyższego poziomu.
  • Safari — kwestia domyślnej wartości SameSite jest w dużej mierze bezprzedmiotowa, ponieważ Intelligent Tracking Prevention blokuje ciasteczka w kontekście cross-site niezależnie od tego, czy zadeklarowano SameSite=None; Secure.

Konsekwencja dla projektowania integracji jest jednoznaczna: SameSite=None; Secure nie jest gwarancją, że ciasteczko dotrze w kontekście cross-site. Jest warunkiem koniecznym w Chromium i nieskutecznym w Safari. Każdy przepływ zakładający ciasteczka trzeciej strony — osadzone widgety, iframe'y z sesją, federacyjne logowanie w ramce — wymaga albo partycjonowania (sekcja o CHIPS poniżej), albo przepisania na FedCM, albo przeniesienia stanu na kanał first-party.

Poniższa tabela opisuje zachowanie w silniku Chromium, który jako jedyny implementuje pełny model z projektu specyfikacji:

Wartość SameSiteNawigacja top-level (cross-site GET)Top-level cross-site POSTZasoby osadzone (iframe, img, fetch)Wymóg flagi Secure
StrictBlokowaneBlokowaneBlokowaneNie
LaxDozwoloneBlokowaneBlokowaneNie
NoneDozwoloneDozwoloneDozwoloneTak
Brak atrybutuDozwolone (zachowanie Lax)Blokowane — z wyjątkiem okna 2 minut (Lax+POST)Blokowane (zachowanie Lax)Nie

Wiersz „Brak atrybutu" opisuje wyłącznie Chromium. W Firefoksie ciasteczko bez atrybutu zachowa się jak None z nałożonym partycjonowaniem, w Safari zostanie w kontekście cross-site odrzucone.

Pułapka dwóch minut: mechanizm Lax+POST wciąż działa i wciąż jest tymczasowy

Chromium utrzymuje wyjątek od reguły Lax, nazywany Lax+POST (w projekcie specyfikacji: tryb wymuszania „Lax-allowing-unsafe"). Ciasteczko ustawione bez atrybutu SameSite i nie starsze niż 2 minuty zostanie dołączone do żądania POST w nawigacji cross-site najwyższego poziomu, mimo że reguła Lax normalnie wymaga metody bezpiecznej.

Ten wyjątek istnieje nadal w 2026 roku i nadal jest w dokumentacji Chromium opisywany jako rozwiązanie tymczasowe, które zostanie usunięte — bez podanej daty (chromium.org). To najgorszy możliwy stan dla architekta: nie można na nim polegać, a jednocześnie skutecznie maskuje błędy konfiguracji podczas testów.

Mechanizm maskowania jest prosty. Zespoły testują w krótkich cyklach i rzadko przekraczają dwie minuty między utworzeniem ciasteczka sesyjnego a pierwszym żądaniem cross-site. W środowisku produkcyjnym te same przepływy trwają dłużej, bo wymagają interakcji użytkownika: federacyjne logowanie OpenID Connect, przekierowanie do bramki płatniczej, wieloetapowa weryfikacja 3-D Secure. Po upływie 120 sekund Chromium przestaje stosować wyjątek, kolejne żądanie POST przychodzi bez ciasteczek uwierzytelniających i serwer aplikacyjny odrzuca transakcję.

Aby wykryć te punkty awarii przed wdrożeniem, należy wymusić w środowisku testowym docelowe zachowanie przeglądarki (chromium.org):

  • --enable-features=SameSiteDefaultChecksMethodRigorously — całkowicie wyłącza wyjątek Lax+POST i wymusza rygorystyczne sprawdzanie reguł Lax dla wszystkich ciasteczek. To symulacja stanu po usunięciu mechanizmu.
  • --enable-features=ShortLaxAllowUnsafeThreshold — obniża próg z 2 minut do 10 sekund. Przeznaczone do testów automatycznych, gdzie odczekiwanie pełnych dwóch minut jest niepraktyczne.

Obie flagi są narzędziami diagnostycznymi, nie konfiguracją produkcyjną. Właściwym rozwiązaniem nie jest dostrajanie progu, tylko jawne zadeklarowanie SameSite na każdym emitowanym ciasteczku.

Kompatybilność wsteczna: kontekst historyczny, nie rekomendacja wdrożeniowa

W dokumentacji z lat 2019–2021 dominuje wątek wykrywania przeglądarek niekompatybilnych z wartością SameSite=None. Problem był realny: wczesny szkic standardu z 2016 roku nakazywał traktować nieznaną wartość atrybutu SameSite jako Strict. Klienty implementujące tamten szkic — Chrome w wersjach 51–66, Safari na iOS 12 i macOS 10.14 Mojave, część przeglądarek opartych na starym Chromium — po otrzymaniu SameSite=None blokowały ciasteczko również w nawigacji najwyższego poziomu, co skutkowało całkowitą utratą sesji.

Standardową odpowiedzią była logika warunkowa na serwerze: wykryj niekompatybilny User-Agent i pomiń atrybut SameSite w całości (w ASP.NET Core: SameSiteMode.Unspecified, o wartości -1, dostępne od .NET Core 3.1), pozwalając starszej przeglądarce zastosować jej domyślne, liberalne zachowanie.

W 2026 roku nie jest to już rekomendacja wdrożeniowa. iOS 12 pochodzi z 2018 roku, Chrome 66 z kwietnia 2018. Udział tego ruchu jest w większości systemów pomijalny, a utrzymywanie sniffingu User-Agenta ma własny koszt: to kod, który trzeba testować, który zawodzi przy nowych ciągach UA i który stoi w sprzeczności z kierunkiem redukcji User-Agenta w Chromium. Ten fragment należy traktować jako wyjaśnienie, skąd wzięło się takie middleware w istniejących systemach — i jako kandydata do usunięcia podczas najbliższego audytu, a nie do wdrożenia w nowym projekcie.

Niezmiennie obowiązuje natomiast reguła twarda: przeglądarki odrzucą ciasteczko SameSite=None bez flagi Secure.

CHIPS: partycjonowanie jako właściwa odpowiedź na potrzeby cross-site

Jeżeli aplikacja ma uzasadnioną potrzebę utrzymania stanu w kontekście cross-site — osadzony widget czatu, panel osadzony w iframe, sesja dla zasobów z subdomeny CDN — właściwym mechanizmem w 2026 roku nie jest samo SameSite=None, lecz CHIPS (Cookies Having Independent Partitioned State) i atrybut Partitioned (privacysandbox.google.com, developer.mozilla.org).

Ciasteczko oznaczone jako Partitioned jest kluczowane podwójnie: przez origin, który je ustawił, oraz przez witrynę najwyższego poziomu, w której kontekście zostało utworzone. Oznacza to osobny „słoik" ciasteczek dla każdej witryny osadzającej. Ten sam widget osadzony na sklep-a.example i sklep-b.example otrzyma dwa całkowicie odseparowane ciasteczka, bez możliwości korelacji użytkownika między witrynami — co jest dokładnie tym, przed czym broniły się mechanizmy blokujące third-party cookies.

Wymagania praktyczne:

  • Ciasteczko Partitioned musi mieć flagę Secure.
  • Zalecane, choć nie wymagane, jest połączenie z prefiksem __Host-, co domyka izolację po stronie hosta.
  • Partitioned stosuje się łącznie z SameSite=None, nie zamiast niego — partycjonowanie określa, do którego słoika trafia ciasteczko, a nie czy w ogóle zostanie wysłane w kontekście cross-site.

Przykładowy nagłówek:

Set-Cookie: __Host-widget_session=abc123; Secure; Path=/; SameSite=None; Partitioned;

Wsparcie jest asymetryczne, ale w korzystnym kierunku. Chromium implementuje CHIPS w pełni. Firefox partycjonuje ciasteczka third-party domyślnie w ramach Total Cookie Protection, więc atrybut jest tam w dużej mierze zgodny z zachowaniem już obowiązującym. Safari partycjonuje lub blokuje niezależnie od deklaracji. Deklaracja Partitioned jest zatem bezpieczna do wdrożenia: w najgorszym razie jest zbędna, a nie szkodliwa.

Prefiksy __Secure- i __Host-: bezpieczeństwo wymuszane przez przeglądarkę

Atrybuty Secure i HttpOnly nie zapobiegają wstrzykiwaniu ciasteczek z niezabezpieczonych subdomen ani portów tego samego hosta. Wynika to z założenia leżącego u podstaw modelu: przeglądarka nie weryfikuje, czy atrybuty ciasteczka przesłanego w nagłówku Set-Cookie zostały zdefiniowane przez uprawniony serwer.

Praktyczne konsekwencje są trzy:

  • Usługa działająca na przejętej subdomenie rodzeństwa (foo.site.example) może nadpisać ciasteczko ustawione przez bar.site.example, deklarując po prostu Domain=site.example.
  • Aktywny napastnik sieciowy może sfałszować odpowiedź HTTP i wstrzyknąć ciasteczka do sesji prowadzonej po HTTPS.
  • Brak izolacji na poziomie portów sprawia, że usługi współdzielące host na różnych portach wzajemnie odczytują i modyfikują swój stan.

Prefiksy ciasteczek wprowadzają mechanizm bezpieczeństwa deklaratywnego: przeglądarka, rozpoznając prefiks w nazwie ciasteczka (dopasowanie nazwy prefiksu jest niewrażliwe na wielkość liter), przeprowadza walidację przed zapisaniem i odrzuca ciasteczko niespełniające kryteriów.

  • __Secure- — ciasteczko zostanie zaakceptowane wyłącznie wtedy, gdy nagłówek Set-Cookie nadszedł połączeniem HTTPS i zawiera atrybut Secure.
  • __Host- — oprócz powyższych wymogów ciasteczko nie może zawierać atrybutu Domain (co blokuje odczyt i nadpisanie przez subdomeny, wiążąc je z konkretnym hostem) oraz musi mieć Path=/.
Atrybut / wymaganie walidacyjneCiasteczko standardowePrefiks __Secure-Prefiks __Host-
Wymaga atrybutu SecureOpcjonalnieWymaganeWymagane
Wymaga kanału HTTPSOpcjonalnieWymaganeWymagane
Dozwolony atrybut DomainTakTakNie (zabroniony)
Dozwolony atrybut PathDowolnyDowolnyWyłącznie /
Odporność na nadpisanie z subdomenyBrakBrakPełna (izolacja hosta)

Prefiksy nie rozwiązują natomiast problemu izolacji po porcie i schemacie__Host- wiąże ciasteczko z hostem, nie z pełnym originem. Tym wątkiem zajmuje się osobna propozycja Origin-Bound Cookies, opublikowana jako Internet-Draft w październiku 2025 i prototypowana w Chromium (ietf.org). Zakłada ona wiązanie ciasteczek również ze schematem i portem, przy czym atrybut Domain ma pozostać mechanizmem rozluźniającym dopasowanie portu. Dane telemetryczne Chromium wskazują, że dotyczy to marginalnego odsetka ruchu (rzędu 0,39% ciasteczek przesyłanych między schematami i 0,09% między portami), więc ryzyko wdrożeniowe jest niskie — ale to wciąż propozycja, nie obowiązujące zachowanie.

Limity rozmiaru, liczby i czasu życia

Projekt specyfikacji porządkuje limity, które wcześniej były wyłącznie konwencją implementacyjną. Trzy z nich mają bezpośrednie znaczenie architektoniczne.

Maksymalny czas życia: 400 dni. Przeglądarki ograniczają wartość wynikającą z Expires i Max-Age do 400 dni (34 560 000 sekund). Próba ustawienia dłuższego okresu skutkuje cichym skróceniem do tej wartości. Preferowany jest atrybut Max-Age, jako mniej podatny na błędy synchronizacji zegara i nadrzędny wobec Expires, gdy podano oba.

Ten limit nie jest jednak najostrzejszym ograniczeniem, z jakim zetknie się aplikacja. Safari w ramach ITP tnie żywotność ciasteczek ustawianych z poziomu JavaScriptu (document.cookie) do 7 dni, a dla domen sklasyfikowanych jako trackery nawet do 24 godzin (snowplow.io). Ciasteczka ustawiane nagłówkiem Set-Cookie przez serwer first-party temu limitowi nie podlegają i mogą żyć pełne 400 dni. Wynika stąd konkretna reguła projektowa: ciasteczka sesyjne i stan długoterminowy ustawiaj po stronie serwera nagłówkiem Set-Cookie, nigdy skryptem po stronie klienta. Projekt, który opiera retencję na document.cookie, traci sesje użytkowników Safari po tygodniu, niezależnie od tego, co deklaruje w Max-Age.

Limity rozmiaru. Suma długości nazwy ciasteczka i jego wartości nie może przekraczać 4096 oktetów — przekroczenie skutkuje odrzuceniem i zignorowaniem ciasteczka. Wartość pojedynczego atrybutu (Domain, Path) jest ograniczona do 1024 oktetów.

Limity liczbowe. Specyfikacja gwarantuje utrzymanie minimum 50 ciasteczek na domenę oraz 3000 ciasteczek łącznie. To wartości minimalne, nie docelowe — architektura, która zbliża się do tych progów, przekracza granicę, za którą ciasteczka przestają być właściwym magazynem stanu.

Rekomendacje wdrożeniowe

1. Audyt emitowanych ciasteczek. Punktem wyjścia jest inwentarz: każde ciasteczko opuszczające system, z jawnie określonymi atrybutami SameSite, Secure, HttpOnly, Domain, Path i czasem życia. Ciasteczko bez jawnej deklaracji SameSite jest defektem konfiguracji, nawet jeśli obecnie działa dzięki wyjątkowi Lax+POST.

2. Wzorzec dwóch ciasteczek sesyjnych. Opieranie całego uwierzytelniania na jednym ciasteczku SameSite=Strict powoduje, że użytkownik wchodzący z linku w wiadomości e-mail trafia na ekran wylogowania — mimo aktywnej sesji. Rozwiązaniem jest podział:

  • Ciasteczko odczytuSameSite=Lax, wystarczające do prezentacji danych po wejściu z zewnętrznego źródła.
  • Ciasteczko zapisuSameSite=Strict, wymagane przy każdej operacji modyfikującej stan. Eliminuje CSRF i wymusza wykonanie operacji w bezpiecznym kontekście.

Warto przy tym pamiętać, że SameSite jest zabezpieczeniem warstwowym, nie jedynym: ze względu na rozjazd domyślnych zachowań między przeglądarkami opisany wyżej, ochrona przed CSRF nie może opierać się wyłącznie na nim. Weryfikacja nagłówków Sec-Fetch-Site / Origin lub tokeny anty-CSRF pozostają konieczne.

3. Fazowa migracja na prefiksy. Przejście na __Host- lub __Secure- w działającym systemie produkcyjnym wymaga etapowania, ponieważ zmiana nazwy ciasteczka unieważnia wszystkie aktywne sesje:

  • Faza 1 (dual cookie) — serwer emituje równolegle ciasteczko tradycyjne i jego prefiksowany odpowiednik (session_id oraz __Host-session_id).
  • Faza 2 (grace period) — aplikacja odczytuje w pierwszej kolejności wersję prefiksowaną, a w razie jej braku sięga po legacy i natychmiast migruje. Faza musi trwać dłużej niż najdłuższa dopuszczalna sesja.
  • Faza 3 (cutover) — serwer przestaje obsługiwać ciasteczka bez prefiksu.

4. Weryfikacja w warunkach docelowych. Testy regresyjne przepływów cross-site należy uruchamiać z flagą SameSiteDefaultChecksMethodRigorously, a nie w domyślnej konfiguracji przeglądarki. Osobno wymaga sprawdzenia ścieżka w Safari — jest to jedyna przeglądarka, w której poprawnie skonfigurowane SameSite=None; Secure może nadal nie zadziałać.

5. Dla scenariuszy osadzonych — Partitioned zamiast walki z blokadami. Jeśli przepływ wymaga stanu w iframe lub widgecie, CHIPS jest jedynym mechanizmem, który ma szansę działać we wszystkich trzech silnikach. Alternatywą dla logowania federacyjnego jest FedCM, który przetrwał wygaszenie Privacy Sandbox właśnie jako docelowe zastąpienie ciasteczek third-party w tym scenariuszu.