introduzione
Non so se ci sia o ci sarà mai un modo per identificare in modo univoco le macchine usando solo un browser. Le ragioni principali sono:
- Dovrai salvare i dati sul computer degli utenti. Questi dati possono essere cancellati dall'utente in qualsiasi momento. A meno che tu non abbia un modo per ricreare questi dati che sono unici per ogni macchina, allora sei bloccato.
- Convalida. Devi stare attento allo spoofing, al dirottamento della sessione, ecc.
Anche se ci sono modi per tracciare un computer senza usare i cookie, ci sarà sempre un modo per bypassarlo e un software che lo farà automaticamente. Se hai davvero bisogno di tracciare qualcosa basato su un computer, dovrai scrivere un'applicazione nativa (Apple Store / Android Store / Programma Windows / ecc.).
Potrei non essere in grado di darti una risposta alla domanda che hai posto, ma posso mostrarti come implementare il monitoraggio della sessione. Con il monitoraggio delle sessioni si tenta di tenere traccia della sessione di navigazione anziché del computer che visita il sito. Tracciando la sessione, lo schema del database sarà simile al seguente:
sesssion:
sessionID: string
// Global session data goes here
computers: [{
BrowserID: string
ComputerID: string
FingerprintID: string
userID: string
authToken: string
ipAddresses: ["203.525....", "203.525...", ...]
// Computer session data goes here
}, ...]
Vantaggi del monitoraggio basato sulla sessione:
- Per gli utenti che hanno effettuato l'accesso, è sempre possibile generare lo stesso ID sessione dagli utenti
username
/ password
/ email
.
- Puoi comunque tenere traccia degli utenti guest utilizzando
sessionID
.
- Anche se più persone utilizzano lo stesso computer (ad es. Cybercafe), è possibile seguirle separatamente se effettuano l'accesso.
Svantaggi del monitoraggio basato sulla sessione:
- Le sessioni sono basate su browser e non su computer. Se un utente utilizza 2 browser diversi, si otterranno 2 sessioni diverse. Se questo è un problema, puoi smettere di leggere qui.
- Le sessioni scadono se l'utente non ha effettuato l'accesso. Se un utente non ha effettuato l'accesso, utilizzerà una sessione ospite che verrà invalidata se l'utente elimina i cookie e la cache del browser.
Implementazione
Esistono molti modi per implementarlo. Non credo di poterle coprire tutte, elencherò solo il mio preferito che renderebbe questa una risposta supponente . Tienilo a mente.
Nozioni di base
Tracciamo la sessione utilizzando quello che è noto come un cookie per sempre. Si tratta di dati che si ricrea automaticamente se l'utente cancella i suoi cookie o aggiorna il suo browser. Non sopravviverà comunque all'utente che cancella sia i cookie che la cache di navigazione.
Per implementare questo userò il meccanismo di memorizzazione nella cache dei browser ( RFC ), l'API WebStorage ( MDN ) e i cookie del browser ( RFC , Google Analytics ).
legale
Al fine di utilizzare gli ID di tracciamento, è necessario aggiungerli sia alla politica sulla privacy sia ai termini di utilizzo, preferibilmente sotto il sottotitolo Tracciamento . Useremo i seguenti tasti su entrambi document.cookie
e window.localStorage
:
- _ga : dati di Google Analytics
- __utma : cookie di tracciamento di Google Analytics
- sid : SessionID
Assicurati di includere collegamenti alla tua Informativa sulla privacy e termini di utilizzo in tutte le pagine che utilizzano il monitoraggio.
Dove posso conservare i dati della mia sessione?
È possibile archiviare i dati della sessione nel database del sito Web o sul computer degli utenti. Dal momento che lavoro normalmente su siti più piccoli (consento più di 10 mila connessioni continue) che utilizzano applicazioni di terze parti (Google Analytics / Clicky / ecc.) È meglio per me archiviare i dati sul computer client. Questo ha i seguenti vantaggi:
- Nessuna ricerca nel database / sovraccarico / carico / latenza / spazio / ecc.
- L'utente può cancellare i propri dati ogni volta che lo desidera senza la necessità di scrivermi fastidiose e-mail.
e svantaggi:
- I dati devono essere crittografati / decrittografati e firmati / verificati, il che crea un sovraccarico della CPU sul client (non così male) e sul server (bah!).
- I dati vengono eliminati quando l'utente elimina i cookie e la cache. (questo è quello che voglio davvero)
- I dati non sono disponibili per l'analisi quando gli utenti non sono in linea. (analisi solo per gli utenti che navigano attualmente)
UUID
- BrowserID : ID univoco generato dalla stringa dell'agente utente del browser.
Browser|BrowserVersion|OS|OSVersion|Processor|MozzilaMajorVersion|GeckoMajorVersion
- ComputerID : generato dall'indirizzo IP dell'utente e dalla chiave di sessione HTTPS.
getISP(requestIP)|getHTTPSClientKey()
- FingerPrintID : fingerprinting basato su JavaScript basato su fingerprint.js modificato .
FingerPrint.get()
- SessionID : chiave casuale generata quando l'utente visita il primo sito.
BrowserID|ComputerID|randombytes(256)
- GoogleID : generato da
__utma
cookie.getCookie(__utma).uniqueid
Meccanismo
L'altro giorno stavo guardando lo spettacolo di Wendy Williams con la mia ragazza ed ero completamente inorridito quando l'host ha consigliato ai suoi spettatori di cancellare la loro cronologia del browser almeno una volta al mese. L'eliminazione della cronologia del browser ha normalmente i seguenti effetti:
- Elimina la cronologia dei siti Web visitati.
- Elimina i cookie e
window.localStorage
(aww man).
La maggior parte dei browser moderni rende questa opzione prontamente disponibile ma non teme gli amici. Perché c'è una soluzione. Il browser ha un meccanismo di memorizzazione nella cache per memorizzare script / immagini e altre cose. Di solito anche se cancelliamo la nostra cronologia, questa cache del browser rimane comunque. Tutto ciò di cui abbiamo bisogno è un modo per archiviare i nostri dati qui. Ci sono 2 metodi per farlo. Il migliore è utilizzare un'immagine SVG e archiviare i nostri dati all'interno dei suoi tag. In questo modo i dati possono ancora essere estratti anche se JavaScript è disabilitato usando Flash. Tuttavia, poiché è un po 'complicato, mostrerò l'altro approccio che utilizza JSONP ( Wikipedia )
example.com/assets/js/tracking.js (attualmente tracking.php)
var now = new Date();
var window.__sid = "SessionID"; // Server generated
setCookie("sid", window.__sid, now.setFullYear(now.getFullYear() + 1, now.getMonth(), now.getDate() - 1));
if( "localStorage" in window ) {
window.localStorage.setItem("sid", window.__sid);
}
Ora possiamo ottenere la nostra chiave di sessione in qualsiasi momento:
window.__sid || window.localStorage.getItem("sid") || getCookie("sid") || ""
Come faccio a tenere il tracking.js nel browser?
Possiamo raggiungere questo obiettivo usando le intestazioni HTTP Cache-Control , Last-Modified ed ETag . Possiamo usare SessionID
come valore per l'intestazione etag:
setHeaders({
"ETag": SessionID,
"Last-Modified": new Date(0).toUTCString(),
"Cache-Control": "private, max-age=31536000, s-max-age=31536000, must-revalidate"
})
Last-Modified
header dice al browser che questo file non viene praticamente mai modificato. Cache-Control
indica ai proxy e ai gateway di non memorizzare nella cache il documento, ma indica al browser di memorizzarlo nella cache per 1 anno.
La prossima volta che il browser richiede il documento, invierà If-Modified-Since
e le If-None-Match
intestazioni. Possiamo usarli per restituire una 304 Not Modified
risposta.
example.com/assets/js/tracking.php
$sid = getHeader("If-None-Match") ?: getHeader("if-none-match") ?: getHeader("IF-NONE-MATCH") ?: "";
$ifModifiedSince = hasHeader("If-Modified-Since") ?: hasHeader("if-modified-since") ?: hasHeader("IF-MODIFIED-SINCE");
if( validateSession($sid) ) {
if( sessionExists($sid) ) {
continueSession($sid);
send304();
} else {
startSession($sid);
send304();
}
} else if( $ifModifiedSince ) {
send304();
} else {
startSession();
send200();
}
Ora ogni volta che il browser richiede che il tracking.js
nostro server risponda con un 304 Not Modified
risultato e imponga l'esecuzione della copia locale di tracking.js
.
Ancora non capisco. Spiegamelo
Supponiamo che l'utente cancelli la cronologia di navigazione e aggiorni la pagina. L'unica cosa rimasta sul computer degli utenti è una copia tracking.js
nella cache del browser. Quando il browser lo richiede tracking.js
, riceve una 304 Not Modified
risposta che gli fa eseguire la prima versione tracking.js
ricevuta. tracking.js
esegue e ripristina SessionID
ciò che è stato eliminato.
Validazione
Supponiamo che Haxor X rubi i cookie dei nostri clienti mentre sono ancora connessi. Come li proteggiamo? Crittografia e impronte digitali del browser in soccorso. Ricorda che la nostra definizione originale per SessionID
era:
BrowserID|ComputerID|randomBytes(256)
Possiamo cambiarlo in:
Timestamp|BrowserID|ComputerID|encrypt(randomBytes(256), hk)|sign(Timestamp|BrowserID|ComputerID|randomBytes(256), hk)
Dove hk = sign(Timestamp|BrowserID|ComputerID, serverKey)
.
Ora possiamo convalidare il nostro SessionID
utilizzando il seguente algoritmo:
if( getTimestamp($sid) is older than 1 year ) return false;
if( getBrowserID($sid) !== createBrowserID($_Request, $_Server) ) return false;
if( getComputerID($sid) !== createComputerID($_Request, $_Server) return false;
$hk = sign(getTimestamp($sid) + getBrowserID($sid) + getComputerID($sid), $SERVER["key"]);
if( !verify(getTimestamp($sid) + getBrowserID($sid) + getComputerID($sid) + decrypt(getRandomBytes($sid), hk), getSignature($sid), $hk) ) return false;
return true;
Ora, affinché l'attacco di Haxor funzioni, devono:
- Avere lo stesso
ComputerID
. Ciò significa che devono avere lo stesso provider di servizi Internet della vittima (Tricky). Ciò darà alla nostra vittima l'opportunità di intraprendere un'azione legale nel proprio paese. Haxor deve anche ottenere la chiave di sessione HTTPS dalla vittima (Difficile).
- Avere lo stesso
BrowserID
. Chiunque può falsificare la stringa User-Agent (fastidiosa).
- Essere in grado di creare il proprio falso
SessionID
(molto difficile). Gli attacchi di volume non funzioneranno perché utilizziamo un timestamp per generare la chiave di crittografia / firma, quindi sostanzialmente è come generare una nuova chiave per ogni sessione. Inoltre, crittografiamo i byte casuali, quindi anche un semplice attacco del dizionario è fuori discussione.
Possiamo migliorare la convalida inoltrando GoogleID
e FingerprintID
(tramite ajax o campi nascosti) e confrontandoli con quelli.
if( GoogleID != getStoredGoodleID($sid) ) return false;
if( byte_difference(FingerPrintID, getStoredFingerprint($sid) > 10%) return false;