Skip to content

Commit 73d6504

Browse files
authored
Merge commit from fork
Sessions: fix signing key selection when key rotation is enabled
2 parents 941efd4 + cbb6c36 commit 73d6504

File tree

4 files changed

+21
-8
lines changed

4 files changed

+21
-8
lines changed

CHANGES.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@ Version 3.1.1
33

44
Unreleased
55

6+
- Fix signing key selection order when key rotation is enabled via
7+
``SECRET_KEY_FALLBACKS``. :ghsa:`4grg-w6v8-c28g`
68
- Fix type hint for `cli_runner.invoke`. :issue:`5645`
79
- ``flask --help`` loads the app and plugins first to make sure all commands
810
are shown. :issue:5673`

docs/config.rst

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -127,13 +127,16 @@ The following configuration values are used internally by Flask:
127127

128128
.. py:data:: SECRET_KEY_FALLBACKS
129129
130-
A list of old secret keys that can still be used for unsigning, most recent
131-
first. This allows a project to implement key rotation without invalidating
132-
active sessions or other recently-signed secrets.
130+
A list of old secret keys that can still be used for unsigning. This allows
131+
a project to implement key rotation without invalidating active sessions or
132+
other recently-signed secrets.
133133

134134
Keys should be removed after an appropriate period of time, as checking each
135135
additional key adds some overhead.
136136

137+
Order should not matter, but the default implementation will test the last
138+
key in the list first, so it might make sense to order oldest to newest.
139+
137140
Flask's built-in secure cookie session supports this. Extensions that use
138141
:data:`SECRET_KEY` may not support this yet.
139142

src/flask/sessions.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -318,11 +318,12 @@ def get_signing_serializer(self, app: Flask) -> URLSafeTimedSerializer | None:
318318
if not app.secret_key:
319319
return None
320320

321-
keys: list[str | bytes] = [app.secret_key]
321+
keys: list[str | bytes] = []
322322

323323
if fallbacks := app.config["SECRET_KEY_FALLBACKS"]:
324324
keys.extend(fallbacks)
325325

326+
keys.append(app.secret_key) # itsdangerous expects current key at top
326327
return URLSafeTimedSerializer(
327328
keys, # type: ignore[arg-type]
328329
salt=self.salt,

tests/test_basic.py

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -381,14 +381,21 @@ def set_session() -> str:
381381
def get_session() -> dict[str, t.Any]:
382382
return dict(flask.session)
383383

384-
# Set session with initial secret key
384+
# Set session with initial secret key, and two valid expiring keys
385+
app.secret_key, app.config["SECRET_KEY_FALLBACKS"] = (
386+
"0 key",
387+
["-1 key", "-2 key"],
388+
)
385389
client.post()
386390
assert client.get().json == {"a": 1}
387391
# Change secret key, session can't be loaded and appears empty
388-
app.secret_key = "new test key"
392+
app.secret_key = "? key"
389393
assert client.get().json == {}
390-
# Add initial secret key as fallback, session can be loaded
391-
app.config["SECRET_KEY_FALLBACKS"] = ["test key"]
394+
# Rotate the valid keys, session can be loaded
395+
app.secret_key, app.config["SECRET_KEY_FALLBACKS"] = (
396+
"+1 key",
397+
["0 key", "-1 key"],
398+
)
392399
assert client.get().json == {"a": 1}
393400

394401

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy