无Cookie追踪独立访客
速览
该技术旨在替代传统的Cookie-based用户追踪方式,通过设备指纹或其他匿名标识实现独立访客统计。它能在保护用户隐私的同时,为网站提供准确的流量分析。这对于因Cookie逐步被淘汰而受影响的数字营销和数据分析行业具有重要意义。
AI 深度解读
背景
网络分析工具要统计“唯一访客”数量,本质上是一个身份识别问题:如何判断两次请求来自同一个人。过去25年,答案一直是Cookie——设置一个随机ID,之后每次请求都能读取。但这个方案如今面临重重障碍:ePrivacy指令要求用户同意、浏览器(Safari、Firefox)主动封禁第三方Cookie,甚至第一方Cookie在Safari ITP(智能防跟踪)下也只能存活7天。同时,用户和监管机构对设备端存储和指纹识别愈发警惕。因此,业界开始探索无Cookie的身份追踪方案。
核心内容
原文梳理了识别唯一访客的完整技术菜单,从经典Cookie到服务器端哈希,逐一分析其准确性与隐私代价。
策略1:Cookie
第一方Cookie仍可技术实现,但受ePrivacy规则限制,必须征得同意才能存储信息到用户设备。即便获得同意,Safari的ITP将脚本设置的Cookie有效期限制为7天,导致“两年稳定身份”对大量流量实际上变成一周。
// 经典第一方分析Cookie(类GA)
let id = readCookie("_uid");
if (!id) {
id = crypto.randomUUID();
document.cookie = `_uid=${id}; Max-Age=63072000; SameSite=Lax; Path=/`;
}
策略2:localStorage
一些人试图绕过Cookie规则,将ID存到localStorage、sessionStorage、IndexedDB,甚至利用ETag缓存等技术。但ePrivacy指令第5(3)条覆盖的是“在用户设备上存储信息或获取已存储信息”,从未专指Cookie。因此,换存储API而不改同意流程,只是合规漏洞。
策略3:指纹识别
若能存储ID,就让浏览器本身成为ID——通过组合User-Agent、语言、屏幕尺寸、Canvas绘图差异、音频处理器差异等生成唯一哈希。这种做法最黑暗:持久(用户无法清除从未存储的东西)、对用户不可见,且研究显示许多网站恰好在用户拒绝Cookie后使用它。监管机构将其纳入ePrivacy管辖,浏览器(Safari、Firefox)则主动模糊相关API。任何声称“无Cookie唯一访客”却依赖指纹库的分析工具,只是用更差的视角重建了问题。
策略4:服务器端衍生ID
既不存储也不读取用户设备,仅利用HTTP请求自带的信息:IP地址和User-Agent。将二者哈希,同一人产生相同值(除非IP或浏览器改变)。但原始方式等同于服务器端指纹——产生持久假名ID。隐私优先工具的共同演进方案是让哈希过期,Margin正属于这一家族。
策略5:放弃身份
有些工具干脆不统计唯一访客,仅统计页面浏览量、来源和基于启发式的“会话”(30分钟间隔重置),无需任何身份。这是最隐私、最诚实的选项,但“多少人访问”通常是分析工具最常被问的问题,因此大多数工具不会止步于此。
行业的技巧:过期哈希
所有严肃的无Cookie分析工具收敛到同一思路:从服务器已看到的信息衍生访客ID,并将ID的作用域限定为单日,使其无法成为跟踪ID。
- Plausible:计算
hash(daily_salt + domain + ip + user_agent)。盐是一个随机值,每24小时轮换一次,旧盐被删除。昨天的ID无法关联到今天,攻击者和Plausible自身都无法做到。 - Fathom:对IP、User-Agent、主机名和站点范围盐进行SHA-256哈希,哈希后立即丢弃原始IP。
- GoatCounter:将
site + IP + User-Agent → 随机ID的映射在内存中保持最多8小时,仅持久化随机ID。
// Plausible风格方案伪代码
const salt = await saltStore.today(); // 随机128+位,24小时轮换,旧值永久删除
const visitorId = sha256(`${salt}${domain}${ip}${userAgent}`);
// 存储visitorId;绝不存储ip或userAgent
共同特性:
- 同一人在同一日内产生相同ID,日唯一数准确。
- 输入(IP、User-Agent)从不存储,仅存储衍生ID。
- ID随日过期,无持久性数据可用于构建行为画像。
注意:需要维护一个单一的盐存储(saltStore)来生成盐、分发给所有执行哈希的服务器,并在一天后可靠销毁。
Margin的计算方式
Margin的哈希逻辑如下(在接收请求的处理函数中运行):
const day = new Date().toISOString().slice(0, 10);
const digest = await crypto.subtle.digest(
"SHA-256",
new TextEncoder().encode(`${day}:${site}:${ip}:${userAgent}`),
);
// 取前16字节,十六进制编码
与Plausible等同属一系,但有一个架构差异改变了信任模型:运行位置。
Margin没有第三方事件端点。SDK将接收路由挂载到你的应用上,因此浏览器直接与你的域名通信,访客哈希在你的服务器上计算,仅你的基础设施看到原始请求。传递给Margin API的只有截断后的哈希值,原始IP和User-Agent从未离开你的栈。
浏览器 ── POST /api/margin (你的应用)
│ 从 ip + ua 衍生访客哈希
└──> Margin API (仅哈希值 + 组织密钥)
对于托管脚本+端点的工具,“我们哈希并丢弃访客IP”是一个需要你信任的承诺,因为它们的服务器必然看到原始请求。在Margin模型里,这一跳无需信任:供应商根本收不到识别输入。
需要诚实的部分
Margin使用日期而不是随机每日盐。这是一个有意的权衡,且带来代价。
随机盐的作用是使哈希不可重新计算。没有盐,任何人只要拥有哈希值并能枚举可能的输入,就可以进行成员测试(例如“IP X 和 User-Agent Y 是否在本日访问过此站点?”)。使用日期作为盐意味着输入集有限(每日IP、User-Agent组合可枚举),攻击者若获得哈希数据库,可以反向推测哪些用户访问过。Plausible的每日随机盐正是为了防止这种攻击。
Margin选择日期而非随机盐,是为了避免维护一个中央化的盐存储(saltStore)——对于每个自托管实例,管理跨服务器的盐轮换和删除会增加运维复杂度。这是一个明确的准确性与隐私保障之间的权衡:日期哈希仍能阻止跨日关联(因为不同日期产生不同哈希),但不具备抵抗枚举攻击的能力。原文称“trade-offs are real and mostly under-advertised”,Margin在文档中坦诚了这一成本。
关键要点
- 无Cookie不仅是技术问题,更是合规和隐私问题:ePrivacy指令覆盖所有设备端存储(cookie、LocalStorage、IndexedDB等),换存储API不解决同意要求。
- 指纹识别是黑暗角落:它持久、不可清除、对用户隐形,监管和浏览器双重打压,不是真正的“无Cookie”方案。
- 过期哈希是行业共识方案:利用服务器天然可见的IP+User-Agent,通过每日轮换盐(或日期)使ID过期,实现准确且隐私保护的唯一访客统计。
- 信任模型至关重要:托管工具要求用户信任其“哈希后丢弃”的承诺;自托管或代理架构(如Margin)让识别数据始终留在用户基础设施内,供应商无需接触原始IP/User-Agent。
- 日期 vs 随机盐的权衡:日期作为盐省去中心化盐存储的运维,但失去抵抗枚举攻击的能力;Plausible的随机盐提供更强匿名保护,但需管理盐轮换。
- 每日唯一数是准确但有限的:同日内的跨页面访问可准确归因,跨日用户无法关联,因此无法计算长期留存或归因窗口——这正是隐私工具主动放弃的能力。
意义与影响
-
推动分析工具转向隐私优先架构:过期哈希方案被Plausible、Fathom、GoatCounter、Margin等广泛采用,标志着行业从“尽可能追踪”转向“最小化数据留存”。这符合GDPR、ePrivacy等法规精神,也响应了浏览器(Safari ITP、Chrome Privacy Sandbox)对跨站跟踪的限制。
-
**重新
