
Demonstração educacional do evercookie mostrando como técnicas de armazenamento do navegador e cache HTTP podem reidentificar persistentemente um visitante.
Uma demonstração educativa de como os sites identificam você de forma persistente — e por que "limpar os cookies" já não é suficiente.
O ubercookie planta um único id aleatório em 12 vetores diferentes de armazenamento do navegador de uma só vez. Cada vez que você visita, ele lê todos eles, chega a um consenso e reescreve o id de volta em todos os lugares. Limpe qualquer um dos armazenamentos — ou até mesmo todos os seus cookies — e os sobreviventes silenciosamente o ressuscitam. O site mostra a você, em linguagem simples, exatamente onde seu id está escondido e com que frequência ele reconheceu seu navegador.
É a mesma ideia por trás do clássico evercookie de Samy Kamkar — construído aqui como um auxílio de ensino aberto e transparente, focado na ressuscitação de armazenamento e na persistência de supercookies.
[!IMPORTANT] Este projeto rastreia o visitante de propósito, para conscientização. Ele é apenas first-party, armazena somente um id aleatório, contagens de visita, carimbos de data/hora de primeira/última visita e rótulos de origem de recuperação, não compartilha nada com terceiros e inclui um botão "Forget me" de verdade. Não o reaproveite para rastrear pessoas sem o conhecimento ou consentimento delas — isso é o oposto do objetivo. Veja Ética.
| Vetor | Tipo | Precisa de JS? | Limpável via JS? | O que ensina |
|---|---|---|---|---|
document.cookie | cliente | sim | sim | O rastreador básico |
localStorage | cliente | sim | sim | Sobrevive à limpeza de cookies |
sessionStorage | cliente | sim | sim | Redundância por aba |
IndexedDB | cliente | sim | sim | Um banco de dados inteiro que as pessoas esquecem de limpar |
Cache API (caches) | cliente | sim | sim | Armazenamento programável, separado dos anteriores |
window.name | cliente | sim | sim | Persiste entre navegações |
| OPFS (Origin Private File System) | cliente | sim | sim | Um sistema de arquivos isolado (sandbox) que limpezas manuais não alcançam |
| Service Worker + Cache | cliente | sim | sim | Script em segundo plano reentrega o id, mesmo offline |
Cookie de servidor (HttpOnly) | servidor | não | via servidor | Invisível para o JS, ainda enviado em toda requisição |
| Supercookie de ETag | servidor | não | somente com limpeza de cache | Id ecoado de volta em If-None-Match |
| Supercookie de Last-Modified | servidor | não | somente com limpeza de cache | Id codificado na data do recurso em cache |
| Cache HTTP (script com id embutido) | servidor | não | somente com limpeza de cache | Id embutido em um arquivo em cache immutable |
Além desses, a página pede ao navegador armazenamento persistente
(navigator.storage.persist()), o que isenta as cópias em IndexedDB / Cache / Service
Worker / OPFS da remoção automática — tornando-as ainda mais difíceis de eliminar.
Os três vetores baseados em cache são a grande sacada da persistência: eles vivem no cache HTTP do navegador, então o JavaScript (incluindo o nosso próprio "Forget me") não pode excluí-los — apenas a limpeza do cache do navegador consegue. É assim que o id volta dos mortos.
Uma descrição completa dos vetores de armazenamento implementados, além da ideia de
supercookie HSTS que ainda cabe neste projeto, está em
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
Como funciona uma visita (frontend/src/ubercookie/index.js):
HttpOnly.Requer Python ≥ 3.11 (com uv) e 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)
Abra http://localhost:5173 e veja você mesmo sendo rastreado. Abra o DevTools, exclua alguns armazenamentos, clique em Re-scan e observe-os ressuscitar.
Uma linha para iniciar os dois servidores de uma vez:
./scripts/dev.sh
make build # → frontend/dist
cd backend && uv run uvicorn app.main:app --port 8000
# open http://localhost:8000
Servir ambos a partir de uma única origem é a configuração mais fiel, porque os vetores de cache/ETag dependem de cache HTTP real de mesma origem.
make test # backend pytest (server-side vector logic + observation log)
make build # frontend production build
Os testes do backend exercitam os vetores do lado do servidor e o log de observação. O comportamento do navegador ainda precisa de um navegador real para ser verificado, porque vários vetores dependem de armazenamento de origem, Service Workers e cache HTTP.
Esta é uma ferramenta defensiva / de conscientização. Diretrizes incorporadas ao design:
Mantenha qualquer fork no mesmo espírito: use-o para ensinar às pessoas como o rastreamento funciona para que possam se defender, não para rastreá-las secretamente.
MIT — veja LICENSE.