Third-party Cookie 被禁用后前端身份认证与跟踪方案实战

小珂簪 安全 阅读 2,624
赞 18 收藏
二维码
手机扫码查看
反馈

谁更灵活?谁更省事?Third-party Cookie替代方案实战对比

我去年在做一个广告投放效果归因系统时,被Third-party Cookie的消失干懵了。Chrome 125一开,默认禁用第三方 Cookie,我们原来靠 iframe + document.cookie 同步用户 ID 的老路子直接崩了——页面里嵌了个 jztheme.com 的统计脚本,结果 document.cookie 读出来是空的,连 sameSite=Lax 都救不了它。不是报错,是静默失效。那一刻我盯着控制台发了两分钟呆,然后决定:必须把目前主流的几个替代方案亲手试一遍,不是看文档,是真跑通、真测跨域、真压测并发、真上线灰度。

Third-party Cookie 被禁用后前端身份认证与跟踪方案实战

以下是我亲测过的四种方案:Storage Access API、First-party Set、Cookie 前缀(__Host- / __Secure-)、以及服务端中转(Token Proxy)。没提 “FLoC” 或 “Topics API”,那玩意儿我试了三天,发现 Chrome Canary 里根本没触发,文档写得像玄学,果断跳过。

Storage Access API:最“合规”,但最折腾

这是 Chrome 官方力推的方案,核心就一句话:**用户必须主动交互(比如点按钮)后,你才能申请访问第三方 Storage**。

代码不难写,但坑特别多:

  • 必须在用户手势上下文(如 click、touchend)里调用,setTimeout(() => requestStorageAccess(), 0) 直接报错
  • iframe 必须带 allow="storage-access-api" 属性,漏一个字符都不行
  • 用户拒绝一次后,再调用会直接 resolve false,不会弹二次确认框——这点我踩了三次坑才意识到

实操代码长这样(jztheme.com 是第三方统计域名):

<iframe
  src="https://jztheme.com/tracker.html"
  allow="storage-access-api"
  id="tracker-iframe">
</iframe>
// 在用户点击后触发
document.getElementById('consent-btn').addEventListener('click', async () => {
  const iframe = document.getElementById('tracker-iframe');
  try {
    await iframe.contentWindow.document.requestStorageAccess();
    // ✅ 成功!现在可以读写 cookie / localStorage
    console.log('Storage access granted');
  } catch (err) {
    console.warn('Storage access denied or not supported', err);
  }
});

我比较喜欢用这个方案做“高价值用户路径”的归因(比如下单页),因为合规性最高,Safari 和 Firefox 也都支持(虽然 Safari 行为略有差异)。但它不适合埋点类场景——总不能让用户每刷一次页面都点一下“允许追踪”吧?太反人类。

First-party Set:Chrome 115+ 新宠,我最近主力切它

这个我真香了。原理简单粗暴:让第三方域名(jztheme.com)通过 Set-Cookie 响应头,把 cookie 写到你的主站域名(比如 yoursite.com)下。关键在于响应头要带 Partitioned 标志。

服务端(Node.js Express 示例):

app.get('/api/track', (req, res) => {
  res.cookie('tp_id', 'u_abc123', {
    domain: '.yoursite.com', // 注意是主站域名,且带点前缀
    path: '/',
    httpOnly: true,
    secure: true,
    sameSite: 'None',
    partitioned: true // 👈 这个是核心!
  });
  res.json({ ok: true });
});

前端只需要 fetch 一下就行:

// 在 yoursite.com 页面里发起
fetch('https://jztheme.com/api/track', {
  credentials: 'include'
});

效果是:cookie 最终存在 yoursite.com 下,而不是 jztheme.com,所以完全不受 Third-party Cookie 限制。我上线后跑了两周,iOS 17.4+、Chrome 115+、Edge 116+ 全部 OK,连 Safari 技术预览版都支持。唯一小问题是:Firefox 尚未实现 partitioned,但我在 header 里加了 fallback 逻辑,检测到不支持就退到服务端中转,影响不大。

我一般选 First-party Set 做默认方案,尤其适合广告归因、用户身份同步这类需要稳定 ID 的场景。它不像 Storage Access API 那样依赖用户操作,也不像服务端中转那样增加 RTT 延迟。

Cookie 前缀(__Host- / __Secure-):修修补补,聊胜于无

这其实是强化 First-party Cookie 的写法,不是真正解决 Third-party 场景,但我见过不少团队把它当救命稻草来用——比如把原来 Set-Cookie: user_id=xxx; domain=jztheme.com 改成 Set-Cookie: __Host-user_id=xxx; Secure; HttpOnly; SameSite=None,然后祈祷浏览器网开一面。

实话讲:没用。Chrome 125 之后,只要 domain 不匹配当前页面 origin,前缀再规范也白搭。我试过,document.cookie 依然为空。它只对第一方 Cookie 更安全,对第三方问题零帮助。如果你还在用这个“绕过”第三方限制,赶紧停手,别浪费时间了。

服务端中转(Token Proxy):最稳,但最重

就是前端不直接跟 jztheme.com 通信,所有请求走你自己的后端中转:

// 前端发给自己的 API
fetch('/api/proxy/track', {
  method: 'POST',
  body: JSON.stringify({ event: 'view', page: '/home' })
});
// 后端 Node.js(Express)
app.post('/api/proxy/track', async (req, res) => {
  const { event, page } = req.body;
  // 👇 这里带上你自己的 session / cookie,服务端发起请求
  const resp = await fetch('https://jztheme.com/api/track', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({ event, page, user_id: req.session.userId })
  });
  res.json(await resp.json());
});

优点?100% 兼容,不挑浏览器,还能加签名、限流、审计日志。缺点?延迟翻倍,你得维护额外的服务,CDN 缓存全废,QPS 上去后容易成瓶颈。我上个项目用了三个月,最后还是切到了 First-party Set —— 毕竟移动端首屏加载慢 200ms,PM 能跟你聊到凌晨两点。

我的选型逻辑

看场景,我一般选:

  • 需要强用户标识、且主站和第三方都能改服务端 → First-party Set(partitioned),写一次,跑一年
  • 纯前端项目、没法改后端、又必须立刻上线 → Storage Access API + 手动 consent 弹窗,丑是丑了点,但合规
  • 老 IE 还要兼容、或者老板说“先保住现有数据再说” → 服务端中转,别折腾,先活下来
  • Cookie 前缀?删掉,别留着骗自己

没有银弹。Third-party Cookie 死了,但需求没死。我们不是在找“替代品”,是在找“当下能用、明年还不用大改”的务实解法。我上周刚把一个客户项目从服务端中转全量切到 First-party Set,灰度期间监控了七天,没发现 ID 断裂或重复,松了口气。

以上是我踩坑后的总结,希望对你有帮助。有更优的实现方式欢迎评论区交流——尤其是 Safari 下 First-party Set 的兼容细节,我还在跟苹果文档较劲 😅

本文章不代表JZTHEME立场,仅为作者个人观点 / 研究心得 / 经验分享,旨在交流探讨,供读者参考。
发表评论

暂无评论