To avoid an attack known as a “session fixation attack”, where the attacker is able to force your web application to use a specific session id, you’re supposed to be the good guy and regenerate the session id when a user logs in or register (or if you really want to, on every request to have a fleeting session id – but this will also require extra traffic towards your session backend, even if the server side content of the session itself doesn’t change).
Flask-Session supports this through their regenerate
function, which you can call on the defined session
interface (either through app.session_interface
or, in a blueprint, through current_app.session_interface
).
Some language models (regardless of them qualifying themselves as either large or small) are going to say “just use session.clear()
and the session token will be regenerated”, but they’ll be wrong (at least for Flask 3.1).
So you try to do it yourself – you log out of your account, and then sign in again, and by calling regenerate()
in your sign in function, you expect the session token to be regenerated from whatever it previously was.
But that doesn’t happen.
Your code would look like (in a blueprint):
session.clear()
current_app.session_interface.regenerate(session)
session['user_id'] = user.id
return redirect(url_for('index'))
.. but nothing changes. Well, it turns out that Flask-Session guards it regenerate() function with a check for a true-ish value, instead of checking if there’s a valid session given:
def regenerate(self, session: ServerSideSession) -> None:
"""Regenerate the session id for the given session. Can be used by calling ``flask.session_interface.regenerate()``."""
if session:
# Remove the old session from storage
self._delete_session(self._get_store_id(session.sid))
# Generate a new session ID
new_sid = self._generate_sid(self.sid_length)
session.sid = new_sid
# Mark the session as modified to ensure it gets saved
session.modified = True
And this is where the issue happens – since you’ve done what you should be doing – clearing the session, not trusting whatever might be there; you’re left with an empty session dictionary, which will evaluate to a false-y value, and not a true-ish value – so since the session is empty, the code will never run.
The answer is to ask Flask-Session nicely to regenerate the session id after you’ve populated with the user’s information:
session.clear()
session['user_id'] = user.id
current_app.session_interface.regenerate(session)
That way the Flask-Session will be happy with you, since you now have a session that will be seen as true-ish instead, and the world will rejoice.
And that, my friends, was what made me write another post here to document something weird after eight years of hiatus.