Express-session works wrong when website migrated from http to https? - node.js

After we migrated our website from http scheme to https (including enabling https on CDN and redirecting http to https on server), we found that our user sessions works incorrectly sometimes, that is, the user A would be recognized as user B! It seems the session ids of cookies are incorrectly parsed and maybe different users share the same cookies or session ids but all the session ids are generated by uid-safe uniquely.
The issue seems very strange and we really have no idea of the cause.
we use nodejs, Express, express-session with redis storage.
The express-session setup is as below:
app.use(session({
secret: 'xxxx',
cookie: {
maxAge: 3600*24*90*1000
},
store: new redisStore(),
resave: false,
rolling: true,
saveUninitialized: false
}));

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.

Sharing Redis Sessions Across Node Apps

I'm busy building a platform with 3 different subdomains - example.com, auth.example.com and api.example.com. They're run with 3 separate NodeJS apps running on different ports of the server.
Here is the code setting up the sessions:
var session = require("express-session");
var redisStore = require("connect-redis")(session);
var redisClient = require("redis").createClient(config.redis);
app.use(session({
secret: config.server.secret,
store: new redisStore(config.redis),
client: redisClient,
resave: false,
saveUninitialized: false,
cookie: {
domain: "example.co.za",
httpOnly: false
}
}));
The configuration is exactly the same for all 3 apps and they're sitting on the same server. For some reason, the sessions are not being shared. I seem to remember that they were being shared a few weeks back and now things are broken - I have a sneaky suspision that this happened when we moved all the traffic from HTTP to HTTPS. Would this break the sessions? I tried to turn of 'httpOnly' in case it restricted the sessions, but no luck.
I have run redid-cli MONITOR and the session is, in fact, being saved on login (Auth App) but is not being retrieved by the other app. When I turned saveUninitialized to true, the requests to save were coming from all 3 apps - this shows that they are connected to the same Redis Store.
Any help would be great.
I think this is just a cookie issue. The browser is not sending the session cookie back on your sub-domains:
you need a leading . on the domain. e.g.:
cookie: {
domain: ".example.co.za",
httpOnly: false
}
In case that doesn't work and you are having AJAX issues see this post

secure cookies node.js + Heroku + CloudFlare

I've looked at this answer and this answer but no dice. My problem is that when my app is accessed through https://appname.herokuapp.com, everything works fine. but when accessed through https://www.appname.com (which CloudFlare aliases to https://appname.herokuapp.com), it breaks down.
Specifically, when a user logs in, the authentication is processed correctly, but the user session cookie is not set properly. So when the logged-in user is forwarded to the next screen, the request gets rejected as unauthorized.
Right now I am doing this in express:
var mySession = session({
key: "sid",
secret: process.env.SESSIONS_SECRET,
proxy: true,
cookie: {
maxAge: 86400000,
secure: true,
},
store: rDBStore,
resave: false,
saveUninitialized: true,
unset: 'destroy'
});
app.enable('trust proxy');
app.use(mySession);
Am I missing something in my node code, or in my CloudFlare settings?
Could it possibly be related to that CloudFlare puts the node app instanece behind a proxy?
Quoted from expressjs/session documentation:
If you have your node.js behind a proxy and are using secure: true, you need to set "trust proxy" in express.
app.set('trust proxy', 1)
https://github.com/expressjs/session#cookiesecure

Node Express - difference between req.cookies and req.session.cookie

I am trying to find out what the difference is between req.cookies and req.session.cookie. I am using Passport for authentication in Node.js Express.
If I log these two lines in my code:
console.log('cookies',req.cookies);
console.log('session',req.session);
I get this output:
cookies { 'mysite.sid.uid.whatever': 's:Ltko5IdDgsAISG0smrKNYaeIVy8nbBzF.MkGmpnf6uUKITIAgN4ws3YXqxJrMaeeSCzlKdjQnqfI' }
session { cookie:
{ path: '/',
_expires: null,
originalMaxAge: null,
httpOnly: true,
secure: false },
views: 8,
passport: {} }
I am using this configuration:
app.use(bodyParser.json());
app.use(bodyParser.urlencoded());
app.use(busboyBodyParser());
//app.use(busboy());
app.use(cookieParser('cookie parser secret'));
app.use(session({
secret: process.env["SESSION_SECRET"],
saveUninitialized: true, // (default: true)
resave: true, // (default: true)
store: require('mongoose-session')(mongoose),
maxAge: 60000,
key: "mysite.sid.uid.whatever",
cookie: {secure: false}
}));
I don't really know the difference between using sessions or cookies, except that cookies are client-side only and sessions could be either client or server-side. I have read the documentation from Passport.js a few times, but I still don't really understand what is going on here. Can someone help me out with some explanation? As far as I can tell, it seems best to use server-side session using Redis. But I don't see how you can get away from using client-side data in the end. At some point, you have to rely on the client-side data stored right?
after I login with the express app, the passport object gets populated with a user field, with the MongoDB objectid.
passport: { user: 549290b8246f0e1408e48b13 } }
Typically you will be using cookies when serving browsers. The exception to this being authenticating via an HTTP header or POST parameter token, which are more typical for API requests for example.
It is true you can do client side or server side sessions using cookies, where the entire session data is stored in the cookie in the former (and does not use any storage server-side) or session data is stored server-side (with a session ID stored in a client-side cookie) in the latter.
req.cookies contains cookie values only, no matter if the cookies are session related or not. req.session.cookie contains the Set-Cookie parameters used in the client-side session ID cookie.

session persistence between sub domains

I am having two subdomains, api.abc.com and beta.abc.com. Both of them are on same server (box), api.abc.com is running on port 4000 and the beta.abc.com is running on 5000. I am also using node-htty-proxy to reverse proxy the requests. beta.abc.com is used to serve only static content, while api.abc.com returns the response in json.
The user authentication is done through facebook oauth on the server (api) side. Once that is done, session is created and the user is redirected to the beta. The problem I am having here is I am not able to persist sessions! I tried giving the domain option in the cookie obj (as i had seen in other questions), even that din't work.
app.use(express.session({
secret: 'omg'
, store: new mongoStore({
url: config.db.uri
, collection: 'sessions'
})
, cookie: {
domain: ".abc.com"
, maxAge: 1000*60*60*24*30*12
}
}))
How do I go about this? Am I doing anything wrong?
I found a very similar question here.

Resources