python-flask/0005-Backport-support-for-the-accessed-attribute.patch
Brian C. Lane d170540219 - Copy missing tests over from distgit
- Backport fix for CVE-2023-30861
  Resolves: rhbz#2196683
2023-05-10 13:35:57 -07:00

108 lines
3.5 KiB
Diff

From 640ff67e9d59d7acd786683bbab422d8aa17211c Mon Sep 17 00:00:00 2001
From: "Brian C. Lane" <bcl@redhat.com>
Date: Tue, 9 May 2023 15:36:11 -0700
Subject: [PATCH 5/5] Backport support for the accessed attribute
This is added to the SessionMixin and SecureCookieSession to support
fixing CVE-2023-30861.
Related: rhbz#2196683
---
flask/sessions.py | 40 +++++++++++++++++++++++++++++++++++++++-
tests/test_basic.py | 8 ++++++++
2 files changed, 47 insertions(+), 1 deletion(-)
diff --git a/flask/sessions.py b/flask/sessions.py
index 2f60e7eb..278c3583 100644
--- a/flask/sessions.py
+++ b/flask/sessions.py
@@ -48,6 +48,11 @@ class SessionMixin(object):
#: The default mixin implementation just hardcodes ``True`` in.
modified = True
+ #: Some implementations can detect when session data is read or
+ #: written and set this when that happens. The mixin default is hard
+ #: coded to ``True``.
+ accessed = True
+
def _tag(value):
if isinstance(value, tuple):
@@ -111,14 +116,47 @@ session_json_serializer = TaggedJSONSerializer()
class SecureCookieSession(CallbackDict, SessionMixin):
- """Base class for sessions based on signed cookies."""
+ """Base class for sessions based on signed cookies.
+
+ This session backend will set the :attr:`modified` and
+ :attr:`accessed` attributes. It cannot reliably track whether a
+ session is new (vs. empty), so :attr:`new` remains hard coded to
+ ``False``.
+ """
+
+ #: When data is changed, this is set to ``True``. Only the session
+ #: dictionary itself is tracked; if the session contains mutable
+ #: data (for example a nested dict) then this must be set to
+ #: ``True`` manually when modifying that data. The session cookie
+ #: will only be written to the response if this is ``True``.
+ modified = False
+
+ #: When data is read or written, this is set to ``True``. Used by
+ # :class:`.SecureCookieSessionInterface` to add a ``Vary: Cookie``
+ #: header, which allows caching proxies to cache different pages for
+ #: different users.
+ accessed = False
+
def __init__(self, initial=None):
def on_update(self):
self.modified = True
+ self.accessed = True
CallbackDict.__init__(self, initial, on_update)
self.modified = False
+ def __getitem__(self, key):
+ self.accessed = True
+ return super().__getitem__(key)
+
+ def get(self, key, default=None):
+ self.accessed = True
+ return super().get(key, default)
+
+ def setdefault(self, key, default=None):
+ self.accessed = True
+ return super().setdefault(key, default)
+
class NullSession(SecureCookieSession):
"""Class used to generate nicer error messages if sessions are not
diff --git a/tests/test_basic.py b/tests/test_basic.py
index 85555300..5ad8c3de 100644
--- a/tests/test_basic.py
+++ b/tests/test_basic.py
@@ -192,12 +192,20 @@ def test_session():
@app.route('/set', methods=['POST'])
def set():
+ assert not flask.session.accessed
+ assert not flask.session.modified
flask.session['value'] = flask.request.form['value']
+ assert flask.session.accessed
+ assert flask.session.modified
return 'value set'
@app.route('/get')
def get():
+ assert not flask.session.accessed
+ assert not flask.session.modified
v = flask.session.get("value", "None")
+ assert flask.session.accessed
+ assert not flask.session.modified
return v
c = app.test_client()
--
2.40.1