Modern browsers have several security levels to separate cross-site communications, including various settings to how cookies should behave across the sites. CHIPS is best explained by the description on MDN:
Cookies Having Independent Partitioned State (CHIPS, also known as Partitioned cookies) allows developers to opt a cookie into partitioned storage, with a separate cookie jar per top-level site.
Without cookie partitioning, third-party cookies can enable services to track users and associate their information across unrelated top-level sites. Cookies marked Partitioned are double-keyed: by the origin that sets them and the origin of the top-level page.
CHIPS is necessary to keep cross-site cookies working properly, as Google Chrome has been phasing third-party cookies out for some time now.
CHIPS technology was introduced not so long ago, but still has “little” adoption (currently “only” available in Blink-based or Gecko-based browsers). Prior to Firefox 141, it was temporarily disabled due to web compatibility issues. Starting with Firefox 141, the feature is fully enabled. The feature is also implemented in Safari 18.4 (released recently).
CHIPS implementation introduces a new Cookie parameter named Partitioned, which should be applied during Secure context.
This RFC proposes two groups of changes:
1. Adding a new option “partitioned” for setcookie()
and setrawcookie()
functions.
<?php setcookie('name', 'value', ['secure' => true, 'partitioned' => true]); ?>
Notably, only the array overload of these functions is affected. This is in a similar vain to the recent samesite
addition that also was only added to the array overload.
2. Add support for partitioned session cookies. This means that session_set_cookie_params()
, session_get_cookie_params()
, and session_start()
will receive support for partitioned cookies.
Currently, frameworks and applications have to work around not having this option by manually setting a header, which is cumbersome. This feature was requested via https://github.com/php/php-src/issues/12646, and has seen some activity and workarounds being posted.
Extend setcookie()
and setrawcookie()
functions and make them able to accept one more option named “partitioned” to control CHIPS behavior.
Using “partitioned” without setting “secure” will throw a ValueError
.
Extend session_start()
options with “cookie_partitioned”, and session_set_cookie_params()
's array overload to support the “partitioned” key. Also update the returned array from session_get_cookie_params()
to include the “partitioned” key with a boolean value.
Example 1: Regular CHIPS usage:
<?php setcookie("name", "value", ["secure" => true, "partitioned" => true]); // will result in headers: // Set-Cookie: name=value; secure; Partitioned ?>
Example 2: Using “partitioned” without “secure” or with disabled “secure” option:
<?php setcookie("name", "value", ["partitioned" => true]); setcookie("name", "value", ["secure" => false, "partitioned" => true]); // Both raise a ValueError: // Uncaught ValueError: setcookie(): "partitioned" option cannot be used without "secure" option in ... ?>
Example 3: Starting a session with partitioned cookies:
<?php session_id("12345"); session_set_cookie_params(["secure" => true, "partitioned" => true]); session_start(); // will result in headers: // Set-Cookie: PHPSESSID=12345; path=/; secure; Partitioned ?>
Example 4: Setting the session cookie settings and dumping those settings:
<?php session_set_cookie_params([ "secure" => true, "partitioned" => true ]); var_dump(session_get_cookie_params()); // will dump this array: // array(7) { // ["lifetime"]=> // int(0) // ["path"]=> // string(1) "/" // ["domain"]=> // string(0) "" // ["secure"]=> // bool(true) // ["partitioned"]=> // bool(true) // ["httponly"]=> // bool(false) // ["samesite"]=> // string(0) "" // } ?>
Example 5: Configuring the session with partitioned, but not secure:
<?php var_dump(session_start(["cookie_secure" => false, "cookie_partitioned" => true])); // bool(false) // Warning: session_start(): Partitioned session cookie cannot be used without also configuring it as secure in ... ?>
The reason we defer the check until the session is started, is because any combination of ini_set()
, session_start()
, session_set_cookie_params()
can set some cookie settings.
No breaking changes.
PHP 8.5
No effects.
setcookie()
and setrawcookie()
PHP APIs are contained there. Furthermore, there is an internal API php_setcookie
for C extensions that now gets an additional boolean argument partitioned
.An additional cookie parameter is introduced, but it has no direct API influence on the SAPI layer.
The session cookie settings for session_start()
and session_set_cookie_params()
are stored in INI settings. These functions internally modify the session INI settings for the lifetime of the request. For example, using session_start(["cookie_secure" => true])
will set the session.cookie_secure
setting to true. Likewise, we will add a session.cookie_partitioned
boolean setting that defaults to false, but can be set via the above-mentioned functions. It is also possible to default this setting to true in the php.ini if one desires to do so.
No issues.
Currently, there is no future scope. Any CHIPS evolution steps will be made separately.
Single voting widget that requires 2/3rd majority.
Implementation (patch+test): https://github.com/php/php-src/pull/12652
After the RFC is implemented, this section should contain:
CHIPS MDN: https://developer.mozilla.org/en-US/docs/Web/Privacy/Guides/Privacy_sandbox/Partitioned_cookies
None yet.
Version 0.9.1: Extra clarifications on non-Blink browsers, thanks Claude! Version 0.9: First version.