Reputation: 7958
I'm using redis as a session store,
Storing sessions like so
[NameSpace]:[UniqueId] -> [email_id]
when a user resets their password, how do I invalidate all the sessions of that user ?
Here are the solutions I came up with,
Store sessions like so
[NameSpace]:[UniqueId]-[email_id] -> [email_id]
Then I can use SCAN MATCH
to delete all the keys when the user resets the password.
After storing sessions like
[NameSpace]:[UniqueId] -> [email_id]
Maintain a separate list with
[NameSpace2]:[email_id] -> [ "[UniqueId]", "[UniqueId]" ]
and invalidate the sessions using the list. (I can use redis
namespace pubsub to maintain the validity of the above list)
[UniqueId]-[email_id]
in the cookie ? PS: I'm aware that there is a similar question but I felt that it was noisy and geared towards express.js instead of being generic for redis and user-sessions. (Invalidating all of a single user's sessions in express.js)
Upvotes: 8
Views: 4550
Reputation: 15773
Based on your examples, it appears you are storing sessions as a key-->single value pair, and that a user can have multiple sessions. There are a few ways you can deal with this.
Use a very short expiration and refresh on page load. As part of the password changing code you pull the session ID from the user's session and delete it. The short expiration ensures old sessions are removed.
Use a hash or set of hashes. Depending on user count you can either use a single hash, if "small" user base, or hash them into buckets. You can then store namespace:sessions[userid] -> email for your session. At this point you can easily remove the single user session,and you don't have duplicate sessions. You do lose the ability to automatically expire sessions.
Use hashes, sorted sets, and a scheduled task for cleanups. In this method you use the session ID as the key to a hash which has session keys and their values. Two of those members are creation and last seen time stamps. You can then use another hash for each user which maps sessionid to last seen time stamp. With this you keep the update on page refresh from option 1, but you have an easy to get list of sessions for each user. This does not, however, prune old sessions. You can expire a hash, but you'd have to either expire both and update both on page view, or us a scheduled task.
For that you can use a sorted set which has session ID as the member and timestamp as the score. Now you can use standard sorted set queries such as zrangebyscore to get all sessions older than a certain timestamp into a list, then delete those keys and members.
You could prevent multiple session with this option by having your session creation code check the user's session hash for existence and either use expiration or have the session creation code check for last update being within your active session criteria and re-use it or clear transient members from it. Because you either have a single session or can easily pull a list, and hopefully have expiration and/or a scheduled task to prune old ones, managing sessions becomes much easier - and without the need for scan or keys.
I'd recommend single-session per user and liberal use of expiration.
Upvotes: 1
Reputation: 11185
Maintain a set of all user sessions
[NameSpace]:[email_id] -> {}
Each session identifier is a value in the set. If you'd like to store session attributes use a map sessionIdentifier1 -> sessionProperties1
(lookup and deletion costs are the same)
[NameSpace]:[email_id] -> {sessionIdentifier1 , sessionIdentifier2}
Bulk session invalidation - Delete the key [NameSpace]:[email_id]
. Cost O(1).
Looking up a sessionIdentifier - SISMEMBER sessionIdentifier1
of the key [NameSpace]:[email_id]
. Cost O(1).
Are there any security issues with storing the session-id like [UniqueId]-[email_id] in the cookie ?
It depends. If the cookie is not HttpOnly
it would allow malicious JS to read that cookie through a XSS vulnerability. You could leave yourself open to phishing attacks. You can use the user's internal UUID
instead.
Upvotes: 3
Reputation: 49942
Re. 1 - since the number of active user sessions is far lower (presumably) from that of the total number of sessions in the database, I'd go for manually managing the active sessions per user rather than SCAN
ning. I would, however, use a set per user to store the active sessions key identifiers rather than a list because you want to be able to effectively add and remove active sessions from it. If the user has a lot of active sessions that need to be bulk-invalidated, you can use SSCAN
instead of SMEMBERS
.
Re. 2 - if someone got into your app/db server there are a lot of security issues :)
Upvotes: 1