2

Okay, so I am just getting in to the MEAN stack, and I'm trying to build an app with Passport.js.

I'm just starting user serialization to maintain sessions. In their example, Passport uses this for serialization and deserialization:

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

passport.deserializeUser(function(id, done) {
  User.findById(id, function(err, user) {
    done(err, user);
  });
});

So, my question is this: is this example considered secure? If I understand this right, doesn't that mean that a client could just fake the user ID to become logged in as whichever user has that ID?

I guess what I'm asking is, is their example considered "secure" and a proper way of doing things, or is it expected that you will change these functions to generate unique serialization. If this is considered secure, then I think I'm missing something on how this works, and I'd love to be filled in.

On the other hand, if this is not secure and I am expected to write my own functions in place of these, would the following be a valid and secure way of doing this:

  • Upon serialization of a user, generate a random hash and put that in the user's database entry. Random hash is the serial that represents that user.
  • Upon deserialization, look up the random hash in the database and return the corresponding user. If the hash isn't found throw some kind of error.
  • When the user logs out, delete their serial hash from their entry in the database.

If my logic up until here is valid, what would be a proper way to generate this random hash?

danielhep
  • 346
  • 1
  • 7

1 Answers1

2

Yes, that is how you do serialization / deserialization. The id is not received from the client.

Session information is stored to your local session store, eg. database, under a random ID. For example, express-session uses uid-safe to generate the session ID. This ID is set to a cookie which is then sent to the client.

When the client makes a request, the session ID is read from the cookie if it has not been tampered (usually the ID is signed with the secret you define when intializing sessions). Using this ID, the real session data is read from your local session store. This is where the id used in deserialization comes from.

Here is an example what a session object stored to MongoDB could look like:

{
  "_id" : "_RXnIfFeb_qH6AXMO2ounrxlJZPHkwda",
  "session" : "{\"cookie\":{\"originalMaxAge\":null,\"expires\":null,\"secure\":false,\"httpOnly\":true,\"path\":\"/\"},\"passport\":{\"user\":\"5614c62e4372842244660dcf\"}}"
}

The _id here is what is signed and sent in the cookie. The session string, decoded to JSON object, is:

{
  "cookie": {
    "originalMaxAge": null,
    "expires": null,
    "secure": false,
    "httpOnly": true,
    "path": "/"
  },
  "passport": {
    "user": "5614c62e4372842244660dcf"
  }
}

Here, passport.user is the actual user ID returned by my applications seralizeUser that is given to deserializeUser when a session is being loaded.

So what happens if you change the cookie content? If the cookie is signed, it will be invalidated because the altered value does not match the signature. If it is not signed, the value is used when querying session store. The query will not return anything because you changed the ID and there is no matching session in the database (unless you have found out / guessed the session ID of another active session - ie. performing session hijacking).

Community
  • 1
  • 1
vesse
  • 4,871
  • 26
  • 35
  • Okay, ultimately then, passport.user can be whatever I want it to be since it's not being sent to the client anyway, right? – danielhep Oct 07 '15 at 13:40
  • Theoretically yes, but haven't ever tried if returning eg. objects or arrays work. – vesse Oct 08 '15 at 11:17