2025年如何可靠地检测第三方Cookie阻止

网络正在逐步告别第三方Cookie,这项曾经被广泛依赖的技术正在走向终结。Cookie最初在1994年由网景公司引入,用于支持虚拟购物车等功能,长期以来一直是网络功能的基础。然而,出于隐私和安全考虑,业界正在努力彻底淘汰它们。

各大浏览器(Chrome、Safari、Firefox和Edge)都在逐步淘汰第三方Cookie,尽管这个过程是渐进的。虽然这一变化增强了用户隐私,但也破坏了依赖第三方Cookie的合法功能,比如单点登录(SSO)、欺诈防护和嵌入式服务。

为什么Cookie检测仍然重要

理想情况下,我们应该完全放弃第三方Cookie,尽快使用隐私优先的替代方案重新设计集成。但现实中,这种迁移可能需要数月甚至数年时间,特别是对于遗留系统或第三方供应商。与此同时,用户已经在使用禁用第三方Cookie的浏览器,但往往不知道有功能缺失。

想象一个旅行预订平台,它嵌入一个来自第三方合作伙伴的iframe来显示实时火车或航班时刻表。这个嵌入式服务使用自己域名上的Cookie来验证用户身份并个性化内容,比如显示保存的行程或会员奖励。但当浏览器阻止第三方Cookie时,iframe无法访问这些数据,用户看到的不是流畅的体验,而是错误页面、空白屏幕或无效的登录提示。

检测第三方Cookie阻止不仅是良好的技术实践,更是用户体验的前线防御。

为什么检测第三方Cookie阻止如此困难

检测第三方Cookie是否被支持并不像调用navigator.cookieEnabled那么简单。即使是这样看似安全的检查,也无法告诉你真正需要知道的信息:

// 这样做无法检测第三方Cookie阻止
function areCookiesEnabled() {
    if (navigator.cookieEnabled === false) {
        return false;
    }
    try {
        document.cookie = "test_cookie=1; SameSite=None; Secure";
        const hasCookie = document.cookie.includes("test_cookie=1");
        document.cookie = "test_cookie=; Max-Age=0; SameSite=None; Secure";
        return hasCookie;
    } catch (e) {
        return false;
    }
}

这个函数只能确认Cookie在当前(第一方)上下文中有效,对于第三方场景(比如另一个域名上的iframe)却一无所知。更糟糕的是,它具有误导性:在某些浏览器中,即使Cookie被阻止,navigator.cookieEnabled在第三方iframe中仍可能返回true

现代浏览器如何处理第三方Cookie

Safari:完全阻止第三方Cookie

自版本13.1起,Safari默认阻止所有第三方Cookie,没有例外,即使用户之前与嵌入域有过交互。对于需要Cookie访问的嵌入内容(如SSO iframe),Safari提供了存储访问API,需要用户手势才能授予存储权限。

Firefox:按设计分区Cookie

Firefox的总Cookie保护按站点隔离Cookie。第三方Cookie仍然可以设置和读取,但按顶级站点分区,这意味着同一第三方在不同站点上的Cookie是分开存储的,无法共享。

Chrome:从弃用计划到隐私沙盒

基于Chromium的浏览器默认仍允许第三方Cookie,但情况正在改变。从Chrome 80开始,第三方Cookie必须显式标记为SameSite=None; Secure,否则会被拒绝。

Google原计划在2022年淘汰第三方Cookie,但时间表多次更新。2024年7月,Google明确表示没有计划单方面弃用第三方Cookie,而是转向用户选择界面,让用户决定是否全局阻止或允许第三方Cookie。

Edge:基于追踪器的阻止

Edge(基于Chromium)与Chrome共享对第三方Cookie的处理方式,并引入了追踪预防模式:基本、平衡(默认)和严格。在平衡模式下,它会阻止已知的第三方追踪器,但允许许多未被归类为追踪器的第三方Cookie。

检测技术概览

基本JavaScript API检查(误导性)

如前所述,navigator.cookieEnabled或在主页面上设置document.cookie无法反映跨站点Cookie状态。这些检查仅适用于第一方,应避免用于检测。

服务器辅助Cookie探测(重量级)

经典方法包括通过HTTP从第三方域设置Cookie,然后检查是否返回。这种方法有效,但需要自定义服务器端逻辑,增加开发和基础设施复杂性。

存储访问API(补充信号)

document.hasStorageAccess()方法允许嵌入的第三方内容检查是否有权访问未分区的Cookie。这个API在检测Cookie是否存在但被分区的场景中特别有用,但目前最好用作补充信号,而不是独立检查。

iframe + postMessage(最佳实践)

尽管存在存储访问API,但这仍然是最可靠和浏览器兼容的方法:

  1. 嵌入来自第三方域的隐藏iframe
  2. 在iframe内尝试设置测试Cookie
  3. 使用window.postMessage向父页面报告成功或失败

逐步实现:通过iframe检测第三方Cookie

步骤1:创建Cookie测试页面

在第三方域上创建一个简单的HTML页面(例如:https://cookietest.example.com/cookie-check.html):

<!DOCTYPE html>
<html>
<body>
<script>
    document.cookie = "thirdparty_test=1; SameSite=None; Secure; Path=/;";
    const cookieFound = document.cookie.includes("thirdparty_test=1");
    
    const sendResult = (status) => window.parent?.postMessage(status, "*");
    
    if (cookieFound && document.hasStorageAccess instanceof Function) {
        document.hasStorageAccess().then((hasAccess) => {
            sendResult(hasAccess ? "TP_COOKIE_SUPPORTED" : "TP_COOKIE_BLOCKED");
        }).catch(() => sendResult("TP_COOKIE_BLOCKED"));
    } else {
        sendResult(cookieFound ? "TP_COOKIE_SUPPORTED" : "TP_COOKIE_BLOCKED");
    }
</script>
</body>
</html>

步骤2:嵌入iframe并监听结果

在主页面上:

function checkThirdPartyCookies() {
    return new Promise((resolve) => {
        const iframe = document.createElement('iframe');
        iframe.style.display = 'none';
        iframe.src = "https://cookietest.example.com/cookie-check.html";
        document.body.appendChild(iframe);
        
        let resolved = false;
        
        const cleanup = (result, timedOut = false) => {
            if (resolved) return;
            resolved = true;
            window.removeEventListener('message', onMessage);
            iframe.remove();
            resolve({ thirdPartyCookiesEnabled: result, timedOut });
        };
        
        const onMessage = (event) => {
            if (["TP_COOKIE_SUPPORTED", "TP_COOKIE_BLOCKED"].includes(event.data)) {
                cleanup(event.data === "TP_COOKIE_SUPPORTED", false);
            }
        };
        
        window.addEventListener('message', onMessage);
        setTimeout(() => cleanup(false, true), 1000);
    });
}

步骤3:使用存储访问API增强检测

在Safari中,即使第三方Cookie被阻止,用户也可以通过存储访问API手动授予访问权限,但只能响应用户手势。

第三方Cookie被阻止时的回退策略

基于重定向的流程

对于身份验证相关流程,从嵌入iframe转换为顶级重定向。让用户直接在身份提供商的站点上进行身份验证,然后重定向回来。

请求存储访问

在明确的UI手势后使用requestStorageAccess()提示用户(Safari需要这样做)。

基于令牌的通信

通过以下方式直接从父页面向iframe传递会话信息:

  • postMessage(需要正确的origin)
  • 查询参数(例如,iframe URL中的签名JWT)

分区Cookie(CHIPS)

Chrome(自版本114起)和其他基于Chromium的浏览器现在支持带有Partitioned属性的Cookie,允许按顶级站点进行Cookie隔离。

总结

第三方Cookie正在消失,虽然过程是渐进和不均匀的。在转换完成之前,作为开发者,你的工作是在技术限制和真实用户体验之间架起桥梁。这意味着:

  1. 关注标准:FedCM和隐私沙盒功能正在重塑我们如何处理身份和分析,而不依赖跨站点Cookie。
  2. 结合检测与优雅回退:无论是提供重定向流程、使用requestStorageAccess(),还是回退到基于令牌的消息传递,每一个小的UX改进都会累积。
  3. 告知用户:用户不应该被留在那里想知道为什么某个功能在一个浏览器中工作,但在另一个浏览器中无声地失败。

使用htmlpage:强大的HTML在线构建器,免费在线快速创建网页:https://htmlpage.cn/builder,支持源码导出!