add SESSION_COOKIE_PARTITIONED config

co-authored-by: Jose Cespedes <josecespedes@ibm.com>
This commit is contained in:
David Lord 2024-06-09 19:55:22 -06:00
parent 6f2014d353
commit 9efc1ebeeb
No known key found for this signature in database
GPG Key ID: 43368A7AA8CC5926
5 changed files with 34 additions and 0 deletions

View File

@ -15,6 +15,8 @@ Unreleased
through the ``MAX_CONTENT_LENGTH`` config. Added through the ``MAX_CONTENT_LENGTH`` config. Added
``MAX_FORM_MEMORY_SIZE`` and ``MAX_FORM_PARTS`` config. Added documentation ``MAX_FORM_MEMORY_SIZE`` and ``MAX_FORM_PARTS`` config. Added documentation
about resource limits to the security page. :issue:`5625` about resource limits to the security page. :issue:`5625`
- Add support for the ``Partitioned`` cookie attribute (CHIPS), with the
``SESSION_COOKIE_PARTITIONED`` config. :issue`5472`
Version 3.0.3 Version 3.0.3

View File

@ -173,6 +173,23 @@ The following configuration values are used internally by Flask:
Default: ``False`` Default: ``False``
.. py:data:: SESSION_COOKIE_PARTITIONED
Browsers will send cookies based on the top-level document's domain, rather
than only the domain of the document setting the cookie. This prevents third
party cookies set in iframes from "leaking" between separate sites.
Browsers are beginning to disallow non-partitioned third party cookies, so
you need to mark your cookies partitioned if you expect them to work in such
embedded situations.
Enabling this implicitly enables :data:`SESSION_COOKIE_SECURE` as well, as
it is only valid when served over HTTPS.
Default: ``False``
.. versionadded:: 3.1
.. py:data:: SESSION_COOKIE_SAMESITE .. py:data:: SESSION_COOKIE_SAMESITE
Restrict how cookies are sent with requests from external sites. Can Restrict how cookies are sent with requests from external sites. Can

View File

@ -189,6 +189,7 @@ class Flask(App):
"SESSION_COOKIE_PATH": None, "SESSION_COOKIE_PATH": None,
"SESSION_COOKIE_HTTPONLY": True, "SESSION_COOKIE_HTTPONLY": True,
"SESSION_COOKIE_SECURE": False, "SESSION_COOKIE_SECURE": False,
"SESSION_COOKIE_PARTITIONED": False,
"SESSION_COOKIE_SAMESITE": None, "SESSION_COOKIE_SAMESITE": None,
"SESSION_REFRESH_EACH_REQUEST": True, "SESSION_REFRESH_EACH_REQUEST": True,
"MAX_CONTENT_LENGTH": None, "MAX_CONTENT_LENGTH": None,

View File

@ -224,6 +224,14 @@ class SessionInterface:
""" """
return app.config["SESSION_COOKIE_SAMESITE"] # type: ignore[no-any-return] return app.config["SESSION_COOKIE_SAMESITE"] # type: ignore[no-any-return]
def get_cookie_partitioned(self, app: Flask) -> bool:
"""Returns True if the cookie should be partitioned. By default, uses
the value of :data:`SESSION_COOKIE_PARTITIONED`.
.. versionadded:: 3.1
"""
return app.config["SESSION_COOKIE_PARTITIONED"] # type: ignore[no-any-return]
def get_expiration_time(self, app: Flask, session: SessionMixin) -> datetime | None: def get_expiration_time(self, app: Flask, session: SessionMixin) -> datetime | None:
"""A helper method that returns an expiration date for the session """A helper method that returns an expiration date for the session
or ``None`` if the session is linked to the browser session. The or ``None`` if the session is linked to the browser session. The
@ -338,6 +346,7 @@ class SecureCookieSessionInterface(SessionInterface):
domain = self.get_cookie_domain(app) domain = self.get_cookie_domain(app)
path = self.get_cookie_path(app) path = self.get_cookie_path(app)
secure = self.get_cookie_secure(app) secure = self.get_cookie_secure(app)
partitioned = self.get_cookie_partitioned(app)
samesite = self.get_cookie_samesite(app) samesite = self.get_cookie_samesite(app)
httponly = self.get_cookie_httponly(app) httponly = self.get_cookie_httponly(app)
@ -354,6 +363,7 @@ class SecureCookieSessionInterface(SessionInterface):
domain=domain, domain=domain,
path=path, path=path,
secure=secure, secure=secure,
partitioned=partitioned,
samesite=samesite, samesite=samesite,
httponly=httponly, httponly=httponly,
) )
@ -374,6 +384,7 @@ class SecureCookieSessionInterface(SessionInterface):
domain=domain, domain=domain,
path=path, path=path,
secure=secure, secure=secure,
partitioned=partitioned,
samesite=samesite, samesite=samesite,
) )
response.vary.add("Cookie") response.vary.add("Cookie")

View File

@ -293,6 +293,7 @@ def test_session_using_session_settings(app, client):
SESSION_COOKIE_DOMAIN=".example.com", SESSION_COOKIE_DOMAIN=".example.com",
SESSION_COOKIE_HTTPONLY=False, SESSION_COOKIE_HTTPONLY=False,
SESSION_COOKIE_SECURE=True, SESSION_COOKIE_SECURE=True,
SESSION_COOKIE_PARTITIONED=True,
SESSION_COOKIE_SAMESITE="Lax", SESSION_COOKIE_SAMESITE="Lax",
SESSION_COOKIE_PATH="/", SESSION_COOKIE_PATH="/",
) )
@ -315,6 +316,7 @@ def test_session_using_session_settings(app, client):
assert "secure" in cookie assert "secure" in cookie
assert "httponly" not in cookie assert "httponly" not in cookie
assert "samesite" in cookie assert "samesite" in cookie
assert "partitioned" in cookie
rv = client.get("/clear", "http://www.example.com:8080/test/") rv = client.get("/clear", "http://www.example.com:8080/test/")
cookie = rv.headers["set-cookie"].lower() cookie = rv.headers["set-cookie"].lower()
@ -324,6 +326,7 @@ def test_session_using_session_settings(app, client):
assert "path=/" in cookie assert "path=/" in cookie
assert "secure" in cookie assert "secure" in cookie
assert "samesite" in cookie assert "samesite" in cookie
assert "partitioned" in cookie
def test_session_using_samesite_attribute(app, client): def test_session_using_samesite_attribute(app, client):