State Partitioning

State Partitioning is a broad effort to rework how Firefox manages client-side state (i.e., data stored in the browser) to mitigate the ability of websites to abuse state for cross-site tracking. This effort aims to achieve that by providing what is effectively a "different", isolated storage location to every website a user visits. This article gives an overview of the mechanism, lists the affected APIs and explains how to debug affected sites.

State Partitioning is currently turned on by default in the Firefox Nightly channel. A subset of the state partitioning efforts (namely network partitioning) has been enabled by default in the release channel of Firefox since version 85.

Motivation

Cross-site tracking using shared state

Browsers traditionally key client-side state by the origin (or sometimes registrable domain) of the location a resource was loaded from. For example, the cookies, localStorage objects, and caches available to an iframe loaded from https://example.com/hello.html will be keyed by example.com. This is true regardless of whether the browser is currently loading resources from that domain as a first-party resources or as an embedded third party resources. Trackers have taken advantage of this cross-site state to store user identifiers and access them across websites. The example below shows how example.com can use its cross-site state (in this instance, cookies) to track a user across its own site as well as A.example and B.example.

An example of cross-site state

Past approaches to blocking cross-site tracking

Firefox's past cookie policies attempt to mitigate tracking by blocking access to some storage APIs (e.g., cookies and localStorage) for certain domains under certain conditions. For example, our "block all third-party cookies" policy will prevent all domains from accessing certain storage APIs when loaded in a third-party context. Our current default cookie policy blocks access in a third-party context only for domains classified as trackers.

State Partitioning

State Partitioning is a different approach to preventing cross-site tracking. Rather than block access to certain stateful APIs in a third-party context, Firefox provides embedded resources with a separate storage bucket for every top-level website. More specifically, Firefox double-keys all client-side state by the origin of the resource being loaded and by the top-level site. In most instances, the top-level site is the scheme and eTLD+1 of the top-level page being visited by the user.

In the example below example.com is embedded in A.example and B.example. However, since storage is partitioned, there are three distinct storage buckets (instead of one). The tracker can still access storage, but since every storage bucket is additionally keyed under the top-level site, the data it has access to on A will be different than the data on B. This will prevent a tracker from storing an identifier in their cookies when visited directly and then retrieving that identifier when embedded in other websites.

An example of state partitioning

Standardization

The Privacy Community Group has a Work Item for Client-Side Storage Partitioning. This serves as an overview of the standardization efforts for storage partitioning in the individual standards affected. We intend to align our state partitioning implementation with these efforts as the Work Item is standardized.

Status of partitioning in Firefox

Network Partitioning Enabled by default for all users since Firefox 85.
Dynamic State Partitioning Enabled by default in Firefox Nightly.
Since Firefox 86: Enabled for users that have "Strict" privacy protections enabled.

Network Partitioning

Networking-related APIs are not intended to be used for websites to store data, but they can be abused for cross-site tracking. As such, the following network APIs and caches are permanently partitioned by the top-level site.

Note: Network Partitioning is permanent. Websites can't control or relax these restrictions.

Partitioned APIs

  • HTTP Cache
  • Image Cache
  • Favicon Cache
  • Connection Pooling
  • Stylesheet Cache
  • DNS
  • HTTP Authentication
  • Alt-Svc
  • Speculative Connections
  • Fonts & Font Cache
  • HSTS
  • OCSP
  • Intermediate CA Cache
  • TLS Client Certificates
  • TLS Session Identifiers
  • Prefetch
  • Preconnect
  • CORS-preflight Cache
  • WebRTC deviceID

Dynamic Partitioning

To prevent cross-site tracking via JavaScript accessible storage APIs, Firefox partitions them for third-parties by top-level site. As opposed to Network Partitioning this boundary is dynamic and storage access to the embedders context maybe be granted in certain circumstances.

Firefox implements the StorageAccessAPI to allow frames to request access to the parent storage. Access to top-level storage may also be granted automatically in specific scenarios. You can read more about these heuristics here.

Partitioned APIs

Service Workers are currently disabled in partitioned contexts when dynamic partitioning is enabled. In Bug 1495241 we are exploring options to enable Service Workers in partitioned contexts.

Storage Access Heuristics

To improve web compatibility, Firefox currently includes some heuristics to grant unpartitioned storage access automatically to third parties that receive user interaction. These heuristics are intended to allow some third-party integrations that are common on the web to continue to function.

Warning: Storage access heuristics are a transitional feature meant to prevent website breakage. They should not be relied upon for current and future web development.

Opener Heuristics
  • When a partitioned third-party opens a pop-up window that has opener access to the originating document, the third-party is granted storage access to its embedder for 30 days.
  • When a first-party a.example opens a third-party pop-up b.example, b.example is granted third-party storage access to a.example for 30 days.

Note: For third-parties which abuse these heuristic for tracking purposes, we may require user interaction with the popup before storage access is granted.

Redirect Heuristics
  • If a site b.example redirects to a.example, then b.example receives storage access to its embedder a.example if both a.example and b.example have been visited and interacted with within the last 10 minutes. This storage access will be granted for 15 minutes.
  • If a tracker tracker.example (as classified by the Enhanced Tracking Protection) redirects to a non-tracker a.example and tracker.example received user interaction as a first-party within the last 45 days, tracker.example is granted storage access to a.example for 15 minutes.

Storage Access API

Third-party frames may use document.requestStorageAccess to request unpartitioned storage access through the StorageAccessAPI. Once granted, the requesting third-party will gain access to its first-party storage bucket (i.e., the storage it would have access to if visited as a first-party). Any calls to dynamically partitioned APIs, for example localStorage, will be made in context of the first-party bucket.

Warning: When storage access is granted there may still be references to the partitioned storage. However, sites shouldn't rely on being able to use partitioned and unpartitioned storage at the same time.

Debugging

We encourage site owners to test their sites, particularly those that rely on third-party content integrations. There are several features in Firefox to make testing easier.

Logging

Here is an overview of the messages logged to the web console when interacting with storage in a third-party context. In the following examples, a.example is the top-level site which embeds the third-party frame b.example.

Reason Console Message
Storage of a third-party frame is partitioned Partitioned cookie or storage access was provided to “b.example” because it is loaded in the third-party context and storage partitioning is enabled.
Storage access is granted through a heuristic Storage access automatically granted for First-Party isolation “b.example” on “a.example”.
Storage access is granted via the StorageAccessAPI Storage access granted for origin “b.example” on “a.example”.

Clear Third-Party Storage-Access

If a third-party iframe is granted storage access to the parent context, Firefox sets a permission. To revoke access you can clear the permission via the Site Information Panel in the permissions section under "Cross-site Cookies".

Test Preferences

Warning: Make sure to set these prefs in a separate Firefox profile or reset them after testing.

Disable Heuristics

The following prefs can be used to disable individual storage access heuristics via the config editor:

  • Enable / disable the redirect heuristics: privacy.restrict3rdpartystorage.heuristic.recently_visited, privacy.restrict3rdpartystorage.heuristic.redirect
  • Enable / disable the window open heuristics: privacy.restrict3rdpartystorage.heuristic.window_open, privacy.restrict3rdpartystorage.heuristic.opened_window_after_interaction
Disable Network Partitioning

Network partitioning can be disabled with the privacy.partition.network_state pref.

Disable Dynamic State Partitioning

To disable dynamic storage partitioning for all sites you can use the network.cookie.cookieBehavior pref:

Value Description
5 Reject (known) trackers and partition third-party storage.
4 Only reject trackers (Storage partitioning disabled).
0 Allow all
Exempt specific origins from partitioning

Dynamic State Partitioning can also be disabled for specific origins with the privacy.restrict3rdpartystorage.skip_list preference. This pref holds a comma separated list of origins to exempt. The pref value should follow the following format first-party_origin_1,third-party_origin_1;first-party_origin_2,third-party_origin_2;....

For example, to disable partitioning for tracker.example on example.com and for social.example on news.example, you would set the pref to the following:

 https://tracker.example,http://example.com;https://social.example,https://news.example