大家好,我是Echa。
最近小编一直在关注谷歌官方浏览器 Chrome,就在前段时间谷歌 Chrome 团队正式发布了六年磨一剑的WebGPU,借助现代 GPU 的计算能力来加速图形和计算并且允许在 Web 上进行高性能 3D 图形和数据并行计算。当时业界圈内一片哗然——重磅!谷歌正式发布 WebGPU
这次谷歌 Chrome 又接二连三的发布了Chrome 113、114 两个版本,都有提到关于 Cookie 的访问方式变化:
Chrome 113:Cookie 第一方集(First-Party Sets)进入稳定版本;
Chrome 114:Cookie 独立分区(CHIPS)默认对所有浏览器启用;
为啥小编特意截上面两张Chrome 官方的图出来,因为这两个都是针对 Cookie 访问方式的大调整,为的就是应对即将来临的三方 Cookie 全面弃用。Chrome 在两年前就已经计划全面弃用方 Cookie 了,因为这个变化对现在的网站影响太大了,如果直接弃用,可能会导致大量网站的正常功能无法正常使用。
另外对 Google 本身的广告业务也有非常大的影响,所以 Chrome 不得不一拖再拖,为的就是能够推出一套对现有的业务影响不是很大,能够保障用户平稳迁移,又能保护用户隐私的方案。
目前看来,随着 Cookie 第一方集、Cookie 独立分区两项能力的稳定推出,全面禁用三方 Cookie 的那一天似乎不远了,这两项改动确实能够解决一大部分正常使用三方 Cookie 的业务场景,但是 Cookie 的读取方式可能要有大调整了。
今天小编就带着大家来提前解读一下这两项关于 Cookie 的大调整,大家也要提前做好迁移和应对策略,保障未来禁用三方 Cookie 之后网站能够避免受到影响。
首先了解Cookie如何产生、Cookie 分类、Cookie用途、Cookie生命周期
Cookie的生命周期有两种,一种是整个会话的,一种是永久的。也就是说,一种是临时性的Cookie,用户关掉浏览器,这个Cookie也就失效了。一种是永久的Cookie,可以持续存在的。一般网站分析工具 判断Unique Visitor使用的是后者。
千言万语,不如一张完整的图讲解:
第一方和第三方Cookie的区别
Cookie 是属于一方 Cookie、还是三方 Cookie,只取决于两个要素:
- Cookie 是被哪个域名种的
- Cookie 是在哪个网站上种的
第一方Cookie和第三方Cookie,都是网站在客户端上存放的一小块数据。他们都由某个域存放,只能被这个域访问。他们的区别其实并不是技术上的区别,而是使用方式上的区别。
比如,访问www.douyin.com这个网站,这个网站通过set-cookie 这个 Header设置了一个Cookie,这个Cookie也只能被www.douyin.com 这个域下的网页读取,这就是第一方Cookie。
如果还是访问www.douyin.com这个网站,网页里有用到bytedance.com网站的一张图片,浏览器在向 bytedance.com请求图片的时候,bytedance.com通过set-cookie 这个 Header 设置了一个Cookie,那这个Cookie只能被bytedance.com这个域访问,反而不能被 www.douyin.com这个域访问,因为对我们来说,我们实际是在访问www.douyin.com这个网站被设置了一个bytedance.com个域下的Cookie,所以叫第三方Cookie。
第一方Cookie的优势和应用
第一方Cookie的最大优势是接受率高。一般主流的浏览器的都会有隐私的设置,可以让用户设置是否接受Cookie,接受哪些Cookie。
除了 完全不接受Cookie这个设置以外,其他情况下,第一方Cookie都是会被用户接受的(不接受的话,是没办法把那小块数据保存下来的)。
所以,如果没有特殊要求,使用第一方Cookie会比第三方Cookie,我们通过分析工具得到的数据会更准确。
三方Cookie的优势和应用
第三方Cookie的接受率不如第一方Cookie(不过主流的浏览器默认的设置下也接受带P3P协议的第三方Cookie,我的经验是接受率能达到90%,甚至95%以上),但在某些特定情况下可以实现第一方Cookie无法实现的功能。
比如,当我们有多个域名的网站需要跟踪,我们希望了解到用户 点击某个广告到达域名A下的网页,然后可能浏览了不论那个域名下的页面,最后在域名B下的网页完成注册的情况。广告可以在域名A下的网页被跟踪到,而注册 可以在域名B下的网页跟踪到。
如果我们使用第一方Cookie,会为域名A建立一个Cookie,为域名B再建立一个Cookie,他们可以关联各自域名 下网页上的行为,但是无法关联起来。而使用第三方Cookie,那么无论多少个域,都只有一个Cookie,一个属于第三方域的Cookie,网站下所有域都能共享这个Cookie,那么所有的行为都能被关联起来分析。
三方 Cookie 有啥问题?
我们的网站不可能只调用同站的域名的接口,调用其他域名的接口再正常不过了,所以有三方 Cookie 也是很正常的,我们也通过三方 Cookie 做了很多正常的需求,比如日志打点、单点登录、广告转化分析等等。那为什么要禁用呢?主要还是因为用户隐私的问题。
比如我们现在正在抖音上刷视频,但是抖音上往往会加载很多三方广告商的请求,这些三方广告商就可以通过三方 Cookie 来记录一些用户的行为。然后下次你逛淘宝的时候,也可能再次加载到这个广告商,因为这时三方广告已经通过三方 Cookie 记录了你的很多用户行为,已经知道了你喜欢什么东西,所以你就会收到一些精准的广告推送,无形之中你的隐私已经泄漏出去了。
在海外,用户隐私可是相当ZZ正确的事,所以 Safira、Firefox 两大浏览器已经迫于压力禁用了三方 Cookie,也就是说,如果你在这两个浏览器上去访问 www.douyin.com 这个网站,那么再发送 bytedance.com 这个域名的请求是种不上 Cookie 的。
目前就剩下 Chrome 还在苦苦支撑了,毕竟 Chrome 现在的浏览器市场份额是最大的,而且直接禁用对它的老板 Google 的广告业务影响也非常大。所以 Chrome 需要等待一个大家都可接受的替代方案出来之后再禁用。
为了增加网络隐私,浏览器供应商正在计划或已经对跨站点跟踪进行限制。这包括逐步取消对第三方cookie的支持,即向顶级文档网站以外的网站发送请求的cookie,因为此类cookie使服务器能够跟踪用户在不同顶级网站上的行为。
在cookie之前:浏览器访问green.com,它有一个嵌入的red.com框架,可以设置cookie。当浏览器导航到blue.com时,red.com框架可以访问green.com上设置的cookie。
两个可能遇到问题的场景
对于我们普通开发者来说,其实还是有很多场景可能会受到影响的,我们也必须在禁用之前作出相应的改变,比如下面两个场景。
三方 iframe Cookie
第一个场景是我们需要和嵌入的三方 iframe 共享状态。假如我们现在开发了一个通用的聊天服务,它的域名是 support.chat.example,我们有很多业务网站(比如 retail.example) 希望用 iframe 的方式嵌入这个聊天框。这个嵌入式的聊天服务可能会依赖 Cookie 来保存用户的交互历史记录。因为我们嵌入的 iframe 域名和当前的网站是夸站的,所以 iframe 种下的 Cookie 就属于三方 Cookie。
假如现在没有了设置跨站点三方 Cookie 的能力,那我们的聊天服务 support.chat.example 可能需要更依赖父级网站 retail.example 主动传递给他们第一方会话的一些标识符。因为这种聊天服务往往都是通用的,所以相应的每个嵌入 support.chat.example 聊天服务的网站都需要额外的设置来传递状态,这大大增加了开发和接入成本。
或者,我们也可以允许聊天服务 support.chat.example 请求我们的网站 retail.example 页面上的 JavaScript。但是这又引入了非常大的安全风险,也不是个靠谱的方法。类似可能遇到的场景还包括:
- 三方地图服务
- 子资源 CDN 负载均衡
- Headless CMS 提供商
- 不信任的用户内容的沙盒域名
- 三方嵌入式广告
三方站点 Cookie
另外还有一个场景,根据域名的不同来定义 Cookie 属于第三方有点太狭隘了,毕竟一个公司不可能只有一个域名:
比如上面我们提到的 www.douyin.com 和 www.bytedance.com ,虽然域名不一样,种的 Cookie 也叫做三方 Cookie,但是明眼人都能看出来,抖音就是字节的,这俩域名就是一家的。
如果禁用了三方 Cookie ,那这种正常的在一家公司不同域名下共享 Cookie 的能力也就不能用了,这给正常的业务需求会带来很大的影响,一个常见的场景就是单点登录,我们往往在登陆一家公司的不同网站的时候只需要登录一次,这是因为用户的个人信息存储在了一个公共的登录服务的 Cookie 上,禁用了三方 Cookie,那登录信息也就无法共享了。下面我们来看看如何解决以上的两个问题。
Cookie 独立分区(CHIPS)
首先我们来看 Chrome 114 默认对所有用户启用的 Cookie 独立分区(CHIPS),这就是用来解决三方 iframe 共享状态的问题的。
如何解决问题?
具有独立分区状态的 Cookie (CHIPS) ,它允许开发者将 Cookie 选择到“分区”存储中,每个顶级站点都有单独的 Cookie jar。
Chrome 官方是这样描述它的:CHIPS 是帮助服务顺利过渡到没有第三方 Cookie 的未来的重要一步。
CHIPS 引入了一个新的 Cookie 属性:Partitioned ,它可以让顶级上下文分决定哪些 Cookie 进行分区。
举个例子,假如我们在站点 A 中通过 iframe 嵌入了一个站点 C,正常情况下如果三方 Cookie 被禁用后,C 是无法在 A 站点访问到它的 Cookie 的。
如果 C 在它的 Cookie 上指定了 Partitioned 属性,这个 Cookie 将保存在一个特殊的分区 jar 中。它只会在站点 A 中通过 iframe 嵌入站点 C 时才会生效,浏览器会判定只会在顶级站点为 A 时才发送该 Cookie。
当用户访问一个新站点时,例如站点 B,如果也它通过 iframe 嵌入了站点 C,这时在站点 B 下的站点 C 是无法访问到之前在 A 下面设置的那个 Cookie 的。
如果用户直接访问站点 C ,一样也是访问不到这个 Cookie 的。
这样就在保障用户隐私的情况下解决了三方 iframe Cookie 共享的问题。
如何使用?
实施方式也非常简单,就像上面说的,想要在当前网站上保留需要共享的三方 Cookie ,只需要在种这个 Cookie 的时候添加一个 Partitioned 属性,另外还有个前提是 Cookie 必须具有 Secure 属性:
Set-Cookie: name=ConardLi; SameSite=None; Secure; Path=/; Partitioned;
实现细节
Partitioned 属性实际上是改变了 Cookie 存储分区的机制,让分区更加严格了,还是上面的例子,我们将一个 https://support.chat.example iframe 嵌入在页面 https://retail.example 上,在启用 Partitioned 之前,Cookie 分区的唯一标识是:support.chat.example ,而启用了Partitioned之后,分区的唯一标识变成了 ("https", "retail.example") + support.chat.example。
Firefox 在它的 ETP 严格模式和隐私浏览模式下默认对所有第三方 cookie 进行了分区,所以所有的跨站 cookie 都会默认按照顶级站点进行分区。但是,在没有第三方选择加入的情况下对 cookie 进行分区可能会导致一些意外的问题,因为在某些特定场景下可能也会用到未分区的第三方 cookie。
Safari 之前也曾尝试过一些 Cookie 分区的机制,但最终还是放弃了,目前完全阻止了三方 Cookie,理由之一是开发者可能会感到困惑。。不过目前好像又开始做一些 Cookie 分区的实验了。
目前我觉得 Chrome 提供的这种启发式 Cookie 分区的思路还挺好用的,既解决了跨站跟踪的问题,而且也能在一定程度上满足用户需求,希望其他浏览器也借鉴一下吧。
Cookie 第一方集(First-Party Sets)
上面我们解决了三方 iframe 状态共享的问题,下面我们提到的 Cookie First-Party Sets 则是用来解决自定义 Cookie 集合的问题,也就是说提供了一种选择性的把一些 Cookie 从三方变为一方的方式。
如何解决问题?
前面我们提到了,很多组织或公司都会有多个域名,所以只用域名的不同来区分 Cookie 属于第一方还是第三方这种方式太严格了。
First-Party Sets 相当于给了网站开发者一个机会,有一些 Cookie 虽然根据域名的划分是第三方的,但是你可以自己选择指定一部分 Cookie 把它们放在一个集合里,在这个集合里的三方 Cookie 都可以按照一种特殊的形式来读取到。
换个角度讲,douyin.com、bytedance.com 这两个域名虽然是属于同一个组织,但是 Chrome 不知道,你可以通过把它们放到一个集合里来告诉 Chrome 这些不同的域名属于同一个组织。
如何使用?
根据上面的解决问题的思路,想要实现 First-Party Sets 就需要两步:
- 第一步:把想要共享 Cookie 的不同域名放到一个集合里,然后提交给 Chrome;
- 第二步:使用 Chrome 提供的特殊的方式来读取这些域名集合下共享的 Cookie;
在早期的提案中,为 Cookie 新增了一个 samePaty 属性,你可以通过这个属性来告诉浏览器哪些 Cookie 是需要三方共享的,然后需要把共享的域名集合放到网站的部署目录下。
但是,这种方式的限制有点过于宽松了,网站可以很轻松的再次实现三方 Cookie 共享,共享的策略也不够透明,所以 Chrome 决定弃用了这种方案,转而实现了一种更复杂的方式。
首先你需要给出一份 JSON 文件,在这个文件里声明哪些域名是需要共享 Cookie 的,然后你需要把这个 JSON 文件通过 Pull Request 提交到 Chrome 提供的一个 Github 仓库中:https://github.com/GoogleChrome/first-party-sets
而且要求 JSON 文件的格式必须符合规范,下面是一个例子:
{
"primary": "https://primary.com",
"associatedSites": ["https://associate1.com", "https://associate2.com", "https://associate3.com", "https://associate4.com"],
"serviceSites": ["https://servicesite1.com"],
"rationaleBySite": {
"https://associate1.com": "An explanation of how you clearly present the affiliation across domains to users and why users would expect your domains to be affiliated",
"https://associate2.com": "An explanation of how you clearly present the affiliation across domains to users and why users would expect your domains to be affiliated",
"https://associate3.com": "An explanation of how you clearly present the affiliation across domains to users and why users would expect your domains to be affiliated",
"https://serviceSite1.com": "An explanation of how each domain in this subset supports functionality or security needs."
},
"ccTLDs": {
"https://associate1.com": ["https://associate1.ca", "https://associate1.co.uk", "https://associate1.de"],
"https://associate2.com": ["https://associate2.ru", "https://associate2.co.kr", "https://associate2.fr"],
"https://primary.com": ["https://primary.co.uk"]
}
}
在这其中有几个关键的概念:
- ccTLDs 域名:网站可能服务于不同的国家,在每个地区都有一个特定的域名,比如 conardli.cn、conardli.jp、conardli.en 等等;
- Service 域名:网站可能会使用特定的域名来保证安全性或者提高性能,但是这些不同域名的网站可能也需要共享用户身份。
- Associated 域名:同一个组织下可能有多个不同的子品牌,对应不同的域名,例如 bytedance.com、douyin.com 就属于这种情况。
提交完 PR 之后,Google 团队会在每个周二的中午 12 点手动 Review 并且合并这些 PR。(这里我也不知道 Chrome 团队是咋想的。。。后面网站多了之后肯定每天都有大量的 PR,这种维护方式真的可行么??)
等到你的 JSON 配置被 Chrome 团队 Merge 后,也不是就代表着你可以随意在这些域名下共享三方 Cookie 了,你还需要用到一个特殊的 Storage Access API(SAA) ,下面是一份演示代码:
https://glitch.com/edit/#!/first-party-sets
我们来拆解一下,首先是判断浏览器是否支持这个 API:
/*
* 通过 UA 判断浏览器版本
*/
if (navigator.userAgentData.brands.some(b => { return b.brand === 'Google Chrome' && parseInt(b.version, 10) >= 108 })) {
// Supported
} else {
// Not supported
}
/*
* 判断 SAA 和 rSAFor API 是否可用
*/
if ('requestStorageAccess' in document) {
// SAA available
} else {
// SAA not available
}
if ('requestStorageAccessForOrigin' in document) {
// rSAFor available
} else {
// rSAFor not available
}
通过 requestStorageAccess 来判断用户是否授予了对三方 Cookie 的访问权限,并且访问所有可以读取到的 Cookie:
if ('requestStorageAccess' in document) {
document.requestStorageAccess().then(
(res) => { console.log('权限请求通过', res) },
(err) => { console.log('拒绝', err) }
);
}
通过 requestStorageAccessForOrigin 来读取指定域名下共享的的三方 Cookie:
if ('requestStorageAccessForOrigin' in document) {
document.requestStorageAccessForOrigin('https://first-party-sets.glitch.me');
location.reload();
} else {
window.alert('document.requestStorageAccessForOrigin not enabled.');
}
最后
一台电脑,一个键盘,尽情挥洒智慧的人生;几行数字,几个字母,认真编写生活的美好;
一 个灵感,一段程序,推动科技进步,促进社会发展。