
Démo éducative d'evercookie montrant comment les techniques de stockage du navigateur et de cache HTTP peuvent ré-identifier de manière persistante un visiteur.
Une démonstration éducative de la façon dont les sites web vous identifient de manière persistante — et pourquoi « effacer vos cookies » ne suffit plus.
ubercookie place un seul identifiant aléatoire dans 12 vecteurs de stockage différents du navigateur à la fois. Chaque fois que vous visitez, il les lit tous, prend un consensus et réécrit l'identifiant partout. Effacez un seul stockage — ou même tous vos cookies — et les survivants le réaniment silencieusement. Le site vous montre, en langage clair, exactement où votre identifiant se cache et combien de fois il a reconnu votre navigateur.
C'est la même idée derrière le classique evercookie de Samy Kamkar — construit ici comme un outil pédagogique ouvert et transparent axé sur la résurrection du stockage et la persistance des supercookies.
[!IMPORTANT] Ce projet suit intentionnellement le visiteur, dans un but de sensibilisation. Il est uniquement first-party, ne stocke qu'un identifiant aléatoire, des compteurs de visites, des horodatages de première/dernière visite, et des étiquettes de source de récupération, ne partage rien avec des tiers, et fournit un véritable bouton « Oubliez-moi ». Ne le réutilisez pas pour suivre des personnes à leur insu ou sans leur consentement — c'est le contraire du but. Voir Éthique.
| Vecteur | Type | Nécessite JS ? | Effaçable depuis JS ? | Ce qu'il enseigne |
|---|---|---|---|---|
document.cookie | client | oui | oui | Le traceur de base |
localStorage | client | oui | oui | Survit à l'effacement des cookies |
sessionStorage | client | oui | oui | Redondance par onglet |
IndexedDB | client | oui | oui | Une base de données entière que les gens oublient de vider |
Cache API (caches) | client | oui | oui | Stockage programmable, distinct des précédents |
window.name | client | oui | oui | Persiste entre les navigations |
| OPFS (Origin Private File System) | client | oui | oui | Un système de fichiers en bac à sable que les nettoyages manuels oublient |
| Service Worker + Cache | client | oui | oui | Un script en arrière-plan ressort l'identifiant, même hors ligne |
Cookie serveur (HttpOnly) | serveur | non | via le serveur | Invisible pour JS, toujours envoyé à chaque requête |
| Supercookie ETag | serveur | non | vidage du cache uniquement | Identifiant renvoyé dans If-None-Match |
| Supercookie Last-Modified | serveur | non | vidage du cache uniquement | Identifiant encodé dans la date de la ressource mise en cache |
| Cache HTTP (script avec identifiant intégré) | serveur | non | vidage du cache uniquement | Identifiant intégré dans un fichier cache immutable |
En plus de cela, la page demande au navigateur un stockage persistant (navigator.storage.persist()), ce qui exempte les copies IndexedDB / Cache / Service Worker / OPFS de l'éviction automatique — les rendant encore plus difficiles à éliminer.
Les trois vecteurs basés sur le cache sont la punchline de la persistance : ils vivent dans le cache HTTP du navigateur, donc JavaScript (y compris notre propre « Oubliez-moi ») ne peut pas les supprimer — seul le vidage du cache de votre navigateur le peut. C'est ainsi que l'identifiant revient d'entre les morts.
Une description complète des vecteurs de stockage implémentés, plus l'idée du supercookie HSTS qui s'intègre encore à ce projet, se trouve dans docs/techniques.md.
ubercookie/
├── backend/ FastAPI — server-side vectors + the observation log (SQLite)
│ └── app/
│ ├── main.py endpoints: /api/visit, /api/whoami, /api/etag-id,
│ │ /api/lastmod-id, /api/cache-id.js, /api/clear-cookie,
│ │ /api/forget
│ ├── store.py "we've seen this browser N times" memory
│ └── ids.py mint/validate the 32-hex tracking id
└── frontend/ Vanilla JS + Vite — the dashboard and the client vectors
└── src/ubercookie/
├── index.js orchestrator: read-all → consensus → respawn → report
└── vectors/ one self-contained module per storage vector
Comment fonctionne une visite (frontend/src/ubercookie/index.js) :
HttpOnly.Nécessite Python ≥ 3.11 (avec uv) et Node ≥ 18.
make install # backend deps (uv) + frontend deps (npm)
# then, in two terminals:
make backend # FastAPI on http://localhost:8000
make frontend # Vite on http://localhost:5173 (proxies /api → :8000)
Ouvrez http://localhost:5173 et observez-vous être suivi. Ouvrez DevTools, supprimez quelques stockages, cliquez sur Re-scanner, et regardez-les réapparaître.
Ligne unique pour les deux serveurs à la fois :
./scripts/dev.sh
make build # → frontend/dist
cd backend && uv run uvicorn app.main:app --port 8000
# open http://localhost:8000
Servir les deux depuis une seule origine est la configuration la plus fidèle, car les vecteurs cache/ETag dépendent du véritable cache HTTP de même origine.
make test # backend pytest (server-side vector logic + observation log)
make build # frontend production build
Les tests backend exercent les vecteurs côté serveur et le journal d'observation. Le comportement du navigateur nécessite encore un vrai navigateur pour vérification car plusieurs vecteurs dépendent du stockage d'origine, des Service Workers et du cache HTTP.
C'est un outil défensif / de sensibilisation. Directives intégrées dans la conception :
Veuillez garder tout fork dans le même esprit : utilisez-le pour enseigner aux gens comment fonctionne le suivi afin qu'ils puissent se défendre, pas pour les suivre discrètement.
MIT — voir LICENSE.