From c4e4157142a59accf7803cae7f68df1a0e72047c Mon Sep 17 00:00:00 2001 From: Lex Date: Mon, 8 Jan 2024 21:43:19 +1000 Subject: [PATCH] Use secrets module for session ids Use secrets module for session ids --- CHANGES.rst | 10 +++++++--- src/flask_session/__init__.py | 1 + src/flask_session/sessions.py | 21 +++++++++++---------- 3 files changed, 19 insertions(+), 13 deletions(-) diff --git a/CHANGES.rst b/CHANGES.rst index 1aadbf2f..2f52c04b 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -1,10 +1,14 @@ -Version 0.5.1 +Version 0.6.0 ------------- Released 2023-00-00 -- use ``should_set_cookie`` for preventing re-save each request the session again. - +- Use ``should_set_cookie`` for preventing each request from saving the session again. +- Permanent session otherwise empty will not be saved. +- Use `secrets` module to generate session identifiers, with 256 bits of + entropy (was previously 122). +- Introduce SESSION_KEY_LENGTH to control the length of the session key in bytes, default is 32. +- Fix expiry is None bug in SQLAlchemy. Version 0.5.0 ------------- diff --git a/src/flask_session/__init__.py b/src/flask_session/__init__.py index c503e714..c4397cad 100644 --- a/src/flask_session/__init__.py +++ b/src/flask_session/__init__.py @@ -55,6 +55,7 @@ def _get_interface(self, app): config.setdefault('SESSION_PERMANENT', True) config.setdefault('SESSION_USE_SIGNER', False) config.setdefault('SESSION_KEY_PREFIX', 'session:') + config.setdefault('SESSION_ID_LENGTH', 32) config.setdefault('SESSION_REDIS', None) config.setdefault('SESSION_MEMCACHED', None) config.setdefault('SESSION_FILE_DIR', diff --git a/src/flask_session/sessions.py b/src/flask_session/sessions.py index 47cfbd62..3ee19d9f 100644 --- a/src/flask_session/sessions.py +++ b/src/flask_session/sessions.py @@ -2,7 +2,7 @@ import time from abc import ABC from datetime import datetime -from uuid import uuid4 +import secrets try: import cPickle as pickle except ImportError: @@ -56,22 +56,22 @@ class SqlAlchemySession(ServerSideSession): class SessionInterface(FlaskSessionInterface): - def _generate_sid(self): - return str(uuid4()) + def _generate_sid(self, session_id_length): + return secrets.token_urlsafe(session_id_length) - def _get_signer(self, app): + def __get_signer(self, app): if not hasattr(app, "secret_key") or not app.secret_key: raise KeyError("SECRET_KEY must be set when SESSION_USE_SIGNER=True") return Signer(app.secret_key, salt="flask-session", key_derivation="hmac") def _unsign(self, app, sid): - signer = self._get_signer(app) + signer = self.__get_signer(app) sid_as_bytes = signer.unsign(sid) sid = sid_as_bytes.decode() return sid def _sign(self, app, sid): - signer = self._get_signer(app) + signer = self.__get_signer(app) sid_as_bytes = want_bytes(sid) return signer.sign(sid_as_bytes).decode("utf-8") @@ -88,17 +88,18 @@ class ServerSideSessionInterface(SessionInterface, ABC): """Used to open a :class:`flask.sessions.ServerSideSessionInterface` instance. """ - def __init__(self, db, key_prefix, use_signer=False, permanent=True): + def __init__(self, db, key_prefix, use_signer=False, permanent=True, sid_length=32): self.db = db self.key_prefix = key_prefix self.use_signer = use_signer self.permanent = permanent + self.sid_length = sid_length self.has_same_site_capability = hasattr(self, "get_cookie_samesite") def set_cookie_to_response(self, app, session, response, expires): if self.use_signer: - session_id = self._get_signer(app).sign(want_bytes(session.sid)) + session_id = self._sign(app, session.sid) else: session_id = session.sid @@ -118,13 +119,13 @@ def set_cookie_to_response(self, app, session, response, expires): def open_session(self, app, request): sid = request.cookies.get(app.config["SESSION_COOKIE_NAME"]) if not sid: - sid = self._generate_sid() + sid = self._generate_sid(self.sid_length) return self.session_class(sid=sid, permanent=self.permanent) if self.use_signer: try: sid = self._unsign(app, sid) except BadSignature: - sid = self._generate_sid() + sid = self._generate_sid(self.sid_length) return self.session_class(sid=sid, permanent=self.permanent) return self.fetch_session_sid(sid)