LW IT Solutions
« Blog Overview /Data Privacy/Tutorials / Cookieless Tracking Fallbacks: Syntetyczne zszywanie sesji po...
This post in other languages:

Cookieless Tracking Fallbacks: Syntetyczne zszywanie sesji po stronie serwera

Cookieless Tracking Fallbacks: Syntetyczne zszywanie sesji po stronie serwera
Spis treści
  1. Przegląd architektury: Dylemat odrzucenia ciasteczek w analityce internetowej
  2. Instrukcja wdrożenia krok po kroku
  3. Podsumowanie i mierzalna wartość dodana
  4. Pytania i odpowiedzi
  5. Źródła

Przegląd architektury: Dylemat odrzucenia ciasteczek w analityce internetowej

We współczesnej analityce internetowej banery zgód (CMP) powodują powstawanie znaczących luk pomiarowych. Gdy użytkownicy odrzucają ciasteczka śledzące lub korzystają z przeglądarek wymuszających agresywne mechanizmy Intelligent Tracking Prevention (ITP), tradycyjne identyfikatory po stronie klienta, takie jak _ga, _gid czy identyfikatory odwiedzających w Matomo, są blokowane lub usuwane. W konsekwencji każde wyświetlenie strony przez użytkownika bez zgody jest rejestrowane jako pojedyncza, izolowana sesja, co czyni statystyczne analizy ścieżek konwersji, modele atrybucji oraz podróże użytkownika całkowicie nieprzydatnymi.

W celu przywrócenia ciągłości analitycznej bez naruszania przepisów RODO, dyrektywy ePrivacy oraz regulacji krajowych, możliwe jest wdrożenie syntetycznego zszywania sesji po stronie serwera (Server-Side Synthetic Session Stitching). W odróżnieniu od trwałego śledzenia cross-site lub fingerprintingu, syntetyczne zszywanie działa wyłącznie w warstwie serwera proxy lub przetwarzania brzegowego (np. Server-Side GTM, Cloudflare Workers lub własne punkty końcowe PHP/Node.js). Poprzez obliczanie ulotnego, rotowanego codziennie skrótu kryptograficznego z nieutrwalanych atrybutów sieciowych – takich jak skrócona podsieć IP, User-Agent oraz generowany na serwerze dzienny salt – sesje mogą być precyzyjnie odtwarzane dla celów statystycznych bez zapisywania jakichkolwiek danych na urządzeniu końcowym.

Tworzenie syntetycznego identyfikatora sesji ze skróconego IP, User-Agenta, Accept-Language i codziennie rotowanej soli przez SHA-256
Droga syntetycznego identyfikatora: skrócone IP, dwa stabilne nagłówki i dzienna sól są haszowane do ID sesji. W przeglądarce nic nie jest zapisywane — a po rotacji soli identyfikatora z poprzedniego dnia nie da się odtworzyć.

Instrukcja wdrożenia krok po kroku

Krok 1: Podstawy generowania ulotnych, zgodnych z prywatnością skrótów (Hash)

Utworzenie zgodnego z RODO syntetycznego identyfikatora sesji wymaga zastosowania trzech fundamentów architektonicznych:

  1. Skracanie podsieci IP: Pełny adres IP nigdy nie może być poddawany bezpośredniemu haszowaniu, gdyż nadal stanowi daną osobową. Adresy IPv4 muszą być maskowane do podsieci /24 (np. 192.0.2.0), a adresy IPv6 do podsieci /48.
  2. Dynamiczny dzienny Salt: Kryptograficzny, losowy ciąg (salt) musi być generowany po stronie serwera i automatycznie rotowany najpóźniej o północy (UTC). Gwarantuje to, że wszystkie skróty wygasają bezpowrotnie najpóźniej po 24 godzinach, co uniemożliwia wielodniowe profilowanie użytkowników.
  3. Jednokierunkowe szyfrowanie: Połączone atrybuty sieciowe muszą być przetwarzane za pomocą nieodwracalnego algorytmu haszującego, takiego jak SHA-256.

Krok 2: Projektowanie generatora skrótów w Edge Worker / Server-Side GTM

Poniższa implementacja produkcyjna w języku JavaScript pokazuje, w jaki sposób wygenerować zgodny z prywatnością syntetyczny identyfikator sesji jako zmienną niestandardową w Server-Side GTM lub w skrypcie Cloudflare Edge Worker bez wysyłania nagłówków HTTP Set-Cookie:

/**
 * Generator syntetycznych skrótów sesji zgodny z prywatnością
 * Cel: Server-Side GTM / Edge Workers
 */
const crypto = require('crypto');

function getSyntheticSessionId(requestHeaders, clientIp, dailySalt) {
    // 1. Anonimizacja adresu IP (skrócenie IPv4 do /24 lub IPv6 do /48)
    let maskedIp = '0.0.0.0';
    if (clientIp.includes('.')) {
        maskedIp = clientIp.split('.').slice(0, 3).join('.') + '.0';
    } else if (clientIp.includes(':')) {
        maskedIp = clientIp.split(':').slice(0, 3).join(':') + '::';
    }

    // 2. Ekstrakcja stabilnych nagłówków środowiska przeglądarki
    const userAgent = requestHeaders['user-agent'] || 'unknown-ua';
    const acceptLanguage = requestHeaders['accept-language'] || 'unknown-lang';

    // 3. Budowa ładunku wejściowego z rotowanym codziennie saltem
    const rawPayload = `${maskedIp}|${userAgent}|${acceptLanguage}|${dailySalt}`;

    // 4. Obliczenie skrótu SHA-256
    const syntheticHash = crypto
        .createHash('sha256')
        .update(rawPayload)
        .digest('hex');

    // Zwrócenie skróconego, 16-znakowego ulotnego ID
    return 'syn_' + syntheticHash.substring(0, 16);
}

Krok 3: Integracja w kolektorze PHP WordPressa (functions.php)

W infrastrukturach oparłych na WordPressie v7.0.2, które wykorzystują własne punkty końcowe REST API do gromadzenia danych, obliczanie syntetycznej sesji da się zintegrować w pliku functions.php aktywnego motywu:

/**
 * Narzędzie generowania syntetycznych skrótów sesji w PHP
 * Cel: WordPress v7.0.2
 */
function lw_generate_synthetic_session_id() {
    $client_ip = $_SERVER['REMOTE_ADDR'] ?? '127.0.0.1';
    
    // Maskowanie IPv4 do /24
    if ( strpos( $client_ip, '.' ) !== false ) {
        $ip_parts  = explode( '.', $client_ip );
        $ip_parts[3] = '0';
        $masked_ip = implode( '.', $ip_parts );
    } else {
        // Maskowanie IPv6 do /48
        $ip_parts  = explode( ':', $client_ip );
        $masked_ip = implode( ':', array_slice( $ip_parts, 0, 3 ) ) . '::';
    }

    $user_agent      = ( $_SERVER['HTTP_USER_AGENT'] ?? '' ) ?: 'unknown-ua';
    $accept_language = ( $_SERVER['HTTP_ACCEPT_LANGUAGE'] ?? '' ) ?: 'unknown-lang';
    
    // Pobranie lub utworzenie rotowanego codziennie salta z tabeli opcji
    $daily_salt = get_transient( 'lw_daily_privacy_salt' );
    if ( ! $daily_salt ) {
        $daily_salt = wp_generate_password( 32, true, true );
        // Wygaśnięcie salta o północy UTC (sekundy pozostałe do końca doby UTC)
        set_transient( 'lw_daily_privacy_salt', $daily_salt, DAY_IN_SECONDS - ( time() % DAY_IN_SECONDS ) );
    }

    $raw_payload = $masked_ip . '|' . $user_agent . '|' . $accept_language . '|' . $daily_salt;
    $sha256_hash = hash( 'sha256', $raw_payload );

    return 'syn_' . substr( $sha256_hash, 0, 16 );
}

Krok 4: Mapowanie syntetycznych ID na platformy analityczne

Po wygenerowaniu, ulotny identyfikator sesji musi zostać przekazany do docelowej platformy analitycznej zamiast brakującego ciasteczka:

  • Google Analytics 4 (GA4): Mapowanie wartości na parametr client_id w Server-Side GTM przy jednoczesnym wymuszeniu parametru non_personalized_ads=1 oraz usunięciu nagłówków IP.
  • Matomo / Piwik PRO: Przypisanie skrótu do właściwości identyfikatora odwiedzającego po stronie serwera (_id lub cid) i włączenie trybu bezciasteczkowego (Cookieless Mode).
  • Eksporty surowych danych do BigQuery: Zapisywanie wartości w osobnej kolumnie (np. synthetic_session_id), co umożliwia modelowanie zapytań SQL oddzielających sesje ciasteczkowe od sesji zszywanych na serwerze.

Krok 5: Kontrola jakości i audyt zgodności

W celu weryfikacji poprawności i pełnej zgodności prawnej mechanizmu syntetycznego zszywania sesji, należy przeprowadzić trzystopniową procedurę testową:

  1. Weryfikacja nagłówków sieciowych: Kontrola odpowiedzi serwera w narzędziach deweloperskich przeglądarki (F12) potwierdzająca, że przy braku zgody nie są wysyłane żadne nagłówki HTTP Set-Cookie.
  2. Testy stabilności i kolizji: Symulacja zapytań z identycznych zakresów podsieci i potwierdzenie, że różne nagłówki User-Agent generują osobne skróty, natomiast kolejne wyświetlenia z tej samej przeglądarki zachowują ten sam identyfikator sesji.
  3. Audyt wygasania salta o północy: Wymuszenie wygaśnięcia dziennego salta i weryfikacja, czy wszystkie nowo generowane identyfikatory natychmiast ulegają zmianie, co dowodzi braku możliwości wielodniowego śledzenia.

Podsumowanie i mierzalna wartość dodana

Co da się osiągnąć dzięki instrukcji: Całkowite zastąpienie pofragmentowanych, pojedynczych odsłon w ruchu bez zgody na ciasteczka przez ulotny, serwerowy model rekonstrukcji sesji, działający bez zapisywania ciasteczek i bez przetwarzania pełnych adresów IP.

Wynikająca z tego wartość dodana:

  • Przywrócenie analityki ścieżek konwersji i lejków: Statystyczne współczynniki konwersji, wskaźniki odrzuceń oraz wielokrokowe ścieżki nawigacji pozostają w przybliżeniu mierzalne także dla wizyt bez zgody na ciasteczka.
  • Mniejsza ingerencja niż śledzenie ciasteczkami, ale bez zwolnienia z RODO: Na urządzeniu użytkownika nic nie jest zapisywane. Skrót z podsieci i nagłówków przeglądarki pozostaje jednak mimo dziennego salta daną pseudonimizowaną, a więc nadal osobową (motyw 26 RODO); jej przetwarzanie wymaga podstawy prawnej, a dopuszczalność bez zgody wymaga oceny w każdym przypadku z osobna.
  • Brak kontaminacji profili reklamowych: Dzięki codziennemu wygasaniu identyfikatorów statystyczna dokładność raportów jest utrzymana bez wspierania inwazyjnego retargetingu i profilowania użytkowników.

Pytania i odpowiedzi

Na ile niezawodnie skrót rozróżnia odwiedzających, którzy dzielą jedną sieć?

Tylko na tyle, na ile różnią się dane wejściowe. Skrót łączy wszystkie żądania pochodzące z tej samej podsieci /24 i niosące ten sam nagłówek User-Agent, a także ten sam Accept-Language. W sieci firmowej, w hotelowym Wi-Fi albo za NAT-em operatora komórkowego (carrier-grade NAT) wiele osób dzieli jeden adres, a popularne urządzenia z aktualną przeglądarką często wysyłają identyczne ciągi User-Agent. Takie wizyty zlewają się w jedną syntetyczną sesję. Chromium dodatkowo skrócił ciąg User-Agent, więc rozróżnia on mniej niż dawniej.

Z kolei pojedyncza wizyta rozpada się, gdy dane wejściowe zmieniają się po drodze: telefon przechodzący z Wi-Fi do sieci komórkowej dostaje inną podsieć, a aktualizacja przeglądarki zmienia User-Agent. W obu przypadkach w środku wizyty powstaje nowy identyfikator.

Odtworzone sesje są więc oszacowaniem obarczonym błędami w obu kierunkach. Osobna kolumna w BigQuery, proponowana w artykule, pozwala analizować ten udział oddzielnie, na przykład zestawiać współczynniki konwersji sesji z ciasteczkiem i bez niego, zamiast je mieszać.

Dlaczego dziennego salta nie należy zapisywać ani umieszczać w kopiach zapasowych?

Bo tylko on chroni skróty przed odwróceniem. Przestrzeń możliwych danych wejściowych jest mała: istnieje zaledwie około 16,8 miliona podsieci IPv4 o rozmiarze /24, a popularne ciągi User-Agent da się wyliczyć, więc przy znanym salcie każdy identyfikator z danego dnia da się przypisać do podsieci i przeglądarki przez sprawdzanie kolejnych kombinacji. W przykładzie w PHP salt leży w bazie danych jako transient, a jeśli nie działa trwała pamięć podręczna obiektów, w tabeli opcji, a więc w każdej kopii zapasowej bazy, gdzie przetrwa dłużej niż swój dzień.

Lukas Wójcik

Lukas Wójcik

Systems architect and technology enthusiast specializing in scalable tracking solutions, GMP Stack (GA4 & GTM), and robust backend architectures. Advocate for clean code and privacy-first design.

Get in Touch

Briefly describe your project or inquiry for a tailored response. This site is protected by reCAPTCHA.

Napisanie komentarza

Obserwacje z innych wdrożeń, zastrzeżenia i pytania są tu mile widziane.

Adres e-mail nie jest publikowany. Pola obowiązkowe oznaczono gwiazdką.

ALL ARTICLES & CATEGORIES

CCTV

Śledź tę kategorię przez RSS

Cloud & AI

Śledź tę kategorię przez RSS

Data Privacy

Wszystkie artykuły w tej kategorii (18) Śledź tę kategorię przez RSS

Digital Analytics

Wszystkie artykuły w tej kategorii (55) Śledź tę kategorię przez RSS

Digital Marketing

Wszystkie artykuły w tej kategorii (37) Śledź tę kategorię przez RSS

IT & Networks

Wszystkie artykuły w tej kategorii (17) Śledź tę kategorię przez RSS

Music Production

Wszystkie artykuły w tej kategorii (14) Śledź tę kategorię przez RSS

Raspberry Pi

Śledź tę kategorię przez RSS

Smart Home

Wszystkie artykuły w tej kategorii (18) Śledź tę kategorię przez RSS

Tworzenie stron internetowych

Wszystkie artykuły w tej kategorii (11) Śledź tę kategorię przez RSS

Wtyczki i triki WordPress

Śledź tę kategorię przez RSS