逐个拆解Safari智能防跟踪(ITP)的工作机制:跟踪域名分类、7天存储上限、第三方Cookie拦截、Referrer裁剪,以及它拦不住的那些追踪手段。
「Safari会拦截跟踪器吗?」这个问题的简短回答是:会;而更长的回答其实更有用。智能防跟踪(Intelligent Tracking Prevention,ITP)并不是一个单独的开关,而是WebKit里一组彼此独立的机制,每一项针对的都是把标识符从一个站点带到另一个站点的不同途径:给具备跟踪能力的域名打标签的分类器、对第三方Cookie的彻底拦截、对脚本能保留数据多久的上限、对Referrer的裁剪,等等。本文逐个拆解,并对每一项都问同样的三个问题:它做了什么,跟踪者会失去什么,普通网站又会失去什么?
核心要点
- ITP是一整套机制,而不是一项功能。 根据WebKit的Tracking Prevention文档,它综合了第三方Cookie拦截、Referrer降级、设备端的跟踪器分类、存储清除和有效期上限。
- 「7天限制」针对的是脚本写入的存储。 如果用户在7天内没有与某个网站发生交互,WebKit就会删除该网站中由JavaScript创建的Cookie,以及
localStorage、IndexedDB、sessionStorage、媒体密钥,还有Service Worker的注册信息和缓存。 - 第三方Cookie被一律拦截。 WebKit明确表示没有例外;只有通过Storage Access API(以及一项针对弹窗的临时兼容性修复)才能获得访问权限。
- ITP只是基于状态的防御。 它清除的是已存储的标识符和共享存储。它不会阻止网站收集自己访客的数据,它也不是反指纹系统——WebKit是通过另一组独立的改动来应对指纹的。
- 在iOS上,它覆盖所有浏览器。 由于iPhone上的所有浏览器都用WebKit渲染,ITP的行为并不是只有选择Safari才能得到的——参见为什么iPhone上的每个浏览器底层都是Safari。
ITP的起点,以及为什么文档页很重要
WebKit在2017年6月推出了ITP。John Wilander撰写的原始公告Intelligent Tracking Prevention,把它定位为通过「进一步限制Cookie和其他网站数据」来减少跨站跟踪,而它建立在一个早已存在的默认做法之上:从Safari 1.0起,WebKit就不允许尚无Cookie的第三方设置新Cookie。
此后,最初的设计已经发生了变化。在2017年的版本里,被分类的域名如果在最近24小时内与用户有过交互,仍可在第三方场景下使用自己的Cookie;如果交互发生在最近30天内,Cookie会保留,但以分区形式存在。而当前的WebKit文档则把第三方Cookie拦截描述为彻底拦截。这也是为什么按时间顺序梳理版本历史并不是学习ITP的好办法——它很快就会过时。持续维护的权威参考是WebKit的Tracking Prevention页面,本文接下来也以这个页面为准。
机制一:给具备跟踪能力的域名分类
它做了什么。 ITP会收集资源加载的统计数据,并与已知的跨站跟踪模式进行比对。如果某个可注册域名符合某种模式,就会被归类为具备跨站跟踪能力。机器学习模型会查看三个数字:该域名作为第三方子资源出现在多少个不同的站点上,作为第三方iframe出现在多少个站点上,以及它在多少个站点下执行过跨站重定向。WebKit在2017年的公告中表示,所有数据收集和分类都在设备端完成。
还有两种模式会带来同样的标签。反复出现的顶层框架重定向(即反弹追踪)也会计入,即便重定向被延迟了几秒钟。另外,跟踪者串通会让标签扩散:一旦某个域名被归类,此前曾重定向到它的每一个域名也会被归类,并沿着重定向图递归下去。
跟踪者会失去什么。 被归类的域名,其全部网站数据都会被删除,除非它在最近30天的浏览器使用时间内,作为第一方获得过用户交互,或者获得过存储访问授权。一个只在后台出现的域名永远得不到这种交互,所以它什么也留不下来。
普通网站会失去什么。 只要看起来不像跟踪者,就什么也不会失去。你真正使用的网站会获得交互记录,这就是豁免条件。代价落在那些用户很少直接访问的正当嵌入式服务身上——一个你从来不会在独立标签页里打开的小组件提供商,可能被误判为跟踪者。
机制二:彻底拦截第三方Cookie
它做了什么。 自Safari 1.0起,WebKit的默认Cookie策略就是:除非第三方已经拥有Cookie,否则不允许它设置新的Cookie。ITP则更进一步:默认拦截所有第三方Cookie,没有例外。另有两条相关规则堵住了旁路。锁存模式(latch mode)意味着,一旦某个请求被禁止使用Cookie,该请求的所有重定向也会被禁止。此外,第三方HSTS也被拦截:它只能由第一方网站为其自己的主机和可注册域名设置。
跟踪者会失去什么。 最经典的机制是:投放在许多网站上的广告或分析域名,在每个网站上都读取同一个Cookie。在ITP下,这个Cookie根本不会被发送,于是跟踪者每次看到的都是一个陌生人。
普通网站会失去什么。 任何依赖共享第三方Cookie的嵌入式服务:单点登录frame、能认出已登录用户的嵌入式评论系统、支付小组件。它们必须明确申请访问权限(见机制六)。
机制三:为脚本写入的存储设上限
它做了什么。 对于在第一方上下文中由JavaScript创建的存储,有两项上限,因为以第一方脚本身份运行的跟踪器,一直把标识符存放在那里:
- 7天。 如果用户在7天内没有与网站发生交互,ITP会删除所有由JavaScript创建的Cookie,以及所有其他可由脚本写入的存储。WebKit列出了受影响的存储:IndexedDB、LocalStorage、媒体密钥、SessionStorage,以及Service Worker的注册信息和缓存。
- 链接装饰为24小时。 有些跟踪器会把「点击ID」作为URL参数附加上去,再在落地页用脚本取走。ITP能检测到这种模式,并把该落地页上由JavaScript创建的Cookie的有效期限制为24小时。
计时依据的是用户的交互——点击、轻触或按键;WebKit说明,滚动不算——而不是从创建起算的日历时间。每隔几天就用一次的网站,其数据会一直保留。
跟踪者会失去什么。 第三方脚本写进页面自身存储里的那个长期第一方标识符。任何隔了一周以上才回来的访客,在它看来都是新访客。
普通网站会失去什么。 任何存放在客户端、需要在一周不访问的情况下依然保留的东西:由JavaScript设置的「记住我」标记、存在localStorage里的草稿、偏好设置Cookie。需要持久状态的网站,应当改为存放在服务器端,或者通过服务器响应来设置。WebKit的页面还指出,主屏幕Web应用不受7天上限的限制,并且与Safari自身的数据保持隔离。
机制四:Referrer降级
它做了什么。 默认情况下,所有第三方Referrer都会被裁剪到只剩来源(origin),HTTP的Referer请求头和document.referrer都是如此。WebKit给出的例子是:完整的Referrer https://www.social.example/feed?clickID=123456,最终呈现为https://www.social.example/。
跟踪者会失去什么。 路径和查询字符串。通过Referrer传递的点击ID或文章URL不会再到达目标站点;到达的只有它来自哪个站点。
普通网站会失去什么。 细粒度的来源分析。网站依然能看到是哪个来源把访客带来的,但看不到该来源上具体是哪个页面,也看不到营销活动参数。
机制五:针对重定向和反弹追踪的对策
它做了什么。 反弹追踪会让你短暂经过跟踪者的域名,使其以第一方身份运行,从而读取自己的Cookie。ITP按域名统计顶层框架的重定向次数,并把结果输入机制一中的分类器。对于已获得用户交互或存储访问授权、却被发现在做反弹的已分类域名,WebKit表示其Cookie可能会被改写为SameSite=strict——这样它们就不会再随跨站导航发送。Cookie拦截的锁存模式(机制二)则覆盖了重定向链。
针对CNAME伪装也有相关对策:当一个看起来像第一方的子域名实际上解析到第三方跟踪器时,ITP会把HTTP响应中设置的Cookie的有效期限制为7天。WebKit对第三方IP地址伪装也采用同样的上限。技术本身请参阅我们的CNAME伪装详解。
跟踪者会失去什么。 借助经过自己域名的短暂重定向变成第一方并取回自己Cookie的能力。
普通网站会失去什么。 基于重定向的正当流程,例如单点登录的跳转或短链接服务,看起来可能像反弹。交互豁免会保护用户实际使用过的服务提供方。技术本身请参阅反弹追踪解析。
机制六:Storage Access API,官方认可的例外通道
它做了什么。 ITP的拦截会破坏正当的嵌入式服务,所以WebKit增加了例外:第三方frame可以通过Storage Access API申请访问它自己的第一方Cookie,通常需要响应一次用户手势。MDN把这套API记录为document.hasStorageAccess()和document.requestStorageAccess(),授权范围限定在特定的顶层站点与嵌入站点这一对组合上。当前的行为,以及各浏览器提示方式的差异,请参阅MDN的Storage Access API参考。
WebKit的文档指出,获得存储访问授权是使已分类域名免于被删除数据的两个条件之一(另一个是第一方用户交互)。
跟踪者会失去什么。 悄无声息地获得访问权限的能力。它必须在具体情境中、在一次真实交互之后提出申请,而用户或浏览器可以拒绝。
普通网站会失去什么。 少许的操作摩擦:原本悄悄就能工作的嵌入内容,现在需要一次点击和一次API调用。
底层的分区机制
除了上述六项机制,WebKit的文档还描述了一层分区机制:第三方LocalStorage和IndexedDB按第一方网站分区,并且是临时性的;第三方Service Worker连同它的缓存和IndexedDB一起分区;第三方内容的HTTP缓存条目也按第一方网站分区。为被归类为跟踪器的域名创建的缓存条目,还会被标记为需要验证:七天之后,缓存命中会被当作未命中,资源会被重新加载并做比对,如果两次响应不同,该条目就会被丢弃——这是针对ETag这类基于缓存的标识符的防御。其总体思路参见存储分区详解。
ITP做不到什么
这一节是多数文章埋得很深的内容,所以这里直接说清楚。
- 它不会阻止第一方数据收集。 ITP针对的是跨站跟踪。网站依然可以认出自己的回头客,记录他们的行为,并在自己的HTTP响应中设置Cookie。上述上限适用于脚本写入的存储;WebKit文档并没有把服务器设置的普通第一方Cookie列入受影响的存储(CNAME伪装的情况是例外)。
- 它不会阻止指纹识别。 指纹是根据浏览器和硬件信号计算出来的,不存储任何东西,所以ITP没有什么可删除、可限制或可分区的。想了解其中的原理,请阅读我们的浏览器指纹识别指南,或者运行指纹检测,看看你自己的浏览器暴露了什么。
- 它不会让链接装饰变得无害。 一旦检测到点击ID,ITP会限制落地页上脚本写入的Cookie的存活时间,但如果服务器在请求中收到了点击ID,依然可以把它记录下来。
- 它不能替代声明机制。 Do Not Track请求头只是客客气气地请求网站;ITP则是强制执行。WebKit甚至移除了自己的DNT标志,因为它「被用作了指纹识别的向量」。参见DNT为何失败。
ITP与指纹是不同的子系统
有两件事很容易被混为一谈,而WebKit是把它们分开的。ITP管的是状态:Cookie、存储、Referrer、缓存和重定向。反指纹则是另一组改动,列在同一份文档页面的单独章节里:Device Orientation/Motion API需要获得权限,限制WebRTC透露的已连接摄像头和麦克风信息,把字体可用范围限制为网络字体和系统字体,在营销版本之间冻结用户代理(user-agent)字符串,移除macOS上的插件支持,并拒绝实现Web Bluetooth、Web MIDI和Battery Status API等功能。
两者的目标不同,失效的方式也不同。ITP击败的是跟踪者存储下来的标识符;反指纹则是缩减跟踪者计算标识符时可用的区分信号的数量。Safari推出的每一项基于状态的防御,都让无状态的路线对仍想做跨站关联的跟踪者相对更有价值——这就是为什么一个由浏览器信号构建的持久访客ID,能比上述所有机制都活得更久。
常见问题
Safari会拦截跟踪器吗?
会,而且同时通过多种方式:它拦截第三方Cookie,裁剪第三方Referrer,给具备跟踪能力的域名分类并删除其数据,还限制脚本写入的存储能保留多久。但它并不会拦截所有跟踪——第一方收集和指纹识别依然存在。
ITP的7天Cookie限制是什么?
这是对可由脚本写入的存储的一项上限。如果用户在7天内没有与某个网站发生交互,WebKit就会删除该网站中由JavaScript创建的Cookie,以及localStorage和IndexedDB等其他可由脚本写入的存储。与该网站交互一次,计时就会重置。
ITP适用于iPhone上的Chrome或Firefox吗?
适用,因为在iOS上这些应用都用WebKit渲染——不过在某些地区,具体情况正在发生变化,详见为什么iPhone上的每个浏览器底层都是Safari。ITP的行为是引擎的属性,而不是Safari这个品牌的属性。
我可以关闭ITP吗?
WebKit的文档把默认Cookie策略与Safari的「阻止跨站跟踪」设置联系在一起。把它关掉会让跨站跟踪更容易,而且很少是修复嵌入内容失效的正确办法;官方认可的途径是Storage Access API。
ITP能阻止浏览器指纹识别吗?
不能。ITP关注的是已存储的状态。指纹识别不存储任何东西,而WebKit单独采取的反指纹措施,只是减少了构建指纹可用的信息,并不能将其消除。
总结
ITP之所以有效,是因为它不依赖某一个绝招。分类通过行为找出跟踪者,Cookie拦截撤掉了跨站共享的Cookie,存储上限缩短了脚本能保留的时间,Referrer裁剪去掉了URL中的细节,而Storage Access API则为正当的嵌入内容留下了一条可见的、需要手势触发的回路。同样重要的是它没有触碰的东西:网站自己对自己访客的记录,以及任何靠计算而非存储得来的标识符。如果你想亲眼看看第二类,请在Safari中运行指纹检测,再与另一个浏览器对比一下。
推荐阅读:

