Skip to content
forked from privacycg/CHIPS

A proposal for a cookie attribute to partition cross-site cookies by top-level site

Notifications You must be signed in to change notification settings

ericlaw1979/CHIPS

 
 

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

7 Commits
 
 
 
 

Repository files navigation

CHIPS (Cookies Having Independent Partitioned State)

Editors

Participate

Table of Contents

Motivation

In order to increase privacy on the web, browser vendors are either planning or already shipping restrictions on cross-site tracking. This includes phasing out support for third-party cookies, cookies sent in requests to sites other than the top-level document's site, since such cookies enable servers to track users' behavior across different top-level sites.

Before CHIPS third parties have access to unpartitioned cookies across top-level sites.


Before CHIPS: A browser visits green.com which has an embedded red.com frame that sets a cookie. When the browser navigates to blue.com, the red.com frame can access the cookie set at green.com.

Although third-party cookies have the unfortunate consequence of enabling sites to track user behavior across different top-level sites, there are also use cases on the web today where cross-domain subresources require some notion of session or persistent state. Some examples of such use cases are SaaS providers, headless CMS providers, and sandbox domains for serving untrusted user content, e.g. googleusercontent.com, githubusercontent.com (1, 2). In these scenarios, the intention for the cookies is not to track across sites, but to provide a notion of session (or state) to embedders for a user's activity within a single top-level context.

Key Scenarios

Below are some examples of third-party cookie use cases that are unrelated to tracking that we would like to support with CHIPS. We first describe how unpartitioned third-party cookies meet that particular use case and then we describe the ideal end state would be when cross-site cookies are partitioned by top-level site.

Third-party locator service

Before unpartitioned third-party cookies are blocked

Let's say that a page on example.com uses an embedded third-party location service whose host is embed.map.com, which uses a cookie to save the location of the user's favorite store location. When the browser is on example.com, it would send a request to embed.map.com which would set a cookie by responding with the following header:

Set-Cookie: __Host-locationid=187; SameSite=None; Secure; HttpOnly; Path=/;

Any subsequent request to embed.map.com would include the following header even when the browser's top-level site is no longer example.com:

Cookie: __Host-locationid=187;

While this allows embed.map.com to remember their favorite store location for example.com, it also gives embed.map.com a persistent way to identify users across different top-level sites.

After unpartitioned third-party cookies are blocked

Our goal is for sites like embed.map.com to be able to set a cookie while embedded into example.com that would only be sent when the user's browser's top-level site is example.com. If the user navigates to another top-level site, subsequent requests to embed.map.com would not include the cookie set when the top-level site was example.com. This would enable embed.map.com to store user preferences for their activity per-top-level-site without storing a cross-site identifier on users' machines.

CDN load balancing

Before unpartitioned third-party cookies are blocked

Consider the site example.com who uses a third-party CDN, static.cdn.com to host some of its static assets. static.cdn.com's network uses load balancing servers which use a cookie to store the result of computing the best way to route an incoming request.

With unpartitioned third-party cookies, when a user navigates to example.com for the first time, static.cdn.com would respond to a browser's first request to them with the following Set-Cookie header:

Set-Cookie: __Host-lb=a3e7; SameSite=None; Secure; HttpOnly; Path=/;

...where the value of the cookie is some string of bits that static.cdn.com's load balancers can use to direct a request. Subsequent requests to static.cdn.com would include the following Cookie header:

Cookie: __Host-lb=a3e7;

When a user navigates to another top-level site, other.com, that also uses static.cdn.com to serve static content. The load balancing cookie will be sent in requests to static.cdn.com, even though the user has never visited other.com before.

After unpartitioned third-party cookies are blocked

Our goal is to allow third-party CDNs like static.cdn.com to be able to use cookies for their load balancers but have those cookies be partitioned by top-level site. This means that if static.cdn.com sets a load balancing cookie on a browser on example.com, requests to static.cdn.com will not include that cookie when the browser navigates to other.com.

This implies that static.cdn.com will have to recompute the value of the load balancing cookie for each top-level site a user visits. However, this is preferable to blocking all cookies in third-party contexts because then static.cdn.com will have to compute the best way to route a request each time. A partitioned cookie is also more preferable for static.cdn.com than JavaScript storage since any data in storage would not be available until the document loads.

Headless CMS

Before unpartitioned third-party cookies are blocked

Consider the site example.com now wants to use a third-party headless CMS, headless.cms.com, to store data which example.com's custom front end code uses to render their page. In order to tie together requests to headless.cms.com to a single session, their server sets a cookie:

Set-Cookie: __Host-SID=c78ef; SameSite=None; Secure; HttpOnly; Path=/;

Subsequent requests to headless.cms.com would include the following Cookie header, even when the top-level site is no longer example.com:

Cookie: __Host-SID=c78ef;

After unpartitioned third-party cookies are blocked

Our goal is to give sites like headless.cms.com a way to set session cookies partitioned by top-level site and are available after unpartitioned third-party cookies are blocked. These cookies could be used to identify which requests belong to the same session within a top-level site. However, unlike the current state of the art, we do not want a cookie set when the top-level site is example.com to be sent when the browser navigates to another site.

Other examples of use cases

Some other examples of use cases for partitioned cookies not listed above are:

  • Third-party CDNs that use cookies to serve access-controlled content
  • Front-end frameworks that rely on remote hosting and RPCs to remote services
  • Other types of third-party SaaS embeds

Non-goals

  • This document does not describe any changes to how a top-level site interacts with its own site's cookies.

  • This document also does not describe a replacement for third-party cookies that are shared across different domains owned by the same first party.

  • If you are using cross-site cookies between first-party domains that may be visited in top-level context, consider using First-Party Sets.

  • This document also does not describe partitioning any other type of browser storage other than cookies (e.g. HTTP cache, LocalStorage, service workers, etc.).

CHIPS: Opt-in Partitioned Cookies

In order to meet the use cases, we propose to introduce partitioned cookies a.k.a. CHIPS (Cookies Having Independent Partitioned State).

Under this proposal when a user visits green.com and embedded content from red.com sets a cookie in response to the cross-site request, the user agent would only send that cookie when the top-level site is green.com. When they are visiting a new site, blue.com, an embedded red.com frame would not receive the cookie set when red.com was embedded in green.com.

After CHIPS third parties' cookie jars are partitioned by top-level context.


After CHIPS: A browser visits green.com which has an embedded red.com frame that sets a cookie. When the user visits blue.com, the red.com frame cannot access the cookie set at green.com since it was a different top-level site.

Note: Firefox recently introduced partitioning all third-party cookies by default as a compatibility measure in the ETP Strict mode, and Safari briefly enabled (and subsequently rolled back) this in a previous version of ITP. More details on this approach are covered in the section Partition all third-party cookies by default.

The purpose of this document is to propose a new cookie attribute, Partitioned, which will allow user agents to opt-in to partitioning cookies by top-level context, i.e. partitioned by top-level site (or that site's First-Party Set if it has one).

Design Principles

Opt-in partitioned cookies

The primary aspect that distinguishes this proposal from existing implementations of partitioned cookies is the developer opt-in. Cookies must be set with a new attribute in order to be sent on cross-party requests once (unpartitioned) third-party cookies are obsoleted.

This principle is in line with the principle of least privilege in the long term. Initially, this new attribute will restrict a cookie's behavior, since it will limit the scope in which cookies can be sent compared to unpartitioned third-party cookies. But, in the long term these cookies will be the only cookies available in cross-party contexts.

Although existing software and APIs will need to be updated to support this new cookie attribute, we believe that an opt-in will be the best way to help move the web from (unpartitioned) third-party cookies without causing unexpected bugs. See the Partition all third-party cookies by default section below for more information.

Only sent over secure protocols

Partitioned cookies must only be set by and sent over secure protocols. This helps address some aspects of cookies' weak confidentiality and weak integrity.

Hostname-bound

Partitioned cookies should also be hostname bound. This and the requirement partitioned cookies be sent over secure protocols makes partitioned cookies as close to origin-bound as possible. Ideally, we'd like to also have user agents scope partitioned cookies by port as well, making them origin-scoped, but we think this requirement should only be enforced if/when Origin-Bound Cookies is enabled.

Only visible to the HTTP layer

Partitioned cookies should only be visible to the HTTP layer, which makes them less vulnerable to security vulnerabilities such as XSS-attacks.

Since Chrome data suggests only ~17% of cookies use the HttpOnly attribute, we believe that requiring partitioned cookies be HTTP-only will help facilitate cookies becoming more secure overall.

Note: This requirement and the requirement to only use secure protocols makes partitioned cookies behave more similarly to HTTP State Tokens.

Limit the number of cookies a third party can use in a single partition

A third-party domain's cookie jar should have a much lower per-partition size limit than existing garbage collection thresholds (180 cookies per domain in Chrome). We propose that third-party domains be limited to just one or some small number of cookies per-partition. We chose to scope the number of cookies in a single partition per third-party by domain so that a third-party could not circumvent this limit by registering new subdomains.

Browsers may enforce some global limit on the number of partitioned cookies in the cookie jar. This is to ensure that as a user visits more top-level sites over time that the number of partitioned cookies saved to their machine does not grow over time without bound.

Detailed Design

Opt-in cookie attribute

We propose a new cookie attribute, Partitioned, which must be specified by the Set-Cookie header to indicate that the cookie should be stored in a per-top-level partition. Any cookies that are not set with the Partitioned attribute will eventually be blocked in third-party contexts. (Note: Other features like the SameParty attribute may adjust the details of such blocking across domains within the same First-Party Set.)

Partition by top-level context

Cookies set with the Partitioned attribute must only be sent to the third-party host when the user agent is in the same top-level context as when the cookie was first set.

For most sites, the top-level context is just the top-level site. However, when the top-level site is part of a First-Party Set, the third-party can share the same partition across sites within the same set. This is consistent with Chrome’s privacy principle of partitioning identity by first party, and ensures that tracking across unrelated sites is prevented by the obsoletion of unpartitioned third-party cookies.

Using Set-Cookie with Partitioned

Below is an example of a Set-Cookie header that uses the Partitioned attribute:

Set-Cookie: __Host-SID=31d4d96e407aad42; SameSite=None; Secure; HttpOnly; Path=/; Partitioned;
Set-Cookie: abc=21ef; SameSite=None; Secure // blocked in 3p contexts

In third-party contexts, the Partitioned cookies would be sent in the request header as follows:

Cookie: __Host-SID=31d4d96e407aad42

Note: If this is a first-time request to the third-party within the current top-level context, no cookies would be sent. In other words, the third-party would get a new identifier for each top-level context.

Example usage

Below is a description of how Partitioned cookies can be used to meet the use cases laid out in the Key Scenarios section above.

Using Partitioned for third-party embeds

Let us reconsider the third-party embed example above with embed.map.com: a locator service which wishes to use a cookie to store user preferences for their activity on example.com (e.g. their favorite store location).

After third-party cookies are removed, embed.map.com could no longer set a cookie when the top-level site is not map.com or not in a First-Party Set with map.com, unless they include the Partitioned attribute:

Set-Cookie: __Host-locationid=187; SameSite=None; Secure; HttpOnly; Path=/; Partitioned;

When the browser's top-level context is still example.com, any subsequent request to embed.map.com would include the following header:

Cookie: __Host-locationid=187;

However, when the browser navigates to a different top-level context then the browser would not send the Cookie header above to embed.map.com. This gives embed.map.com the capability to store users' favorite example.com store location, but those preferences would only be accessible to embed.map.com when the top-level context is example.com. This is to ensure that embed.map.com cannot use this cookie to link users' activity across different top-level contexts.

CDN load balancing and headless CMS

Cookies with the Partitioned attribute can meet the load balancing use case for static.cdn.com or the session cookie for headless.cms.com. For the sake of brevity, let us only consider the load balancer use case.

When the user visits example.com and static.cdn.com wants to set a cookie storing the result of computing the best way to direct this particular user's requests. They could do so using the Partitioned attribute using the following Set-Cookie header:

Set-Cookie: __Host-lb=a3e7; SameSite=None; Secure; HttpOnly; Path=/; Partitioned;

This cookie would only be available to static.cdn.com when the browser's top-level site is example.com. When the browser navigates to another top-level site, then subsequent requests to static.cdn.com will not include this cookie.

One can extend this to the headless CMS example using the __Host-SID cookie described in the Key Scenarios section.

How to enforce best practices

Partitioned cookies must use the __Host- prefix

User agents must only accept Partitioned cookies which have the __Host- prefix.

The __Host- prefix requires that the cookie be set with Secure and Path=/ and disallows the Domain attribute. These requirements ensure that partitioned cookies only be set from and sent to secure origins only. It also makes the cookies hostname-bound within a partition. This requirement would have the semantics of partitioned cookies as close to origin-bound as possible.

HttpOnly attribute

User agents may also enforce that Partitioned cookies also include the HttpOnly attribute, but we are less confident they should require it. Ensuring that partitioned cookies are only available on the network stack makes them less susceptible to XSS attacks.

SameSite attribute

User agents may only accept Partitioned cookies if their SameSite attribute is None.

Note: a Partitioned cookie without SameSite=None is effectively just a same-site cookie which cannot be sent in a third-party context anyway.

SameParty attribute

User agents should reject any cookie set with both Partitioned and SameParty attributes. Since sites within the same First-Party Set are allowed access to unpartitioned SameParty cookies, the semantic is inconsistent with partitioned cookies.

Clearing partitioned cookies

If a top-level site sends Clear-Site-Data, then the user agent clears all partitioned cookies available to third-parties from that site as well.

If a third-party site sends Clear-Site-Data, then the user agent should clear all cookies available to that third-party in the partition for the current top-level site alone. The user agent must not clear the third-party's cookies in other partitions. This is to prevent abuse of such a capability as a cross-site tracking vector as described here.

Browsers may choose to provide user controls to clear individual partitions of a site’s cookies.

Handling older or incompatible clients

The new cookie attribute will be ignored on older clients that don't recognize it and fall back to default behavior. Since these cookies are intended for third-party contexts, clients that are incompatible with SameSite=None may reject cookies with SameSite=None.

It is also recommended to still include the __Host- prefix. Even clients that do not recognize the Partitioned attribute still enforce the semantics of the __Host- prefix. This would ensure that cross-site cookies are hostname bound and only sent over secure channels, which is still a security win.

Service workers

Service workers have access to cookies via the CookieStore API or when they send HTTP requests using fetch (imagine a worker pings an HTTP endpoint that just echoes back the request's Cookie header in its response). Unless service workers are partitioned, then the unpartitioned cookie jar would be available to the worker even if the cookies are HttpOnly. Because of these reasons, partitioning service workers is the only way to guarantee a partitioned cookie jar.

Safari has already partitioned service workers by the top-level origin when the worker was registered and the service worker's origin, so that service workers can only interact with windows that are the same top-level origin as the top-level page when the worker was installed. If a user agent partitions service workers using this scheme, there is no cross-site tracking risk to exposing Partitioned cookies to service workers.

Service workers are disabled in Firefox when Dynamic Partitioning is enabled, but they are working on implementing a partitioned service worker solution.

Alternative Solutions

Partition all third-party cookies by default

Firefox announced that they are partitioning all third-party cookies by default into their ETP Strict mode. Safari previously tried partitioning cookies based on heuristics, but eventually chose to block them altogether citing developer confusion as one of the reasons.

We do not think cookies should be partitioned without a developer opt-in since developers built their existing servers with the expectation of an unpartitioned third-party cookie. This can cause confusion and unexpected bugs (1, 2, 3, 4).

Partitioning by default also has more implementation complexity for browser developers, since they need to consider how partitioning the cookie jar will impact any part of the browser that interacts with cookies. Supporting opt-in cookie partitioning while gradually moving the web off of globally-scoped third-party cookies will help ease the transition for browsers.

There is also the issue of state proliferation. There are some third-party origins on the web today that are prevalent across many top-level contexts. If we partition the cookie jar by default and do not include a new upper bound on the size of each cookie jar partition, device storage limits will be exhausted more quickly.

Limit the number of cookies in a top-level context's partition

One additional limitation user agents may also enforce is to limit the number of cookies in a top-level context's partition across all third-party domains as well. This limit would prevent a single top-level context's partition from taking up too much space in the cookie jar.

We chose not to enforce a global per-partition limit is that it would open a side channel for a third party to learn if another, distinct third party set a cookie within the same top-level context.

For example, say each third-party domain is restricted to 1 cookie per partition and the global per-partition limit was 10. A malicious third party could embed frames from several domains, evil[1-10].com on some top-level site, 1p.com, which sets a partitioned cookie. If any other third party sets a partitioned cookie on 1p.com, then one of the evil[1-10].com cookies will be evicted and the malicious third party will learn that another, distinct host set a cookie. A malicious third party could use this information to determine if a user has logged in or if they may be using a locator service hosted by a distinct party.

Another attack is where evil.com communicates with other third parties by setting cookies only based on a user’s personal attributes or preferences.

One way to potentially circumvent this is to make the global per-partition limit much larger than the per-partition limit for each third-party domain, but it is unclear what the relative size of the global per-partition limit would have to be to mitigate these attacks.

Requiring the __Secure- prefix

Cookies with the __Host- prefix implicitly have the same properties as cookies with the __Secure- prefix. By requiring partitioned cookies to have the former we guarantee that they also have the same properties as if we required the latter.

Not requiring the __Host- prefix

One alternate design choice is to not require that cookies with the Partitioned attribute have a __Host- prefix. Instead, the semantics of the Partitioned attribute would include the semantics of __Host- prefix cookies (i.e. requiring Secure and Path=/, disallowing Domain).

We decided against this for two reasons. The first is that clients that do not yet recognize the Partitioned attribute may still recognize the __Host- prefix and can still benefit from its semantics. The second is that mixing the semantics of prefixes and attributes is not the right path forward, since it makes the semantics of either more difficult to understand.

DNS CNAME’ing

Websites can choose to delegate/alias a subdomain to a third-party service provider using DNS CNAME records. For example, a site myblog.example may have a subdomain foo.myblog.example that can be mapped to a third-party endpoint dedicated to servicing that site at myblog.cms.example. In this case, the browser treats foo.myblog.example as first-party with the top-level site, and any cookies sent on the request that eventually gets sent to myblog.cms.example are implicitly partitioned on [foo.]myblog.example.

It follows that any cookies sent to foo.myblog.example would not be subjected to cross-site cookie restrictions and would still be sent to myblog.cms.example.

However, this pattern has a couple of security drawbacks:

  • myblog.cms.example would need to acquire and serve TLS certificates issued for foo.myblog.example.

  • All Domain cookies set on myblog.example get sent to myblog.cms.example, including potentially sensitive data set by other subdomains on myblog.example.

Additionally, this adds implementation and deployment complexity for developers.

Prior Art

  • Safari partitioned the cookie jar by default in ITP 2.1
  • Firefox partitioned the cookie jar by default in ETP Strict Mode

References and Acknowledgements

Acknowledgements

We’d like to thank Lily Chen, Steven Bingler, Rowan Merewood, and Jeffrey Yasskin for their insights and advice that helped us shape this proposal.

References

About

A proposal for a cookie attribute to partition cross-site cookies by top-level site

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published