tj / connect-redis

Redis session store for Connect

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Race condition on logout, session alive again

0x0ece opened this issue · comments

Hi, currently express-session + connect-redis suffer from a race condition on logout:

  1. ReqA starts and maybe modifies the session
  2. ReqB arrives and logs out
  3. ReqA terminates after ReqB and overrides the del by readding the session in redis

For context we've been working on (what we think is) a more secure fork of express-session, and also worked on a similar fix for connect-typeorm. The issue with redis came up discussing with a user interested in our fork, but using connect-redis.

TBH I'm not sure what the best solution would be with redis. IMO the real issue is express-session that offers a generic set instead of an explicit insert vs update, but it what it is... maybe an opportunity is to have a better/richer interface for stores.

If you have ideas, happy to work on a PR.

P.S: and big congrats on having 0 open issues, pretty rare!

Edit: renamed the package to express-session-jwt, so fixed the link above

This has always been a limitation of connect-redis (and other session storage implementations). Of course, this affects not just destroying sessions but also setting them. However, given the high use of this library, the issue has been seldom reported in my experience. Note that sessions have a TTL, which can be configured. If for some reason the session was recreated, it would be cleaned up by the TTL set on the keys when that time expired.

I don't know of a way we can account for concurrent session requests racing. On session deletion, the keys are gone by design. It seems we'd have to keep them around just in case something happens right away and try to clean them up but the rules around that don't seem clear IMO.

That my 2 cents.

I see it important to match connect-redis API with your implementation, but I have a feeling this issue exists in more stores. Have you any ideas on what you'd change in the express-session API? Any luck in discussing this with the maintainers there?

I read the past issues and it's clear that there's a race condition on concurrent updates. That's, however, an issue that only the application can solve, and not really a problem just with sessions.

Destroy is different because the user logs out and the session becomes alive again. Think you're on facebook, look at the list of your sessions, click destroy on one that you don't recognize... and that's not really destroyed.

I think there are 2 solutions here:

  1. Soft delete. That's easier on SQL-like stores than noSQL. You add a column destroyedAt = NULL by default, and rewrite the update query as UPDATE ... WHERE destroyedAt is NULL. In the memory store I kept a map of destroyed sessions and rewrote the updates as "if not destroyed, then update". In redis TBH I don't know what the most efficient solution would be.

  2. Add insert, update to the store api, instead of just set. In redis, these could be implemented with set nx, set xx. However this won't work with the original express-session, unless they also change interface. In this case the session flow would be calling the insert on creation, the update on touch & update. The destroy would delete, but the update wouldn't re-insert.

Hey @0x0ece , just acknowledging that I have read your comment and am still thinking about this. Part of the "perk" of this session storage library is we don't keep any sessions around after they are destroyed. We keep a low footprint and we stay fast. I don't love keeping session objects alive and adding a "cleanup" task in case sessions get quickly recreated as it adds more overhead to the process. It seems like your idea of differentiating from an insert versus an update may get around this?

I noticed your fork no longer exists, did this get moved? Ideally, any API change would be something that would get integrated into the main express-session project.

Hi, sorry for the broken link, we decided to rename it to express-session-jwt. Also, published the blog post.

I agree, reaching out to express-session might be the best solution. We could quickly prototype the new insert+update interface within express-session-jwt, provided they're interesting in supporting the new api as well. I'll consolidate the message and open an issue there.

This issue is stale because it has been open 30 days with no activity. Remove stale label or comment or this will be closed in 5 days.

I see you have a conversation started with @dougwilson on this matter. I will keep this case open to see if anything comes out that that may apply to this.

This issue is stale because it has been open 30 days with no activity. Remove stale label or comment or this will be closed in 5 days.

This issue was closed because it has been stalled for 5 days with no activity.

If this does get re-added it should probably be an optional feature, as merging various session states can break apps in other ways.
Possibly the app should be given the opportunity to decide what to do with two conflicting sessions.
Quite often an app would only care about if a user is logged out in either session update, has paid in either session update, or has been given something already.

Particularly, deepmerge concatenates arrays by default since v2, which can break all sorts of things, like causing the session size to spiral exponentially.