Opened 18 months ago
Last modified 7 months ago
#34613 new New feature
add support for Partitioned cookies
Reported by: | Oleg Korsak | Owned by: | nobody |
---|---|---|---|
Component: | HTTP handling | Version: | 4.1 |
Severity: | Normal | Keywords: | chips, cookies, csrf, partitioned |
Cc: | Michael Wheeler, Markus Holtermann, Alex Gaynor, Colin Murtaugh | Triage Stage: | Accepted |
Has patch: | no | Needs documentation: | no |
Needs tests: | no | Patch needs improvement: | no |
Easy pickings: | no | UI/UX: | no |
Description
Hi.
I'm having issues with Django app in Chrome. It is working as a standalone and embedded into IFRAME in another system. Users tend to open both ways in tabs. At some point they manage to overwrite (like re-login) cookies with session id and csrf token in one tab, but Chrome overwrites them for another one as well, while opened IFRAME has an old CSRF token in HTML. So next request fails. No issues in Firefox.
I've found following explanation:
https://developer.chrome.com/docs/privacy-sandbox/chips/
https://blog.mozilla.org/security/2021/02/23/total-cookie-protection/
So Firefox separates such cookies by default. While Chrome needs server to set a "Partitioned" flag for cookies. But... Django is unable to do so due to using standard Python Morsel cookie class, which doesn't support it.
Change History (12)
comment:1 by , 18 months ago
Cc: | added |
---|
comment:2 by , 18 months ago
comment:3 by , 18 months ago
Resolution: | → needsinfo |
---|---|
Status: | new → closed |
comment:4 by , 10 months ago
Resolution: | needsinfo |
---|---|
Status: | closed → new |
Yes, this is still experimental, but Chrome is rolling out their trial to remove third-party cookies starting this month:
https://developers.google.com/privacy-sandbox/blog/cookie-countdown-2023oct
Partitioned cookies will be basically the only way left to implement interactive iframes with state. Our specific use case is this:
https://docs.pretix.eu/en/latest/user/events/widget.html
We'll need to be able to set our session cookies as partitioned quite soon and I was surprised to find that there seems to be no way to it currently, not even a hacky one.
comment:5 by , 10 months ago
Cc: | added |
---|
follow-up: 7 comment:6 by , 10 months ago
Resolution: | → needsinfo |
---|---|
Status: | new → closed |
Raphael, I appreciate you'd like to reopen the ticket, but I'm not exactly sure what can of changes are needed it Django, is it something that can be handled by a custom middleware? Do we need to change SimpleCookie
implementation? Should we mark Django cookies as "partitioned"? Is it only an issue for session cookies? etc. I'd be grateful for your insights.
comment:7 by , 10 months ago
Hi Mariusz,
Replying to Mariusz Felisiak:
Raphael, I appreciate you'd like to reopen the ticket, but I'm not exactly sure what can of changes are needed it Django, is it something that can be handled by a custom middleware? Do we need to change
SimpleCookie
implementation?
That is the very nasty part about this: Cookie headers are as a special case by Django directly on the WSGI/ASGI layer, different from any other header, so as far as I can tell, a custom middleware can *not* implement this. Supporting it in Django requires at least an additional keyword argument to set_cookie()
plus – and that is the nasty part – a change to SimpleCookie
, which is in the stdlib these days.
There is already an issue for the stdlib:
https://github.com/python/cpython/issues/112713
It also has a PR:
https://github.com/python/cpython/pull/112714
But even if that get's merged soon, I don't think it will be backported to existing Python versions, so supporting this in the near future (i.e. next Django version) it would mean vendoring parts of SimpleCookie
again. I'll try to figure out what parts exactly in the next days or weeks, since even if this does not make it in Django soon, we'll need to monkeypatch it in our project somehow.
Should we mark Django cookies as "partitioned"?
I think it should be opt-in, i.e. a settings flag for session cookie and CSRF cookie (similar to Secure and Httponly), and a keyword argument for set_cookie()
.
Is it only an issue for session cookies? etc.
No, this will affect at least session cookie and CSRF cookie, plus possibly custom cookies.
comment:8 by , 10 months ago
Cc: | added |
---|---|
Component: | CSRF → HTTP handling |
Resolution: | needsinfo |
Status: | closed → new |
Triage Stage: | Unreviewed → Accepted |
Thanks! Tentatively accepted.
But even if that get's merged soon, I don't think it will be backported to existing Python versions, so supporting this in the near future (i.e. next Django version) it would mean vendoring parts of
SimpleCookie
again.
That's unfortunate, here be dragons ...
I'll try to figure out what parts exactly in the next days or weeks, since even if this does not make it in Django soon ...
Much appreciated.
follow-up: 10 comment:9 by , 10 months ago
I wonder if it would be possible to follow a similar approach to the one that was used to add support for SameSite
https://github.com/django/django/commit/9a56b4b13ed92d2d5bb00d6bdb905a73bc5f2f0a.
Not sure if anyone was already planning on tackling this, but if not I'd be curious about taking it on as a first time contributor.
follow-up: 11 comment:10 by , 10 months ago
Replying to Michael Wheeler:
I wonder if it would be possible to follow a similar approach to the one that was used to add support for
SameSite
https://github.com/django/django/commit/9a56b4b13ed92d2d5bb00d6bdb905a73bc5f2f0a.
Not sure if anyone was already planning on tackling this, but if not I'd be curious about taking it on as a first time contributor.
Thanks for the pointer here. I was actually going to write a WSGI middleware, but following what was done for SameSite
I used the following:
middleware.py:
... from http import cookies ... cookies.Morsel._flags.add("partitioned") cookies.Morsel._reserved.setdefault("partitioned", "Partitioned") class CookiePartitioningMiddleware(MiddlewareMixin): def process_response( self, request: HttpRequest, response: HttpResponseBase ) -> HttpResponseBase: for name in ( getattr(settings, f"{prefix}_COOKIE_NAME") for prefix in ("CSRF", "SESSION", "LANGUAGE") if getattr(settings, f"{prefix}_COOKIE_SECURE") ): if cookie := response.cookies.get(name): cookie["Partitioned"] = True return response
and added the middleware to my application.
Adding and respecing a ${NAME}_COOKIE_PARTITIONED
would make sense for a PR, but for our use case we want to partition all cookies. It may also make sense to make sure ${NAME}_COOKIE_SAMESITE
is 'None'
since that is recommended for browsers which don't support partitioning via CHIPS
comment:11 by , 9 months ago
Replying to Terence Honles:
Replying to Michael Wheeler:
I wonder if it would be possible to follow a similar approach to the one that was used to add support for
SameSite
https://github.com/django/django/commit/9a56b4b13ed92d2d5bb00d6bdb905a73bc5f2f0a.
Not sure if anyone was already planning on tackling this, but if not I'd be curious about taking it on as a first time contributor.
Thanks for the pointer here. I was actually going to write a WSGI middleware, but following what was done for
SameSite
I used the following:
middleware.py:
... from http import cookies ... cookies.Morsel._flags.add("partitioned") cookies.Morsel._reserved.setdefault("partitioned", "Partitioned") class CookiePartitioningMiddleware(MiddlewareMixin): def process_response( self, request: HttpRequest, response: HttpResponseBase ) -> HttpResponseBase: for name in ( getattr(settings, f"{prefix}_COOKIE_NAME") for prefix in ("CSRF", "SESSION", "LANGUAGE") if getattr(settings, f"{prefix}_COOKIE_SECURE") ): if cookie := response.cookies.get(name): cookie["Partitioned"] = True return responseand added the middleware to my application.
Adding and respecing a
${NAME}_COOKIE_PARTITIONED
would make sense for a PR, but for our use case we want to partition all cookies. It may also make sense to make sure${NAME}_COOKIE_SAMESITE
is'None'
since that is recommended for browsers which don't support partitioning via CHIPS
FYI, this doesn't seem to work for sessionid
cookies, the Partitioned attr only gets set on the csrftoken.
comment:12 by , 7 months ago
Cc: | added |
---|
Hi! Partitioned cookies still seem to be quite experimental in Chrome/Safari. So, we're unlikely to add support for them right away.
But, in order to better understand the issue, can you tell us more information about the setup you have? For example, what's the domain of the site that includes the iframe. What's the domain of the site within the iframe. What cookie-related settings do you have configured?
Can you reproduce the issue in a small project?