Ivan Centamori

EN IT


L'arte (e la scienza) del Browser Fingerprinting

Vi siete mai chiesti come faccia internet a sapere chi siete anche dopo aver svuotato la cache, cancellato i cookie e attivato la famigerata "modalità in incognito"?

Da sviluppatori, passiamo le nostre giornate a far dialogare client e server. Eppure, spesso diamo per scontati i meccanismi fondamentali che permettono a questa conversazione di avere un filo logico. Per decenni ci siamo affidati ai cookie per ricordare se un utente avesse fatto il login o cosa avesse messo nel carrello. Ma cosa succede quando i cookie vengono bloccati? Come fanno le aziende di tracciamento pubblicitario, o i sofisticati sistemi antifrode delle banche, a riconoscere un dispositivo che fa di tutto per nascondersi?

La risposta risiede nei metadati e nelle minuscole, invisibili differenze dell'hardware e del software che utilizziamo. In questo articolo esploreremo la storia del tracciamento, le leggi che lo governano e, soprattutto, come implementare un sistema di fingerprinting ibrido (Client + Server), dando un'occhiata approfondita a una libreria che ho scritto per l'ecosistema Laravel: centamiv/advanced-fingerprint.

Stateless vs Stateful

Prima di addentrarci nel fingerprinting, dobbiamo chiarire un concetto fondamentale dell'architettura del web che a volte viene dato per scontato. Sentiamo spesso dire che il web è un ambiente stateless, ma cosa significa esattamente in contrapposizione a stateful?

Immaginate il protocollo HTTP (quello che fa funzionare il web) come un interlocutore che soffre di una grave forma di amnesia a breve termine, una sorta di pesce rosso digitale. Ogni volta che il client effettua una nuova richiesta, il server ha completamente dimenticato la richiesta precedente.

Il trucco più famoso è il Cookie. Funziona come un cartellino con il nome (un identificativo univoco, come l'ID di sessione) che il server consegna al browser alla prima visita. Nelle richieste successive, il browser "indossa" questo cartellino allegandolo automaticamente alle richieste HTTP. In questo modo, il server legge il cartellino, guarda nel suo database e dice: "Ah, bentornato Mario, ecco la tua dashboard!".

Il fingerprinting entra in gioco quando questo cartellino viene strappato, rifiutato o falsificato.

Cos'è il fingerprinting?

Torniamo all'analogia di prima. Se il cookie è un cartellino con il nome, il Fingerprinting (o impronta digitale del dispositivo) è l'equivalente di un detective che vi osserva senza chiedervi i documenti.

Il detective non ha il vostro cartellino, ma prende appunti: "Questa persona è alta 1.80m, ha gli occhi verdi, un accento milanese, indossa scarpe da ginnastica rosse taglia 43 e ha un piccolo graffio sull'orologio". Presa singolarmente, nessuna di queste caratteristiche vi identifica in modo univoco (ci sono tante persone con gli occhi verdi). Ma la combinazione esatta di tutte queste variabili crea un profilo che, statisticamente, corrisponde quasi sicuramente solo a voi.

Nel mondo digitale, il fingerprinting è una tecnica di identificazione che non salva nulla sul dispositivo dell'utente. Interroga semplicemente il browser raccogliendo dozzine di parametri: "Che sistema operativo usi? Quanti core ha la tua CPU? Come renderizzi i font? Qual è il tuo fuso orario? Quali estensioni hai installato?".

Mettendo insieme questi piccoli indizi, li si fa passare attraverso un algoritmo di hashing (come SHA-256) per ottenere una stringa alfanumerica: la vostra Device Signature (cioè la firma del dispositivo).

La storia del tracciamento

Il web è stato protagonista di una vera e propria "corsa agli armamenti" tra chi voleva tracciare gli utenti (per fini analitici, pubblicitari o di sicurezza) e chi voleva proteggere la loro privacy. Questa evoluzione ci aiuta a capire perché le tecnologie attuali sono così complesse.

Tutto è iniziato nel 1994, quando Lou Montulli, un ingegnere di Netscape Communications, inventò il "Magic Cookie". L'obiettivo era nobile: permettere al neonato sito di e-commerce di ricordare il carrello della spesa creato dall'utente. Il meccanismo, come abbiamo visto, si basava sulla fiducia. Ma ben presto, le reti pubblicitarie capirono che potevano usare i Third-Party Cookies (cookie di terze parti). Inserendo un piccolo banner o un pixel invisibile su migliaia di siti diversi, un'azienda pubblicitaria poteva assegnarvi un cookie univoco e tracciare esattamente quali siti visitavate, costruendo un profilo incredibilmente dettagliato dei vostri interessi.

ETag e LSO (2005 - 2015)

Quando gli utenti più smaliziati iniziarono a rendersi conto della cosa, cominciarono a cancellare regolarmente i cookie. L'industria del tracking rispose con metodi più subdoli e aggressivi. Nacque il concetto di Evercookie (o zombie cookie): script progettati per nascondere identificatori in ogni angolo remoto e persistente del browser.

Oggi

Con l'arrivo dell'HTML5 e la morte di Flash (meno male), i browser moderni che hanno iniziato a prendere sul serio la privacy e il tracciamento è diventato molto più complesso. Apple ha introdotto in Safari l'ITP (Intelligent Tracking Prevention), Firefox ha rilasciato l'ETP (Enhanced Tracking Protection) e anche gli altri browser hanno deprecato i cookie di terze parti e stanno isolando la cache.

Oggi, non si può più salvare uno stato in modo affidabile senza il permesso esplicito dell'utente. È qui che il Browser Fingerprinting è diventato il re indiscusso. Poiché non si può più archiviare un ID, si deve "indovinare" l'identità calcolandola al volo ogni volta.

Implementare il fingerprinting

Per implementare un fingerprinting robusto che riconosca in maniera quasi univoca l'utente dobbiamo affidarci a molti metodi di deduzione. Queste sono divise in due categorie ben distinte, ognuna con i suoi pro e contro: Server-Side e Client-Side.

Server-Side fingerprinting

Questo approccio viene definito "passivo" perché il server non esegue alcun codice sul dispositivo dell'utente. Si limita a ispezionare le informazioni che il browser invia volontariamente e automaticamente nelle intestazioni (Headers) della richiesta HTTP.

Client-Side fingerprinting

Qui cominciamo a fare sul serio! Utilizzando script JavaScript inviati al browser, interroghiamo attivamente le API Web per estrarre informazioni profondamente legate all'hardware sottostante. Ad esempio:

Canvas fingerprinting

Il Canvas Fingerprinting sfrutta le minuscole imperfezioni e differenze architetturali nel modo in cui i diversi sistemi operativi e le diverse schede video (GPU) renderizzano la grafica bidimensionale.

Ma come funziona tecnicamente?

  1. Tramite JS, creiamo un elemento <canvas> di HTML5. Lo teniamo invisibile all'utente.
  2. Disegniamo una scena complessa: testo con font sovrapposti, emoji, curve di Bezier e gradienti di colore.
  3. Chiediamo al browser di esportare questo disegno sotto forma di array di pixel grezzi o immagine Base64 (tramite canvas.toDataURL()).

Perché funziona? Perché Windows usa una tecnologia chiamata ClearType per smussare i bordi dei font (anti-aliasing), mentre macOS usa il suo motore Core Graphics. Una scheda video dedicata NVIDIA calcolerà l'interpolazione dei colori di un gradiente in modo leggermente diverso rispetto a una modesta GPU integrata Intel. A occhio nudo, le due immagini sembrano identiche, ma a livello di singolo pixel (e quindi di Hash crittografico risultante) l'immagine generata dal PC "A" sarà diversa dall'immagine generata dal PC "B". Questo identificatore persiste anche se usate la modalità in incognito o svuotate la cache, perché l'hardware del vostro computer non cambia!

AudioContext Fingerprinting

Simile al Canvas, questa tecnica non disegna immagini, ma "suona" dell'audio invisibile. Si utilizza l'API Web Audio per generare un'onda sinusoidale, la si fa passare attraverso un compressore dinamico e vari filtri matematici, per poi analizzare il risultato. Poiché l'elaborazione dei calcoli in virgola mobile varia leggermente tra diverse architetture di CPU e schede audio, l'output genererà una firma univoca.

Ma tutto ciò è legale?

Arrivati a questo punto, molti sviluppatori cadono in una trappola logica pericolosa: "Non sto salvando nessun cookie, quindi il banner della privacy e il GDPR non mi riguardano". Assolutamente Falso.

In Europa, ci muoviamo sotto due grandi ombrelli normativi:

  1. La Direttiva ePrivacy (la "Cookie Law"): Questa direttiva è stata scritta in modo volutamente ampio. Non parla solo di cookie, ma vieta l'uso di qualsiasi tecnologia che archivi informazioni o acceda a informazioni già archiviate nel dispositivo terminale di un utente senza consenso. Interrogare la GPU per fare un canvas fingerprint è, a tutti gli effetti, "accedere a informazioni del terminale". Ricade in pieno nell'Articolo 5(3).
  2. GDPR: Nel momento in cui usate queste tecniche per distinguere un utente dall'altro nel tempo, state creando un dato personale (un identificatore online). Serve una base giuridica per trattarlo.

Quando si può usare senza chiedere il permesso? Esiste una deroga fondamentale. Se lo scopo del fingerprinting è strettamente necessario per l'erogazione del servizio richiesto dall'utente, o per motivi di sicurezza e prevenzione frodi, potete procedere per "Legittimo Interesse" senza bloccare l'utente con un banner preventivo (dovete comunque dichiararlo nella Privacy Policy).

La mia libreria centamiv/advanced-fingerprint

Mentre lavoravo su applicazioni Laravel che richiedevano elevati standard di sicurezza, mi sono scontrato con un problema: non esisteva un pacchetto nativo che unisse in modo elegante sia l'analisi server-side dei moderni Client Hints, sia un'implementazione pulita del Canvas Fingerprinting lato client.

Così ho scritto centamiv/advanced-fingerprint.

Architettura

La forza di questa libreria risiede nel suo approccio "Dual-Layer". Calcolare l'hash dell'hardware tramite Canvas richiede che la pagina web si carichi e che JavaScript venga eseguito. Questo crea un ritardo.

Per risolvere il problema, la libreria genera due firme:

  1. Server Hash (Immediato): Calcolato in PHP nel momento esatto in cui la richiesta HTTP tocca il server, prima ancora che la view venga renderizzata. Usa IP, Client Hints e Accept-Language. È perfetto per implementare un rate limiting molto granulare (es. "blocca questo dispositivo se fa più di 10 tentativi di login", anche se cambia IP dietro la stessa VPN).
  2. Client Hash (Ritardato ma Accurato): Tramite una direttiva Blade @fingerprintScript, viene iniettato uno script JS minimale che esegue il Canvas Fingerprinting ed esamina le API di sistema. Il risultato viene poi inviato al backend asincronamente.

Configurazione Flessibile

Essendo sviluppatori, abbiamo bisogno di controllo. Il livello di "entropia" (quanto deve essere precisa l'impronta) lo decidete voi. Modificando il file pubblicato config/fingerprint.php, potete abilitare o disabilitare i singoli sensori.

Volete un sistema che riconosca l'utente anche se passa dal Wi-Fi di casa alla connessione del cellulare? Basta impostare 'ip' => false. In questo modo, il fingerprint si baserà unicamente sull'hardware e sul software, ignorando la rete.

Un caso d'uso reale: prevenire il Session Hijacking

L'hijacking della sessione avviene quando un malintenzionato ruba il cookie di sessione di un utente legittimo (magari tramite una vulnerabilità XSS su un form non sicuro) e lo imposta sul proprio browser. Per il server standard, le richieste sembreranno provenire dall'utente originale.

Con advanced-fingerprint, possiamo fermarlo. Al momento del login salviamo la "Firma" dell'utente:

use Centamiv\AdvancedFingerprint\Facades\Fingerprint;
use Illuminate\Support\Facades\Auth;

public function login(Request $request) {
   // ... validazione credenziali ...

   // Generiamo l'impronta del dispositivo al momento del login
   $signature = Fingerprint::generate();

   // Salviamo l'impronta associata all'utente nel database
   Auth::user()->update(['last_device_signature' => $signature]);

   return redirect('/dashboard');
}

Poi, creiamo un Middleware personalizzato da applicare alle rotte protette. Questo middleware verificherà ad ogni richiesta critica se il dispositivo che sta usando la sessione corrisponde a quello che ha effettuato il login:

namespace App\Http\Middleware;

use Closure;
use Centamiv\AdvancedFingerprint\Facades\Fingerprint;
use Illuminate\Support\Facades\Auth;

class PreventSessionHijacking
{
   public function handle($request, Closure $next)
   {
       // Ricalcola la firma ad ogni interazione
       $currentSignature = Fingerprint::generate();
       $userSignature = Auth::user()->last_device_signature;

       if ($currentSignature !== $userSignature) {
           // Allarme rosso! Il token di sessione è valido,
           // ma l'hardware o il browser sono cambiati radicalmente.
           // Qualcuno potrebbe aver rubato il cookie di sessione.

           Auth::logout();
           return redirect('/login')->withErrors('Rilevato un cambio di dispositivo anomalo. Per la tua sicurezza, effettua nuovamente l'accesso.');
       }

       return $next($request);
   }
}

Per concludere

Il Browser Fingerprinting è una tecnologia affascinante ma intrinsecamente a doppio taglio. Nelle mani delle agenzie pubblicitarie o dei data broker, rappresenta lo strumento definitivo per erodere l'anonimato sul web, al punto che browser come Brave o Tor Project dedicano ingenti risorse per creare del "rumore casuale" (Canvas Randomization) nel tentativo di falsificare queste impronte.

Tuttavia, nelle mani degli ingegneri del software che sviluppano applicazioni enterprise, piattaforme finanziarie o sistemi di autenticazione critici, è uno scudo formidabile. Ci permette di difendere i nostri utenti da attacchi botnet automatizzati, da furti di sessione e da frodi informatiche.

Conoscere a fondo queste meccaniche (comprendere cosa sono i Client Hints, come funziona l'entropia del Canvas o gestire lo stato in un protocollo stateless) non ci rende solo programmatori più capaci, ma ci conferisce la consapevolezza necessaria per prendere decisioni tecniche ed etiche sull'architettura dei sistemi che costruiamo ogni giorno.