一个教育性演示,展示网站如何持续识别你——以及为什么“清除 cookie”已经不够了。
ubercookie 将单个随机 id 同时植入 12 种不同的浏览器存储载体。每次你访问时,它都会读取所有载体、进行共识判断,并将该 id 重新写回所有位置。清除任意一个存储——甚至清除全部 cookie——幸存者也会悄悄地将它复活。该网站会用通俗的语言告诉你,你的 id 藏在哪些地方,以及它识别出你的浏览器的次数。
这与 Samy Kamkar 经典的 evercookie 背后的理念相同——在此构建为一个开放、透明的教学工具,专注于存储复活与超级 cookie 持久化。
[!IMPORTANT] 本项目故意跟踪访问者,目的是提高意识。它仅限第一方,只存储随机 id、访问次数、首次/最后访问时间戳和恢复来源标签,不与第三方共享任何数据,并提供一个真正的 “Forget me” 按钮。不要将其改用来在他人不知情或未经同意的情况下跟踪他们——那与本项目的初衷背道而驰。参见伦理。
| 存储载体 | 类型 | 需要 JS? | 可从 JS 清除? | 教学要点 |
|---|---|---|---|---|
document.cookie | 客户端 | 是 | 是 | 最基础的跟踪器 |
localStorage | 客户端 | 是 | 是 | 清除 cookie 后依然存活 |
sessionStorage | 客户端 | 是 | 是 | 按标签页的冗余 |
IndexedDB | 客户端 | 是 | 是 | 一个人们忘记清除的完整数据库 |
Cache API(caches) | 客户端 | 是 | 是 | 可编程存储,独立于上述各项 |
window.name | 客户端 | 是 | 是 | 在页面导航间保持 |
| OPFS(源私有文件系统) | 客户端 | 是 | 是 | 手动清理会遗漏的沙盒文件系统 |
| Service Worker + Cache | 客户端 | 是 | 是 | 后台脚本重新提供 id,即使离线亦然 |
服务器 cookie(HttpOnly) | 服务器 | 否 | 通过服务器 | 对 JS 不可见,仍随每次请求发送 |
| ETag 超级 cookie | 服务器 | 否 | 仅清除缓存 | id 通过 If-None-Match 回显 |
| Last-Modified 超级 cookie | 服务器 | 否 | 仅清除缓存 | id 编码在缓存资源的日期中 |
| HTTP 缓存(嵌入 id 的脚本) | 服务器 | 否 | 仅清除缓存 | id 固化在一个 immutable 缓存文件中 |
除此之外,页面还会向浏览器申请持久化存储(navigator.storage.persist()),使 IndexedDB / Cache / Service Worker / OPFS 中的副本免于被自动逐出——让它们更难被摆脱。
三个基于缓存的载体是持久化的关键所在:它们存放在浏览器的 HTTP 缓存中,因此 JavaScript(包括我们自己的“Forget me”按钮)无法删除它们——只有清除浏览器缓存才能做到。id 正是这样死而复生的。
关于已实现存储载体的完整说明,以及仍然适用于本项目的 HSTS 超级 cookie 构想,见 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
一次访问的工作流程(frontend/src/ubercookie/index.js):
HttpOnly cookie。需要 Python ≥ 3.11(配合 uv)和 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)
打开 **http://localhost:5173**,亲眼看着自己被跟踪。打开 DevTools,删除某些存储,点击 Re-scan,然后看着它们复活。
同时启动两个服务器的一行命令:
./scripts/dev.sh
make build # → frontend/dist
cd backend && uv run uvicorn app.main:app --port 8000
# open http://localhost:8000
从同一源提供两者是最贴近真实环境的部署方式,因为 cache/ETag 载体依赖真实的同源 HTTP 缓存。
make test # backend pytest (server-side vector logic + observation log)
make build # frontend production build
后端测试覆盖服务器端载体和观察日志。浏览器行为仍需使用真实浏览器验证,因为多个载体依赖源存储、Service Worker 和 HTTP 缓存。
这是一个防御性 / 意识提升工具。设计内置了以下准则:
请让任何分支保持同样的精神:用它来教人们了解跟踪的工作原理,以便他们保护自己,而不是暗中跟踪他们。
MIT —— 见 LICENSE。