Einführung
Ich weiß nicht, ob es eine Möglichkeit gibt oder jemals geben wird, Maschinen allein mit einem Browser eindeutig zu identifizieren. Die Hauptgründe sind:
- Sie müssen Daten auf dem Computer des Benutzers speichern. Diese Daten können vom Benutzer jederzeit gelöscht werden. Wenn Sie nicht die Möglichkeit haben, diese Daten neu zu erstellen, die für jede Maschine eindeutig sind, stecken Sie fest.
- Validierung. Sie müssen sich vor Spoofing, Sitzungsentführung usw. schützen.
Selbst wenn es Möglichkeiten gibt, einen Computer ohne Verwendung von Cookies zu verfolgen, gibt es immer eine Möglichkeit, ihn zu umgehen, und Software, die dies automatisch tut. Wenn Sie wirklich etwas auf der Basis eines Computers verfolgen müssen, müssen Sie eine native Anwendung schreiben (Apple Store / Android Store / Windows-Programm / usw.).
Ich kann Ihnen möglicherweise keine Antwort auf die von Ihnen gestellte Frage geben, aber ich kann Ihnen zeigen, wie Sie die Sitzungsverfolgung implementieren. Mit der Sitzungsverfolgung versuchen Sie, die Browsersitzung zu verfolgen, anstatt dass der Computer Ihre Site besucht. Wenn Sie die Sitzung verfolgen, sieht Ihr Datenbankschema folgendermaßen aus:
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
}, ...]
Vorteile des sitzungsbasierten Trackings:
- Für angemeldete Benutzer sind , können Sie immer die gleiche Session - ID von den Benutzern erzeugen
username
/ password
/ email
.
- Sie können weiterhin Gastbenutzer mit verfolgen
sessionID
.
- Selbst wenn mehrere Personen denselben Computer verwenden (z. B. Cybercafe), können Sie sie separat verfolgen, wenn sie sich anmelden.
Nachteile des sitzungsbasierten Trackings:
- Sitzungen sind browserbasiert und nicht computerbasiert. Wenn ein Benutzer zwei verschiedene Browser verwendet, führt dies zu zwei verschiedenen Sitzungen. Wenn dies ein Problem ist, können Sie hier aufhören zu lesen.
- Sitzungen laufen ab, wenn der Benutzer nicht angemeldet ist. Wenn ein Benutzer nicht angemeldet ist, verwendet er eine Gastsitzung, die ungültig wird, wenn der Benutzer Cookies und den Browser-Cache löscht.
Implementierung
Es gibt viele Möglichkeiten, dies umzusetzen. Ich glaube nicht, dass ich sie alle abdecken kann. Ich werde nur meinen Favoriten auflisten, was dies zu einer meinungsbildenden Antwort machen würde . Denken Sie daran.
Grundlagen
Ich werde die Sitzung verfolgen, indem ich einen so genannten Forever-Cookie verwende. Dies sind Daten, die sich automatisch neu erstellen, selbst wenn der Benutzer seine Cookies löscht oder seinen Browser aktualisiert. Es wird jedoch nicht überleben, wenn der Benutzer sowohl seine Cookies als auch seinen Browser-Cache löscht.
Um dies zu implementieren, verwende ich den Browser-Caching-Mechanismus ( RFC ), die WebStorage-API ( MDN ) und Browser-Cookies ( RFC , Google Analytics ).
Legal
Um Tracking-IDs verwenden zu können, müssen Sie diese sowohl zu Ihrer Datenschutzrichtlinie als auch zu Ihren Nutzungsbedingungen hinzufügen, vorzugsweise unter der Überschrift Tracking . Wir werden die folgenden Tasten für beide document.cookie
und verwenden window.localStorage
:
- _ga : Google Analytics-Daten
- __utma : Google Analytics-Tracking-Cookie
- sid : SessionID
Stellen Sie sicher, dass Sie auf allen Seiten, die Tracking verwenden, Links zu Ihren Datenschutzrichtlinien und Nutzungsbedingungen einfügen.
Wo speichere ich meine Sitzungsdaten?
Sie können Ihre Sitzungsdaten entweder in Ihrer Website-Datenbank oder auf dem Computer des Benutzers speichern. Da ich normalerweise auf kleineren Websites arbeite (mit weniger als 10.000 fortlaufenden Verbindungen), die Anwendungen von Drittanbietern (Google Analytics / Clicky / usw.) verwenden, ist es für mich am besten, Daten auf dem Computer des Clients zu speichern. Dies hat folgende Vorteile:
- Keine Datenbanksuche / Overhead / Laden / Latenz / Speicherplatz / etc.
- Benutzer können ihre Daten jederzeit löschen, ohne mir nervige E-Mails schreiben zu müssen.
und Nachteile:
- Daten müssen verschlüsselt / entschlüsselt und signiert / verifiziert werden, was einen CPU-Overhead auf dem Client (nicht so schlecht) und dem Server (bah!) Erzeugt.
- Daten werden gelöscht, wenn der Benutzer seine Cookies und seinen Cache löscht. (das ist was ich wirklich will)
- Daten sind für Analysen nicht verfügbar, wenn Benutzer offline gehen. (Analyse nur für Benutzer, die derzeit surfen)
UUIDS
- BrowserID : Eindeutige ID, die aus der Benutzeragentenzeichenfolge des Browsers generiert wird.
Browser|BrowserVersion|OS|OSVersion|Processor|MozzilaMajorVersion|GeckoMajorVersion
- ComputerID : Wird aus der IP-Adresse und dem HTTPS-Sitzungsschlüssel des Benutzers generiert.
getISP(requestIP)|getHTTPSClientKey()
- FingerPrintID : JavaScript-basiertes Fingerprinting basierend auf einem modifizierten fingerprint.js .
FingerPrint.get()
- SessionID : Zufälliger Schlüssel, der generiert wird, wenn der Benutzer die Site zum ersten Mal besucht.
BrowserID|ComputerID|randombytes(256)
- GoogleID : Aus
__utma
Cookie generiert .getCookie(__utma).uniqueid
Mechanismus
Neulich habe ich mit meiner Freundin die Wendy Williams Show gesehen und war völlig entsetzt, als die Moderatorin ihren Zuschauern riet, ihren Browserverlauf mindestens einmal im Monat zu löschen. Das Löschen des Browserverlaufs hat normalerweise folgende Auswirkungen:
- Löscht den Verlauf der besuchten Websites.
- Löscht Cookies und
window.localStorage
(aww man).
Die meisten modernen Browser stellen diese Option zur Verfügung, fürchten jedoch keine Freunde. Denn es gibt eine Lösung. Der Browser verfügt über einen Caching-Mechanismus zum Speichern von Skripten / Bildern und anderen Dingen. Selbst wenn wir unseren Verlauf löschen, bleibt dieser Browser-Cache normalerweise bestehen. Wir brauchen nur eine Möglichkeit, unsere Daten hier zu speichern. Hierfür gibt es zwei Methoden. Das bessere ist, ein SVG-Bild zu verwenden und unsere Daten in seinen Tags zu speichern. Auf diese Weise können Daten auch dann extrahiert werden, wenn JavaScript mithilfe von Flash deaktiviert ist. Da dies jedoch etwas kompliziert ist, werde ich den anderen Ansatz demonstrieren, der JSONP ( Wikipedia ) verwendet.
example.com/assets/js/tracking.js (tatsächlich 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);
}
Jetzt können wir jederzeit unseren Sitzungsschlüssel erhalten:
window.__sid || window.localStorage.getItem("sid") || getCookie("sid") || ""
Wie bringe ich tracking.js dazu, im Browser zu bleiben?
Dies können wir mit Cache-Control- , Last-Modified- und ETag- HTTP-Headern erreichen. Wir können den SessionID
as-Wert für den etag-Header verwenden:
setHeaders({
"ETag": SessionID,
"Last-Modified": new Date(0).toUTCString(),
"Cache-Control": "private, max-age=31536000, s-max-age=31536000, must-revalidate"
})
Last-Modified
Der Header teilt dem Browser mit, dass diese Datei grundsätzlich nie geändert wird. Cache-Control
Weist Proxys und Gateways an, das Dokument nicht zwischenzuspeichern, sondern den Browser anzuweisen, es 1 Jahr lang zwischenzuspeichern.
Das nächste Mal , wenn der Browser das Dokument anfordert, wird es senden If-Modified-Since
und If-None-Match
Header. Wir können diese verwenden, um eine 304 Not Modified
Antwort zurückzugeben.
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();
}
Jedes Mal, wenn der Browser dies anfordert, antwortet tracking.js
unser Server mit einem 304 Not Modified
Ergebnis und erzwingt die Ausführung der lokalen Kopie von tracking.js
.
Ich verstehe immer noch nicht. Erklären Sie es mir
Nehmen wir an, der Benutzer löscht seinen Browserverlauf und aktualisiert die Seite. Das einzige, was auf dem Computer des Benutzers übrig bleibt, ist eine Kopie tracking.js
im Browser-Cache. Wenn der Browser dies anfordert tracking.js
, erhält er eine 304 Not Modified
Antwort, die dazu führt, dass er die erste empfangene Version ausführt tracking.js
. tracking.js
führt das SessionID
gelöschte aus und stellt es wieder her.
Validierung
Angenommen, Haxor X stiehlt unseren Kunden Cookies, während sie noch angemeldet sind. Wie schützen wir sie? Kryptographie und Browser-Fingerabdruck zur Rettung. Denken Sie daran, unsere ursprüngliche Definition für SessionID
war:
BrowserID|ComputerID|randomBytes(256)
Wir können dies ändern in:
Timestamp|BrowserID|ComputerID|encrypt(randomBytes(256), hk)|sign(Timestamp|BrowserID|ComputerID|randomBytes(256), hk)
Wo hk = sign(Timestamp|BrowserID|ComputerID, serverKey)
.
Jetzt können wir unsere SessionID
mit dem folgenden Algorithmus validieren :
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;
Damit Haxors Angriff funktioniert, müssen sie:
- Habe dasselbe
ComputerID
. Das bedeutet, dass sie denselben ISP-Anbieter wie das Opfer haben müssen (Tricky). Dies gibt unserem Opfer die Möglichkeit, rechtliche Schritte im eigenen Land einzuleiten. Haxor muss auch den HTTPS-Sitzungsschlüssel vom Opfer erhalten (schwer).
- Habe dasselbe
BrowserID
. Jeder kann die User-Agent-Zeichenfolge fälschen (ärgerlich).
- Seien Sie in der Lage, ihre eigene Fälschung zu erstellen
SessionID
(sehr schwer). Volume-Angriffe funktionieren nicht, da wir einen Zeitstempel verwenden, um einen Verschlüsselungs- / Signaturschlüssel zu generieren. Im Grunde ist es so, als würde für jede Sitzung ein neuer Schlüssel generiert. Darüber hinaus verschlüsseln wir zufällige Bytes, sodass ein einfacher Wörterbuchangriff ebenfalls nicht in Frage kommt.
Wir können die Validierung verbessern, indem wir GoogleID
und FingerprintID
(über Ajax oder versteckte Felder) weiterleiten und mit diesen abgleichen.
if( GoogleID != getStoredGoodleID($sid) ) return false;
if( byte_difference(FingerPrintID, getStoredFingerprint($sid) > 10%) return false;