Express-session not deleting previous sessions - node.js

I am currently working on a new project and I use sessions with the express-session library.
Here is the code where I set up the session:
const IN_PROD = process.env.MODE==='production'
app.use(session({
name: 'sid',
secret: 'asecret',
store: new MongoStore({
mongooseConnection: mongoose.connection,
collection: 'sessions'
}),
saveUninitialized: false,
resave: false,
cookie: {
sameSite: true,
secure: IN_PROD,
expires: new Date(new Date().getTime() + 1000 * 60 * 60 * 24)
}
}))
Imagine the following steps:
1) My server sends a session id (sid=A) in a cookie to my client.
2) The client manually deletes the cookie
3) At the next request, the client sends another session id (sid=B)
Is it normal that both A and B cookies are stored in the database and the first one is not overridden?

It is normal. It is up to either you or the session store you use to clean up older sessions.
If you look at the MongoStore() documentation, you will see that it has several features related to automatic removal of session objects.
Here's one example:
// connect-mongo will take care of removing expired sessions, using defined interval.
app.use(session({
store: new MongoStore({
url: 'mongodb://localhost/test-app',
autoRemove: 'interval',
autoRemoveInterval: 10 // In minutes
})
}));
Keep in mind that at the express-session level, a session is just a blob of data associated with a cookie. Any time a browser makes a request to your server and no session cookie exists, a new session cookie is created and a new express-session object that is connected to that new cookie.
If the user then deletes that cookie and connects to your server again, express-session has no idea that this browser is the same browser as the previous session. The original cookie is the only way it could know that and the cookie is now gone. So, express-session just sees a new browser connecting to your server that doesn't have a session cookie so it creates a new cookie and then creates a new session object to go with it.
Any association of a logged in user with an express session is done at your application level (by putting user-identification information into the session object) and express-session is not aware of that at all.

Related

express-session secure: true

app.use(session({
secret: "testing credentials",
store: sessionStore,
resave: true,
saveUninitialized: true,
cookie : {
httpOnly: true,
//secure: true,
maxAge : 60 * 60 * 1000
}
}));
I'm working on some security problems on my newly developed website. And after done some research online, if secure=true is set, then it will be more secure. However,
If set secure: true, then information inside session will lose every time when the user send another request. Is there a way to solve this problem? If doesn't include "secure: true" in the cookie: , then the session will last for that maxAge.
If a cookie is set with the secure flag, it will only be sent to the server by the browser over https, and not plain http. This should be the default for production environments.
However, when developing an app, you probably use plain http on your dev machine. If you set your session cookie as secure in this case (using plain http), the server will never receive it, and you will experience a new empty session on each request.
So in short, you should only set the cookie as secure if you are using https (that is, in later stages of your development pipeline, and definitely in production).
On another note, if you set maxAge, the cookie will be persisted, which is not the best practice for session cookies. Without maxAge, the cookie will be kept until the user closes the browser and not normally persisted to disk, which is the correct behaviour for session cookies.

My Node.js web app establishes new session every time I reopen the browser

Every time I close all the browser windows and then open the web app again, a new session is established, that means I have to authenticate again.
For your reference, I use express#4.14.0 as the web application framework, express-session#1.14.1 + connect-mongo#1.3.2 as middleware to store the sessions and passport#0.3.2 for authentication.
Below is the code for cookie and session configuration:
// CookieParser should be above session
app.use(cookieParser());
// Express MongoDB session storage
app.use(session({
resave: true,
saveUninitialized: true,
name: config.sessionName,
secret: config.sessionSecret,
store: new MongoStore({
mongooseConnection: db.connection,
collection: config.sessionCollection
})
}));
The "old" session stored in MongoDB still has two weeks to expire.
It seems like the Node.js application cannot recognize the "old" session from browser, therefore create a "new" one and tell the browser to use the "new" one.
It does not happen occasionally, but always, so I believe there is something wrong in my web application.
Thanks to #Bradley, finally I figured out what's wrong.
This is my solution
app.use(session({
cookie: {
maxAge: ms('14 days') // `ms` is a node module to convert string into milliseconds
},
resave: true,
saveUninitialized: true,
name: config.sessionName,
secret: config.sessionSecret,
store: new MongoStore({
mongooseConnection: db.connection,
collection: config.sessionCollection
})
}));
For more information, please refer to https://github.com/expressjs/session#expires
By default, no expiration is set, and most clients will consider this a "non-persistent cookie" and will delete it on a condition like exiting a web browser application.
That's why I encountered this problem.

Node/Express with connect-redis, how handle session expiry

I have a Node/Express application that use redis as session store.
I have a question concerning the handling of the expiry of the session.
I'd like have an active session until the browser is closed, so I didn't set a session expiration time.
Doing that the session cookie works fine, but I have a doubt about Redis.
It seems that the couple Key/Value stored in Redis DB never expire.
How is the right way to handle this?
There is a way to configure redis to destroy a value stored with a certain idle time?
Or is better set a TTL when the connect-redis is invoked inside the application?
Actual configuration of the session inside the application:
var session = require('express-session');
var RedisStore = require('connect-redis')(session);
app.use(session({
store: new RedisStore({port:6379, host: 'localhost'}),
secret: "my-secret-here",
resave: false,
saveUninitialized: true }));
Using Redis with express-session, you can use the touch() method from express-session to reset the TTL. So if you set a TTL when creating the session, do something like this on the routes where you don't want the session to expire:
api.get("/someRoute/", (req, res) => {
req.session.touch();
// Whatever else you need to do
res.sendStatus(200);
}
That will reset the TTL on Redis and prevent the session from expiring assuming the client is still hitting your API - I'm assuming that if the client doesn't interact with your API for long enough, that implies the browser is closed or otherwise finished using your app.
You can specify a ttl while creating the session store.
You can find more options in the readme.
app.use(session({
store: new RedisStore(options),
secret: 'keyboard cat',
ttl : 20 // ttl is in seconds. From the readme.
}));

Express and Redis - If session exists for this user, don't allow access

I am using Redis and Express like this:
// app.js
var redis = require('redis'),
redisClient = redis.createClient(),
session = require('express-session'),
RedisStore = require('connect-redis')(session);
session = session({
store: new RedisStore({client: redisClient}),
secret: 'secretKey',
resave: true,
saveUninitialized: true
})
app.use(session);
In my index route file, I set a user session like this:
req.session.user = user;
When this user comes back (or opens another tab), how could I detect how many sessions he is currently having and block him access if he already has one active session?
express-session working via cookies. So you had cookie named session with some sessionId. All tabs inside browsed share cookies and you can't rely on cookies if you want to strict working via only one browser tab.
You need to create your own Sessions for each opened browser tab. Something like generating tabId at client side and saving {userId, tabId} to Redis
Or you can use websockets (http://socket.io/) for that, a little overhead, but doing exactly what you want

Controlling Session Start with LocomotiveJS

I know it is possible to control session start with express and connect middleware. Like suggested here: Controlling Session Start with express and connect middleware
Is it possible to control session start with LocomotiveJS?
I don't want to start session for every user - I just want to start it when user successfully logs in.
I'm already storing session in MongoDb (myabe in the future I will use Redis) and creating not required session for every user which enter the page seems to be a waste of resources.
I just found the solution:
Maybe LcomotiveJS itself does not support it directly, but it can be easily implemented using Express (and Locomotive is on top of it).
Instead of declaring session as:
this.use(express.cookieParser());
this.use(express.session({
secret: '123qwemax',
cookie: {maxAge: 60 * 60 * 1000},
store: new MongoStore({
url: 'mongodb://localhost:27017/tests'
}),
}));
Declare your session as:
this.get(/^\/login\/.*/, express.cookieParser());
this.get(/^\/login\/.*/, express.session({
secret: '123qwemax',
cookie: {maxAge: 60 * 60 * 1000},
store: new MongoStore({
url: 'mongodb://localhost:27017/tests'
}),
}));
This way session will start any time we will go to /login/.* pages.
I don't know why this.all was not working...

Resources