容器标签页隔离的是Cookie和网站存储,不是你的设备。本文讲清楚哪些信息被隔离、哪些保持不变,以及哪些追踪手段依然能跨容器认出你。
Firefox 正在把容器标签页整合进浏览器本身——曾经需要安装 Multi-Account Containers 扩展才能实现的功能,如今正变成一项原生选项。这正是把「容器到底做了什么」讲清楚的好时机,因为大多数人心里的那套认知模型,在一个要紧的地方是错的:容器是一个独立的Cookie 罐,不是一个独立的浏览器。下文的一切都建立在这一个区别之上——如果读者假设的是别的东西,就会把容器当成它从未被设计来提供的保护。
核心要点
- 容器是一个独立的 Cookie 罐,不是一个独立的浏览器实例——MDN 的
contextualIdentities参考文档写得很直白:「每个身份都会获得一个不与其他标签页共享的 Cookie 存储区。」在 Firefox 上,这种隔离也一并延伸到站点的其余存储。 - 存储层以下的一切都是共享的:你的 IP 地址、TLS/HTTP/2 握手特征、Canvas/WebGL/音频输出、已安装字体、屏幕参数和时区,在同一浏览器的每个容器里都完全相同。
- 基于指纹的追踪器看到的是同一个访客,而不是两个——在依赖 Cookie 识别身份的网站眼里像是两个不同身份的容器,一旦网站改用指纹识别而非依赖存储,就会立刻被合并回同一个画像。
- 容器确实能阻止基于 Cookie 关联的跨站身份识别:依赖共享 Cookie 罐的登录状态探测和基于重定向的追踪,一旦 Cookie 罐被拆分隔离,就失去了赖以生存的基础。
- 它们只是一整个隔离方案家族中的一员——隐私窗口、独立浏览器配置文件、VPN 各自隔离的是不同的层,而搞混一个工具究竟覆盖了哪一层,正是人们对自己防护过度自信的最常见原因。
容器到底隔离了什么
Firefox 的「情境身份」(contextual identities)功能——Multi-Account Containers 背后的机制,如今也是原生容器背后的机制——会为每个标签页分配一个容器身份,并把站点存储按这个身份来划分。MDN 的 contextualIdentities API 参考文档对存储这一半写得很精确:「在内部,每个身份都会获得一个不与其他标签页共享的 Cookie 存储区」,并用 cookieStoreId 来寻址。在 Firefox 中,容器 id 会随「源属性」(origin attributes)一起附在存储请求上,因此实际被拆开的并不只有 Cookie——localStorage、IndexedDB 以及站点的其余存储,同样会按容器落进不同的桶里。
在「工作」容器和「个人」容器里分别打开同一个网站,网站看到的是两个完全独立的存储桶——一个容器里设置的 Cookie 不会泄露到另一个,一个容器里开始的登录会话也不会带到另一个容器。
有一点必须和上面区分开:Firefox 还会沿着另一条完全不同的轴来分区状态。MDN 的状态分区指南描述的是浏览器如何「按被加载资源的源(origin)和顶层站点(top-level site)对所有客户端状态做双重键控」——覆盖存储类 API(localStorage、sessionStorage、IndexedDB、Service Worker)和网络状态(HTTP 缓存、图片缓存、DNS、TLS 会话标识符、HSTS)。那份文档讲的是跨站隔离,键是地址栏里的那个站点,它完全没有提到容器。在 Firefox 上这两套机制是同时生效的,而且谁也替代不了谁:一套阻止追踪者跨站跟着你走,另一套阻止你自己的几个身份互相看见。
但无论走哪条轴,这两套机制都止步于存储层。它们是真实、有用的边界——同时也是全部的边界。它们都不涉及浏览器在设备或网络层面暴露出的任何信息。
每个容器里保持不变的是什么
这一部分是 Firefox 的公告里没有细讲的,也是读者最容易自行脑补出错误答案的地方。容器分区完全只作用于存储层。任何来自「你的浏览器和连接如何表现」而非「网站存了什么」的信号,都完全不受影响:
- 你的 IP 地址和网络路径——容器不会改变流量的路由方式,也不会改变服务器看到你的连接是从哪里来的。
- TLS 与 HTTP/2 握手特征——无论请求由哪个容器发起,发出去的协商顺序和参数都是一样的。
- Canvas、WebGL 与音频输出——每个容器里都是同一块 GPU 渲染出同样的像素、同一个音频上下文产生同样的波形,因为底层是同一套硬件和驱动栈。
- 已安装字体与屏幕几何参数——是实时从操作系统和显示器读取的,不属于容器能够限定作用域的任何东西。
- 时区与语言设置——直接来自操作系统配置,在每个标签页里都完全相同。
把这些信号组合起来,就是一份浏览器指纹——而指纹根本不关心请求是哪个容器发出的。如果一个网站是靠指纹而不是靠读取 Cookie 来识别访客,同一台机器上的两个容器会产生完全相同的指纹,被合并成同一个被追踪的身份,无论你把它们的 Cookie 罐分得多干净都无济于事。我们在浏览器指纹熵与匿名集详解一文中讲过,哪怕完全不涉及 Cookie,只需要极少数这类信号,就足以让一台设备变得独一无二、可被唯一识别。不想只是听信文字,想亲眼验证一下?在两个不同的容器里打开同一个网页,分别运行 BrowserInsight 的指纹检测——你会看到两次得到的哈希值完全一致。如果不一致,那也是某个反指纹模式在给 Canvas 之类的信号按站点加噪声,而不是容器边界起了作用。
容器与其他隔离方案的对比
容器只是浏览器隔离工具这个小家族里的一员,而这些工具各自隔离的其实是完全不同的层。把它们搞混,正是大多数「过度信任」发生的地方。
| 隔离方案 | 被分开的是什么 | 仍然共享的是什么 |
|---|---|---|
| 容器标签页 | 按情境身份分开的 Cookie 与站点存储 | 设备/网络指纹、IP 地址——也就是上一节提到的一切 |
| 隐私/无痕窗口 | 一个随窗口关闭而清空的临时存储罐 | 设备/网络指纹;窗口本身往往可以通过独立的存储配额行为被识别为隐私模式 |
| 独立浏览器配置文件 | Cookie、存储、扩展与浏览器级设置 | 依然是同一个 IP 地址,也依然是同一套底层硬件指纹 |
| VPN 或代理 | 你的网络路径,以及服务器观察到的 IP | 浏览器侧的一切信号——Cookie、指纹,网络层之上的所有东西 |
把这张表整体看下来,规律很清楚:没有任何一个工具能同时覆盖不止一行。容器加上 VPN,才是同时处理了两个真正不同的层,这才更接近人们以为「光靠容器标签页」就能提供的那种保护。
容器真正起作用的地方
这些都不意味着容器没用——它们恰恰划定了容器真正的价值所在。容器专门对付的是依赖共享 Cookie 罐的那类追踪,而这确实是有实际意义的一整个追踪类别。
跨站登录检测——网站通过探测与你现有会话 Cookie 绑定的计时、错误事件或重定向行为,来推断你还登录了哪些其他服务——一旦这些会话分别存在于不同容器里,就立刻失去了赖以判断的信号。如果你在某个容器里根本没有登录某项服务,也就不存在可供探测的共享 Cookie 状态。
反弹追踪失效的原因在结构上是一样的。它通过重定向让追踪者自己的域名短暂变成第一方,借机植入或读取一个基于 Cookie 的标识符——而这种标识符恰恰就是情境身份会分开保存的那种按容器区分的存储,所以它没办法把一个容器里的访问和另一个容器里的访问关联起来。对这两种追踪而言,把你的身份拆进不同的 Cookie 罐,正好去掉了它们赖以运作的那个机制本身。
容器边界之外仍会泄露的信息
基于 Cookie 的追踪并不是网站能够依赖的唯一一种存储,也不是所有能持久保存状态的机制,作用域划分方式都和 Cookie 一样。ETag 与缓存超级 Cookie把标识符藏在普通的 HTTP 缓存重新验证响应头里,而不是 Cookie 存储里。
在这里,上面那两套机制的方向并不一致。HTTP 缓存正在状态分区文档所列的、Firefox 会永久按顶层站点键控的网络状态之中,因此这套把戏的跨站版本无论有没有容器都已经被堵死。但两份 MDN 文档都没有对跨容器的那一版说过任何话——某个具体浏览器和版本究竟如何按情境身份划分 HTTP 缓存的作用域,根本不像 Cookie 隔离那样是一条写进文档的保证。稳妥的假设是:容器边界对 Cookie 以及 MDN 所描述的那些存储是经过验证的,而对其他任何东西,在你用自己实际使用的浏览器核实之前,都不能视为已被证明。
容器是身份分隔工具,不是匿名工具
老实说,Firefox 公告里没有明说、但其实隐含的结论是:容器做的是把你在同一台设备上的多个身份彼此隔开——一个工作账号的登录状态永远看不到个人账号的 Cookie,一次购物会话不会把广告再营销状态带进一个毫不相关的标签页。这是身份分隔(compartmentalization),而它对这个目的来说,确实非常有用。
它不是用来躲避一个正在盯着你看的网站的匿名工具。一个靠读取 Cookie 识别访客的网站,会在你的各个容器里看到彼此独立的访客;一个靠指纹识别的网站,看到的只是同一个人。如果你正在考虑要不要把这份工作交给一个浏览器扩展来做,我们的浏览器扩展隐私风险一文讨论了一个更根本的问题:无论旁边挂着哪种内置隔离功能,一款已安装的软件本身能看到什么。把这两个目标在脑子里分清楚,容器就会恰好做到它承诺的事——不多,也不少。
常见问题
容器标签页能隐藏我的指纹吗?
不能。容器标签页按情境身份对 Cookie 和站点存储做分区,但对你的 IP 地址、TLS 握手特征、Canvas/WebGL 输出、字体、屏幕参数或时区都没有任何影响。这些信号在同一浏览器的每个容器里都完全相同,而它们恰恰就是指纹的原材料。
网站能看出我在用容器吗?
并没有哪个面向网页的 API 会主动宣告这件事:contextualIdentities 是给扩展用的 WebExtensions API,你访问的网站根本调用不到。网站真正能看到的是结果——一个空的 Cookie 罐——而这跟一个刚清空了 Cookie 的访客看起来是一样的。问题在于「存储是空的、指纹却眼熟」本身也是一种模式,这正是为什么容器的设计目标是让各个容器之间无法通过存储彼此关联,而不是隐藏这项功能本身的存在。
Firefox 把容器变成原生功能,会改变它隔离的内容吗?
不会。Firefox 153 中的原生容器把 Multi-Account Containers 的功能整合进了浏览器本身,但底层机制——也就是 contextualIdentities 一直描述的那套情境身份存储分区——并没有改变。无论用哪种方式实现,本文描述的这条隔离边界都是同一条。
容器和隐私/无痕窗口是一回事吗?
不一样。隐私窗口用的是一个随窗口关闭而清空的临时存储罐;容器给你的则是多个并排运行、彼此分开的持久存储罐。隐私窗口还有一些自己特有的可被检测的怪癖——参见网站如何检测隐身与无痕浏览模式——这些完全不适用于容器。
已经用了容器,还需要 VPN 吗?
它们解决的是两个不同的问题。容器通过隔离存储,把你在同一台设备上的各个身份彼此分开;VPN 改变的是服务器看到的网络路径和 IP 地址,而这是容器完全碰不到的部分。两者互不能替代——容器覆盖不了的网络侧那一半,可以参见 BrowserInsight 的 VPN/代理检测。


