0

I am running an Express node.js app that allows users to login with the PassportJS local or LinkedIn strategies and, for most users, that's working fine - they log in and see their profiles.

For a small set of users (maybe 5%), when they first click 'sign up' then their browser seems to read another user's authenticated session cookie so they are immediately taken to a different user's profile. These users all work for the same employer but are spread across different geographical sites (not sharing a computer as I'd initially hoped).

Their IT services aren't very helpful, so I'd be grateful if anyone has experience with a similar scenario where sessions seem to be shared when they shouldn't be? Is this likely to be an issue on my part, or their IT infrastructure?

And I've tried the answer from a similar question, adding app.disable('view cache'); to my app.js, but no joy.

My sessions are set up with Redis so my app.js looks like:

var express = require('express');
var app = express();
var path = require('path');
var port = process.env.PORT || 3000;
var favicon = require('serve-favicon');
var logger = require('morgan');
var cookieParser = require('cookie-parser');
var bodyParser = require('body-parser');
var passport = require('passport');
var LinkedInStrategy = require('passport-linkedin').Strategy;
var LocalStrategy = require('passport-local').Strategy;
var config = require('./config').config();
var bcrypt = require('bcrypt-nodejs');
var helmet = require('helmet')
var Model = require('./data/models/model');

app.disable('view cache');

app.use(session({ 
  store: new RedisStore({
  host: '127.0.0.1',
  port: 6379
}), secret: 'mysecretkey' }));

app.use(passport.initialize());
app.use(passport.session());

// view engine and routes here

passport.serializeUser(function(user, done) {
  done(null, user);
});

passport.deserializeUser(function(obj, done) {
  if (obj.provider != 'linkedin'){
    new Model.User({id: obj.id}).fetch().then(function(user) {
      done(null, user.attributes);
    })
  }
  else {
    new Model.User({email: obj.emails[0].value}).fetch().then(function(data) {
      if(data != null){
        return done(null, data.attributes);
      }
      else{
        return done(null, obj);
      }
    })
  }  
});

app.listen(port);

#update2

My nginx config:

  location / {
    proxy_pass http://1.2.3.4:3000;
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection 'upgrade';
    proxy_set_header Host $host;
    proxy_cache_bypass $http_upgrade;
  }
Community
  • 1
  • 1
Wikooo
  • 29
  • 5
  • Do you have a reverse proxy like nginx or Apache in front? It sounds like you need to Vary on cookie (or just not cache). – MrWillihog Jun 13 '16 at 14:12
  • Yep, I have nginx sitting in front of my app. I'm struggling to crack how the vary on cookie line works and where it should be added - does it need to be added to the nginx config in #update2? – Wikooo Jun 13 '16 at 14:56
  • The way caching works is - for a given URL and set of headers the server will store a cached version. For this example, lets imagine that we only vary by URL. User A comes along and hits /myaccount. The server caches this. User B comes along and hits /myaccount. The server sees that it is in cache and returns the cached version (User A's account!!). If we add Vary Cookie, only unique combinations of url and cookie (where the user authentication is stored) will match. I.e., User A's `/myaccount` is different to User B's `/myaccount`. – MrWillihog Jun 13 '16 at 15:01
  • To establish if this is the case you can look at the headers being sent back - open Chrome Inspector and look at the network tab - in the response you should see a `Cache-Control` header. If it is a caching issue, it might be better to just specify `nocache` for sensitive pages. – MrWillihog Jun 13 '16 at 15:02
  • @mrwillihog That's exactly what seems to be happening for some users - possibly those on a shared ip or on an old corporate network. In Chrome, once logged in, I see `Cache-Control:max-age=0`. I thought adding `res.header("Cache-Control", "no-cache, no-store");` to my route should fix the problem but I'm still getting 'max-age=0' – Wikooo Jun 13 '16 at 15:51
  • Are you looking at the Request Headers, rather than the Response Headers section? – MrWillihog Jun 13 '16 at 15:58
  • @mrwillihog ah, yes, that's what I was looking at - apologies. When I tried to set the `res.header...` nothing came up under Response Headers. Could you also point out where I'd need to add `nocache` for the sensitive pages? In headers set for the routes of those pages? – Wikooo Jun 13 '16 at 16:30

0 Answers0