flask: Invalidate sessions and JWTs when a user's password changes (1/3 split of #73) - #74
Open
RudraBJoshi wants to merge 1 commit into
Conversation
*** REQUIRED BEFORE THIS DEPLOYS: production runs MySQL (see __init__.py --
SQLALCHEMY_DATABASE_URI switches to MySQL whenever DB_ENDPOINT/DB_USERNAME/
DB_PASSWORD are set), a completely separate database this session had no
access to. Only the local dev SQLite DB has been migrated. Someone MUST run
this against production before/with this deploy, or every login there will
error on the missing column:
ALTER TABLE users ADD COLUMN token_version INTEGER NOT NULL DEFAULT 0;
***
Previously nothing tied an issued JWT or Flask-Login session to a specific
password: the JWT carried no exp claim at all (never expired by JWT
semantics) and no password-derived data, and Flask-Login sessions just
carried a bare user id, re-validated against fresh DB data on every request
but with no check that the underlying credential hadn't changed. A stolen
JWT or session cookie kept working indefinitely, surviving a password reset
that was meant to lock an attacker out.
Adds User.token_version, bumped in set_password() (the single funnel every
password-change path already goes through) only on an actual hash change.
JWTs now carry token_version + exp and are checked against the account's
current value in auth_required. Sessions now carry it via a composite
get_id() ("id:token_version"), checked in load_user (main.py), so a stale
session is rejected before ever reaching a @login_required route instead of
running with outdated auth state.
Verified live: fresh JWT/session -> 200, password reset -> old JWT gets 401
with an explicit "password has changed" message, old session gets redirected
to login, fresh login after the reset works again.
Author
|
@jmort1021 accept the pull request pls so Dhyan can add the schema |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Splitting #73 into smaller, independently-reviewable PRs across spring/flask/pages. This one covers the password reset button side of flask — session/JWT invalidation on password change.
Independent of the other PRs in this stack.
Previously nothing tied an issued JWT or Flask-Login session to a specific password: the JWT had no
expclaim at all and carried nothing password-derived, and sessions carried a bare user id. A stolen JWT or session cookie kept working indefinitely, surviving a password reset meant to lock an attacker out.Adds
User.token_version, bumped inset_password()only on an actual hash change. JWTs now carrytoken_version+expand are checked against the account's current value; sessions carry it via a compositeget_id(), checked inload_user.Requires a schema change before deploy:
ALTER TABLE users ADD COLUMN token_version INTEGER NOT NULL DEFAULT 0;Original PR: #73