Bezpieczeństwo ciasteczek
Ciasteczka (cookies) przechowują dane sesji, tokeny uwierzytelnienia, preferencje użytkownika i identyfikatory śledzenia. Niepoprawnie skonfigurowane ciasteczko to jeden z najczęstszych wektorów ataków na aplikacje webowe — przechwycenie sesji, kradzież tokenu przez XSS czy fałszowanie żądań cross-site (CSRF).
Atrybuty bezpieczeństwa ciasteczek to flagi dodawane do nagłówka Set-Cookie, które instruują przeglądarkę jak ma się zachować z danym ciasteczkiem. W przeciwieństwie do nagłówków bezpieczeństwa HTTP, nie jest to osobny nagłówek — to część deklaracji każdego ciasteczka.
Przegląd atrybutów
| Atrybut | Co robi |
|---|---|
Secure | Ciasteczko wysyłane tylko przez HTTPS |
HttpOnly | Ciasteczko niedostępne dla JavaScript |
SameSite=Strict | Ciasteczko wysyłane tylko przy żądaniach z tej samej domeny |
SameSite=Lax | Ciasteczko wysyłane przy nawigacji do strony, blokuje POST cross-site |
SameSite=None | Ciasteczko wysyłane zawsze (wymaga Secure) |
Max-Age | Czas ważności w sekundach |
Expires | Data wygaśnięcia |
Atrybut Secure
Oznacza, że ciasteczko może być wysyłane wyłącznie przez szyfrowane połączenie HTTPS. Przeglądarka nie wyśle go przy żądaniach HTTP.
Chroni przed przechwyceniem ciasteczka przez atakującego podsłuchującego ruch sieciowy (man-in-the-middle), np. w niezabezpieczonych sieciach Wi-Fi.
Set-Cookie: session_id=abc123; Secure⚠️ Secure nie szyfruje treści ciasteczka
Atrybut Secure zapewnia tylko, że ciasteczko jest przesyłane przez zaszyfrowany kanał. Wartość ciasteczka nadal jest widoczna w przeglądarce (DevTools → Application → Cookies). Nie przechowuj wrażliwych danych wprost w ciasteczkach — używaj ich jako identyfikatorów sesji odwołujących się do danych po stronie serwera.
Atrybut HttpOnly
Uniemożliwia dostęp do ciasteczka przez JavaScript — document.cookie nie zwróci jego wartości, żaden skrypt nie może go odczytać ani zmodyfikować.
Chroni przed atakami XSS (Cross-Site Scripting), gdzie złośliwy skrypt wstrzyknięty w stronę próbuje wykraść ciasteczka sesji.
Set-Cookie: session_id=abc123; HttpOnly💡 HttpOnly dla ciasteczek sesji
Ciasteczka przechowujące identyfikatory sesji, tokeny uwierzytelnienia i CSRF tokeny powinny zawsze mieć atrybut HttpOnly. JavaScript nie musi znać wartości sesji — ta informacja należy do serwera.
Atrybut SameSite
Kontroluje, czy ciasteczko jest wysyłane w żądaniach cross-site — czyli gdy żądanie pochodzi z innej domeny niż ta, dla której ciasteczko zostało ustawione. Chroni przed atakami CSRF (Cross-Site Request Forgery).
Wartości
Strict— ciasteczko wysyłane tylko gdy użytkownik jest już na twojej stronie. Żądania z zewnętrznych linków (np. kliknięcie linku w e-mailu) nie będą zawierać tego ciasteczka.Lax— ciasteczko wysyłane przy nawigacji do strony (kliknięcie linku, wejście przez pasek adresu), ale nie przy żądaniach POST z innych domen. Dobry kompromis między bezpieczeństwem a użytecznością.None— ciasteczko wysyłane zawsze, bez ograniczeń. Wymaga jednoczesnego atrybutuSecure.
Set-Cookie: session_id=abc123; SameSite=Lax; Secure
Set-Cookie: embed_token=xyz; SameSite=None; SecureINFO
Od 2020 roku większość przeglądarek traktuje ciasteczka bez atrybutu SameSite jak SameSite=Lax. Starsze przeglądarki mogą zachowywać się inaczej — jawne ustawienie atrybutu eliminuje to ryzyko.
Czas ważności: Max-Age i Expires
Ciasteczka bez atrybutu Max-Age ani Expires to ciasteczka sesyjne — wygasają gdy użytkownik zamknie przeglądarkę. Ciasteczka z czasem ważności są zapisywane na dysku i przeżywają restart przeglądarki.
Max-Age— czas w sekundach od momentu ustawienia ciasteczkaExpires— konkretna data wygaśnięcia w formacie HTTP
Set-Cookie: pref=dark; Max-Age=2592000; Secure; HttpOnly
Set-Cookie: remember_me=token; Expires=Thu, 01 Jan 2026 00:00:00 GMT; Secure; HttpOnlyKrótki czas ważności ogranicza okno nadużycia w przypadku przechwycenia ciasteczka. Ciasteczka sesyjne są bezpieczniejsze niż długowieczne — rozważ czy trwałość jest naprawdę potrzebna.
Prefiksy bezpieczeństwa: __Secure- i __Host-
Prefiksy w nazwie ciasteczka to dodatkowy mechanizm wymuszania określonych atrybutów — przeglądarka odmówi ustawienia ciasteczka jeśli warunki nie są spełnione.
__Secure-— wymaga atrybutuSecurei wysłania przez HTTPS__Host-— wymagaSecure, braku atrybutuDomainiPath=/(ciasteczko przypisane wyłącznie do hosta, nie do subdomeny)
Set-Cookie: __Secure-session=abc123; Secure; HttpOnly; SameSite=Lax
Set-Cookie: __Host-token=xyz789; Secure; HttpOnly; SameSite=Strict; Path=/💡 Kiedy używać prefiksów
Prefiksy są szczególnie wartościowe dla ciasteczek uwierzytelniających — eliminują możliwość podmienienia ciasteczka przez subdomenę lub przez HTTP. Używaj __Host- dla tokenów sesji gdy nie potrzebujesz współdzielenia ciasteczka między subdomenami.
Pełny przykład
Zalecana konfiguracja dla ciasteczka sesji:
Set-Cookie: __Host-session=abc123; Secure; HttpOnly; SameSite=Lax; Path=/; Max-Age=3600Jak ustawić atrybuty w PHP i WordPress
PHP
setcookie(
'__Host-session',
$value,
[
'expires' => time() + 3600,
'path' => '/',
'secure' => true,
'httponly' => true,
'samesite' => 'Lax',
]
);WordPress — filtr wp_cookie_params
Dostępny od WordPress 6.2, pozwala modyfikować atrybuty ciasteczek logowania:
add_filter( 'wp_cookie_params', function( $params ) {
$params['samesite'] = 'Lax';
$params['secure'] = true;
return $params;
} );Kod dodaj do pliku functions.php aktywnego motywu lub przez wtyczkę do zarządzania snippetami.
WordPress — domyślne ciasteczka sesji
WordPress domyślnie ustawia HttpOnly dla ciasteczek uwierzytelniających (wordpress_logged_in_*, wordpress_sec_*). Atrybut Secure jest ustawiany automatycznie gdy strona działa przez HTTPS. Aby mieć pewność, dodaj do wp-config.php:
define( 'FORCE_SSL_ADMIN', true );⚠️ Wymagane HTTPS
Atrybuty Secure i __Host- działają tylko przez HTTPS. Na stronie bez certyfikatu SSL przeglądarka ciche odrzuci takie ciasteczka. Certyfikat SSL na hostingu Joton możesz aktywować bezpłatnie przez Let's Encrypt — szczegóły w panelu administracyjnym.
Jak sprawdzić atrybuty ciasteczek
Narzędzia deweloperskie przeglądarki
W Chrome lub Firefox: DevTools → zakładka Application (Chrome) lub Storage (Firefox) → Cookies → wybierz domenę. Kolumny Secure, HttpOnly, SameSite pokazują bieżące atrybuty każdego ciasteczka.
Terminal
curl -sI https://twojadomena.pl | grep -i set-cookieNajczęstsze problemy
Ciasteczko z Secure nie jest ustawiane na lokalnym środowisku
Secure wymaga HTTPS. Na localhost bez certyfikatu SSL ciasteczko z tym atrybutem zostanie cicho odrzucone przez przeglądarkę. Podczas developmentu albo pomiń atrybut Secure lokalnie, albo użyj mkcert do utworzenia lokalnego certyfikatu.
WordPress traci sesję po ustawieniu SameSite=Strict
Logowanie przez zewnętrzne formularze lub przekierowania OAuth mogą przestać działać — żądanie POST z zewnętrznej domeny nie przeniesie ciasteczka sesji. Zmień na SameSite=Lax.
Wtyczki płatności przestały działać po zmianie atrybutów
Bramki płatności często wymagają ciasteczek cross-site dla iframe'ów z formularzem płatności. Dla takich ciasteczek ustaw SameSite=None; Secure. Nie modyfikuj bezpośrednio ciasteczek bramek płatności — zmieniaj tylko własne ciasteczka sesji.
Prefiks __Host- nie działa
Ciasteczko z prefiksem __Host- musi spełniać wszystkie cztery warunki jednocześnie: atrybut Secure, brak atrybutu Domain, Path=/ i wysyłanie przez HTTPS. Brak któregokolwiek z nich powoduje ciche odrzucenie ciasteczka przez przeglądarkę bez żadnego komunikatu błędu.
Przydatne linki
- Nagłówki bezpieczeństwa HTTP — CSP, HSTS, X-Frame-Options i inne
- Bezpieczeństwo WordPress — kompleksowy hardening instalacji WordPress
- Certyfikaty SSL — aktywacja Let's Encrypt w panelu Joton
- MDN: Set-Cookie — pełna dokumentacja nagłówka Set-Cookie