Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Support setting both partitioned and unpartitioned cookies of the same domain/path/name #58774

Closed as not planned
@JonathanGawrych

Description

@JonathanGawrych

Description

In ResponseHeaderBag's setCookie() function:

$this->cookies[$cookie->getDomain()][$cookie->getPath()][$cookie->getName()] = $cookie;
cookies are set based on their domain, path, and name. However there's one more category that partitions cookies, ironically named partitioned. You can set both partitioned and unpartitioned cookies at the same time. Unfortunately the ResponseHeaderBag doesn't allow this.

What's the use case you may ask? We have a site that can either be opened in an iframe or at a top level window in a new tab. We set our auth cookie to partitioned inside the iframe and not partitioned in a new tab. This is done in a classroom setting where multiple users often use a single machine. If they only use iframes or only use new tabs, then there's no problem. However, once you mix the two, you can have a case where the new tab cookie leaks into the iframe. Both cookies are then sent with requests, causing the user inside of the iframe to potentially logged in as the last user who had a new tab logged in instead.

To counteract this, we attempt to log out (delete the previous cookies) when a user logs in. However, we need to delete the unpartitioned cookie, and set the partitioned one in the same response. Setting the partitioned cookie overwrites deleting the unpartitioned cookie. The code example below shows a minimal reproduction. Right now our workaround is to use a raw header() statement, which is less than ideal. Note that we are also using Laravel, but before we can make any PR there, we first need to make one here.

Thanks for your work!

Example

<?php
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpFoundation\Cookie;

$response = new Response();
// Log out the old user outside the iframe so the cookie doesn't leak inside the iframe
$response->headers->setCookie(new Cookie('auth', null, sameSite: Cookie::SAMESITE_NONE, partitioned: false));

// Log in the new user by setting their cookie.
$response->headers->setCookie(new Cookie('auth', 'new_token', time() + 7200, sameSite: Cookie::SAMESITE_NONE, partitioned: true));

echo implode('\n', array_map(fn ($cookie) => (string) $cookie, $response->headers->getCookies()));

// expected:
// auth=deleted; expires=Mon, 06 Nov 2023 21:31:24 GMT; Max-Age=0; path=/; httponly; samesite=none
// auth=new_token; expires=Tue, 05 Nov 2024 23:31:57 GMT; Max-Age=7198; path=/; httponly; samesite=none; partitioned

// actual:
// auth=new_token; expires=Tue, 05 Nov 2024 23:31:57 GMT; Max-Age=7198; path=/; httponly; samesite=none; partitioned

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions