introduction
Je ne sais pas s'il existe ou s'il y aura un moyen d'identifier de manière unique les machines en utilisant uniquement un navigateur. Les principales raisons sont:
- Vous devrez enregistrer les données sur l'ordinateur des utilisateurs. Ces données peuvent être supprimées par l'utilisateur à tout moment. Sauf si vous avez un moyen de recréer ces données qui sont uniques pour chaque machine, vous êtes bloqué.
- Validation. Vous devez vous protéger contre l'usurpation d'identité, le piratage de session, etc.
Même s'il existe des moyens de suivre un ordinateur sans utiliser de cookies, il y aura toujours un moyen de le contourner et un logiciel qui le fera automatiquement. Si vous avez vraiment besoin de suivre quelque chose basé sur un ordinateur, vous devrez écrire une application native (Apple Store / Android Store / Windows Program / etc.).
Je ne serai peut-être pas en mesure de vous donner une réponse à la question que vous avez posée, mais je peux vous montrer comment mettre en œuvre le suivi de session. Avec le suivi de session, vous essayez de suivre la session de navigation au lieu de l'ordinateur visitant votre site. En suivant la session, votre schéma de base de données ressemblera à ceci:
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
}, ...]
Avantages du suivi basé sur la session:
- Pour les utilisateurs connectés, vous pouvez toujours générer le même identifiant de session à partir des utilisateurs
username
/ password
/ email
.
- Vous pouvez toujours suivre les utilisateurs invités en utilisant
sessionID
.
- Même si plusieurs personnes utilisent le même ordinateur (c.-à-d. Cybercafé), vous pouvez les suivre séparément si elles se connectent.
Inconvénients du suivi basé sur la session:
- Les sessions sont basées sur un navigateur et non sur un ordinateur. Si un utilisateur utilise 2 navigateurs différents, il en résultera 2 sessions différentes. Si cela pose un problème, vous pouvez arrêter de lire ici.
- Les sessions expirent si l'utilisateur n'est pas connecté. Si un utilisateur n'est pas connecté, il utilisera une session d'invité qui sera invalidée si l'utilisateur supprime les cookies et le cache du navigateur.
la mise en oeuvre
Il existe de nombreuses façons de l'implémenter. Je ne pense pas pouvoir les couvrir tous, je vais simplement énumérer mes préférés, ce qui en ferait une réponse avisée . Gardez cela à l'esprit.
Basiques
Je vais suivre la session en utilisant ce que l'on appelle un cookie permanent. Il s'agit de données qui se recréeront automatiquement même si l'utilisateur supprime ses cookies ou met à jour son navigateur. Il ne survivra cependant pas à la suppression de ses cookies et de son cache de navigation par l'utilisateur.
Pour mettre en œuvre cela, j'utiliserai le mécanisme de mise en cache des navigateurs ( RFC ), l'API WebStorage ( MDN ) et les cookies de navigateur ( RFC , Google Analytics ).
Légal
Afin d'utiliser les identifiants de suivi, vous devez les ajouter à la fois à votre politique de confidentialité et à vos conditions d'utilisation, de préférence sous le sous-titre Suivi . Nous utiliserons les touches suivantes à la fois sur document.cookie
et window.localStorage
:
- _ga : données Google Analytics
- __utma : cookie de suivi Google Analytics
- sid : SessionID
Assurez-vous d'inclure des liens vers votre politique de confidentialité et vos conditions d'utilisation sur toutes les pages qui utilisent le suivi.
Où stocker mes données de session?
Vous pouvez stocker vos données de session dans la base de données de votre site Web ou sur l'ordinateur des utilisateurs. Étant donné que je travaille normalement sur des sites plus petits (plus de 10 000 connexions continues) qui utilisent des applications tierces (Google Analytics / Clicky / etc.), il est préférable pour moi de stocker des données sur l'ordinateur des clients. Cela présente les avantages suivants:
- Aucune recherche de base de données / surcharge / charge / latence / espace / etc.
- L'utilisateur peut supprimer ses données quand il le souhaite sans avoir à m'écrire des e-mails ennuyeux.
et inconvénients:
- Les données doivent être cryptées / décryptées et signées / vérifiées, ce qui crée une surcharge du processeur sur le client (pas si mal) et le serveur (bah!).
- Les données sont supprimées lorsque l'utilisateur supprime ses cookies et son cache. (c'est ce que je veux vraiment)
- Les données ne sont pas disponibles pour l'analyse lorsque les utilisateurs se déconnectent. (analyses pour les utilisateurs actuellement en train de naviguer uniquement)
UUIDS
- BrowserID : identifiant unique généré à partir de la chaîne de l'agent utilisateur du navigateur.
Browser|BrowserVersion|OS|OSVersion|Processor|MozzilaMajorVersion|GeckoMajorVersion
- ComputerID : généré à partir de l'adresse IP et de la clé de session HTTPS des utilisateurs.
getISP(requestIP)|getHTTPSClientKey()
- FingerPrintID : empreinte digitale basée sur JavaScript basée sur un fingerprint.js modifié .
FingerPrint.get()
- SessionID : clé aléatoire générée lors de la première visite du site par l'utilisateur.
BrowserID|ComputerID|randombytes(256)
- GoogleID : généré à partir d'un
__utma
cookie.getCookie(__utma).uniqueid
Mécanisme
L'autre jour, je regardais l'émission de wendy williams avec ma petite amie et j'ai été complètement horrifié lorsque l'animatrice a conseillé à ses téléspectateurs de supprimer l'historique de leur navigateur au moins une fois par mois. La suppression de l'historique du navigateur a normalement les effets suivants:
- Supprime l'historique des sites Web visités.
- Supprime les cookies et
window.localStorage
(aww man).
La plupart des navigateurs modernes rendent cette option facilement disponible, mais ne craignez pas vos amis. Car il y a une solution. Le navigateur dispose d'un mécanisme de mise en cache pour stocker des scripts / images et d'autres choses. Habituellement, même si nous supprimons notre historique, ce cache de navigateur reste toujours. Tout ce dont nous avons besoin, c'est d'un moyen de stocker nos données ici. Il existe 2 méthodes pour ce faire. Le mieux est d'utiliser une image SVG et de stocker nos données dans ses balises. De cette façon, les données peuvent toujours être extraites même si JavaScript est désactivé à l'aide de Flash. Cependant, comme c'est un peu compliqué, je vais démontrer l'autre approche qui utilise JSONP ( Wikipedia )
example.com/assets/js/tracking.js (en fait 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);
}
Maintenant, nous pouvons obtenir notre clé de session à tout moment:
window.__sid || window.localStorage.getItem("sid") || getCookie("sid") || ""
Comment puis-je faire en sorte que tracking.js reste dans le navigateur?
Nous pouvons y parvenir en utilisant les en - têtes HTTP Cache-Control , Last-Modified et ETag . Nous pouvons utiliser SessionID
comme valeur pour l'en-tête etag:
setHeaders({
"ETag": SessionID,
"Last-Modified": new Date(0).toUTCString(),
"Cache-Control": "private, max-age=31536000, s-max-age=31536000, must-revalidate"
})
Last-Modified
l'en-tête indique au navigateur que ce fichier n'est pratiquement jamais modifié. Cache-Control
dit aux mandataires et aux passerelles de ne pas mettre en cache le document mais au navigateur de le mettre en cache pendant 1 an.
La prochaine fois que le navigateur demandera le document, il enverra des en If-Modified-Since
- If-None-Match
têtes. Nous pouvons les utiliser pour renvoyer une 304 Not Modified
réponse.
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();
}
Désormais, chaque fois que le navigateur demande, tracking.js
notre serveur répondra avec un 304 Not Modified
résultat et forcera l'exécution de la copie locale de tracking.js
.
Je ne comprends toujours pas. Explique le moi
Supposons que l'utilisateur efface son historique de navigation et actualise la page. La seule chose qui reste sur l'ordinateur des utilisateurs est une copie du tracking.js
cache du navigateur. Lorsque le navigateur le demande, tracking.js
il reçoit une 304 Not Modified
réponse qui l'amène à exécuter la 1ère version de tracking.js
celui - ci reçue. tracking.js
exécute et restaure le SessionID
qui a été supprimé.
Validation
Supposons que Haxor X vole les cookies de nos clients alors qu'ils sont encore connectés. Comment les protégeons-nous? Cryptographie et empreinte digitale du navigateur à la rescousse. Rappelez-vous que notre définition originale SessionID
était:
BrowserID|ComputerID|randomBytes(256)
Nous pouvons changer cela en:
Timestamp|BrowserID|ComputerID|encrypt(randomBytes(256), hk)|sign(Timestamp|BrowserID|ComputerID|randomBytes(256), hk)
Où hk = sign(Timestamp|BrowserID|ComputerID, serverKey)
.
Nous pouvons maintenant valider notre en SessionID
utilisant l'algorithme suivant:
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;
Maintenant, pour que l'attaque de Haxor fonctionne, ils doivent:
- Avoir la même chose
ComputerID
. Cela signifie qu'ils doivent avoir le même fournisseur de FAI que la victime (Tricky). Cela donnera à notre victime la possibilité d'intenter une action en justice dans son propre pays. Haxor doit également obtenir la clé de session HTTPS de la victime (Hard).
- Avoir la même chose
BrowserID
. N'importe qui peut usurper la chaîne User-Agent (ennuyeux).
- Être capable de créer leur propre faux
SessionID
(très difficile). Les attaques de volume ne fonctionneront pas car nous utilisons un horodatage pour générer une clé de cryptage / signature, donc fondamentalement, c'est comme générer une nouvelle clé pour chaque session. En plus de cela, nous chiffrons des octets aléatoires, donc une simple attaque par dictionnaire est également hors de question.
Nous pouvons améliorer la validation en transférant GoogleID
et FingerprintID
(via ajax ou des champs cachés) et en les comparant à ceux-ci.
if( GoogleID != getStoredGoodleID($sid) ) return false;
if( byte_difference(FingerPrintID, getStoredFingerprint($sid) > 10%) return false;