Node js - user auth, what to store in session? - node.js

First of all, I did not find any similar questions or material that will be useful. I'm sorry if I missed something!
Second of all, I'm not interested in ready solutions like node-passport or connect-auth or everyauth
Now to the question. I'm using Redis to store the express session. My question is, when user is authenticating (i.e. after a post of username & password was made and such user was found in the collection) what should I store in the session?
I can store the whole user object (for example, the way it came from MongoDB). One disadvantage that I see, is that when user is being modified in the DB (he edited his profile), Ill have to "re-set" the user object in session. It gets even more complex if for example the user's profile is changed by administrator - in that case the session have no idea that the user was modified and its data needs to be refreshed from the DB hence the sessions is currently holding outdated user object that will be updated only the next time the user logs in.
Create a collection of "hash => userid" and store in session only the hash. Then every request, call a middleware that will check (pseudo code below, omitted the check for non existing hash, in that case user might be considered as not logged in since the session expired):
if(userhash in req.session) res.local.user = db.users.findById(db.sessions.findUserIdByHash(req.session.userhash));
Well the obvious disadvantage of this method, is the additional collection (i.e. mongodb) or key => value (i.e. redis) storage for hash => userid which also requires some procedure to clean old session hashes (scheduled task\cron that will run and delete old expired hashes).
Another solution similar to #2, instead of using 3-d party collection/key=>value storage, store the hash as part User object in MongoDB. This method however eliminates the extra collection/redis key value, but still required a scheduled task to clean old, expired sessions. And since expired session will probably be defined by "expire date" attribute, its easier to maintain 3-d party collection for active session, instead of putting session related data into User object in MongoDB (thus making the User object huge).
I'm new to Node-js this why I ask. I also understand that there might be no correct answer, and or it might be bounded to personal preferences.
Thank you!

There's really nothing special about a session in Node/Express as compared to traditional frameworks (like PHP/ASP/whatever). What would you do with a user login in PHP?
Just store the user ID in session. Pull the user data from Mongo when needed.
Session data is secure (in that a client can't fiddle with it like they could with a cookie), so you can rely on a session's user ID pointing to user data that has been properly authenticated.

Related

Is there a way for me to "persist" data on an expressjs app?

guys!
I got an expressjs application, an app service. On one of my routers the user will be redirected to another server(e.g: monkeyserver), some data is sent to monkeyserver (a random value, a url to send the user back to my expressjs application and some other stuff). The monkeyserver will send me back that random value so I can check if we are still friends.
So the doubt here is that random value variable(e.g: me_var). What's the simplest way for me to save that me_var so when the user is sent back to my app I can check if me_var value is still the same.
It's hard to understand the exact circumstances you're describing. If you have a way to identify a given http request as belonging to a particular user (session cookie created at user login is the usual way to do this), then you can store information for a particular user in a session store that is tied to the session cookie. Then, sometime later when the user returns, you can still access that same data that corresponds to that user. A session store may be long term persistent (database) or it may be shorter term only (memory store), depending upon how you implement your own session storage.
So, for your random value that will come back to you later in an URL, you can just store the original in the session store. Then, when the user comes back, that route they come back to can check the value in the URL (presumably as a query parameter) and compare it to the value in the session store to see if they still match and you can then act accordingly.

Is it safe to put the entire user in a session vs just the user ID for node/express?

I am using node/express and was wondering if it is safe to put the entire user object in the session rather than just the Id. If I do just the Id then this means I must make another DB call when I go to get the currentUser.
I have seen people do it, but if it is more safe to just put the Id then I will go about doing that. I should state that I would take the password off the user before attaching it to the session or any other sensitive data.
There's nothing especially unsafe about it, but generally not considered a good practice. When you update your user data, you have to update your session and database, so now you have to keep those in sync, which creates challenges.
Also keep in mind your session store. The more data in your session, the larger the storage requirements for your session store, maybe not a problem, but something to consider.

General user session handling (Nodejs)

I wrote a simple webserver with nodejs and express. I implemented an user authentication with email username and password. Furthermore I have a remember-function which stores the user id and pwd hash into a cookie. Now I would like an extra session that ends when the user will close his browser or click to the logout button.
Which way is the best practice for implementation? Is the session the same like the remember-function with an expire time and in each request I must check the credentials against the database? (I'm not that sure about this)
Technologies that I'm using: nodejs, express, mongodb
This is not a nodejs question only, I would prefer a general explanation for the problem.
Let me get this out of the way first; Storing the password hash into a cookie would allow anyone to login when they have the password hash and that would be disastrous if the password hashes ever got exposed for some reason. Encrypting cookies is just fine, but don't allow the actual hash you store in the database to be used for authentication. Ever.
About re-authentication, Node is a technology that operates on a single thread and is scaled by running more instances over multiple processors and/or machines. Keeping sessions is a good idea to avoid trips to the database, but you have to think about the architecture as well. What happens if you, say, use sessions stored in files (ala PHP) and you need to scale to multiple machines? Nothing good, at least. So you need a central point to keep track of the sessions.
This can be either your database (MongoDB) or something such as Redis, or another centralized mechanism allowing you to check sessions. Either way, you will have to spend time doing the request and retrieving the session values for the client. If you do not have additional values you need to store it makes no sense to create a dedicated session architecture (that needs expiration, and so forth) and just doing the authentication again is the easiest and most logical solution.
Personally I almost never need sessions and just do authentication again.

HTTP Remember me authentication

I'm trying to write a simple HTTP remember me authentication system for users.
My users could be represented as such
{
"email" : "foo#bar.com",
"password" : "8EC41F4334C1B9615F930270A4F8BBC2F5A2FCD3" // sha1 hash of password
}
So my idea is that I need to create a cookie, with indefinite (really long) expiration time, that will hold some type of information to enable me to fetch the user from the database, therefore logging the user in.
My first idea was to just simply store the email:password string as a cookie. I thought this would be good since nobody else can really generate that type of information other than the user itself, and I could retrieve the user quite easily by simply comparing the username and password based on what's in the database.
However then I thought this wasn't really good. It turns the password digest into, effectively, a second password that's stored in the clear and passed over the wire in every request.
So then I thought maybe I could generate a signature each time the user logs in, which would basically be a random hash that is stored directly in the user object in the database.
The user logs in, it generates this signature that is stored, and the cookie holds this signature. Whenever you access the website, the site checks which user has that particular signature and logs the user in. Logging out will effectively erase the cookie, and new logins will generate a new random signature.
Does this approach take into account any other vulnerabilities?
I know, I should probably use a library already made for this, but this is just simply an exercise in web-security.
This is essentially what most sites do when you log in. Yes, the cookie should hold a unique identifier for the user's "session". The cookie should be essentially random. Up to you whether to make it persistent across browser sessions.
Along with the cookie in your authentication DB, also store a timestamp of when the entry was created. Cookies older than N seconds should be considered invalid (set N to your taste). You can reset the timestamp each time the cookie is used so that idle sessions time out.
Note that the same user may want to have multiple sessions (do you ever log in to your Email account from both home and work?), so the concept here really is "session", not user.
Vulnerability point-of-view both are same! Cookie stealing and related mechanisms however browsers are smart enough now so you shouldn't worry about that.
Second approach is good in terms of privacy as well since it does not includes email address in the cookie. And it seems much more similar to like storing the sessionID which in your case you are generating a random hash and storing it in DB.
But i think it would be more wiser to use the first approach; you can add another layer to the digest and encrypt it with your some algo or private key; to be on safer side.

Is it safe to store user object in a cookie?

I have a user object which contains information about the user (username, ip, country, name, email... but NOT password).
Should I store just the username in the cookie and then retrieve all info from DB upon loading the page, or just store the entire User object in the cookie?
You can't trust any information stored in a cookie, as the user can manipulate it at his/her leisure.
I suggest using a PHP session to store the object. That way, the end user only has a session ID stored in a cookie, with the real data on your server.
The session will eventually time out, though... forcing the user to log in again.
Edit: Whoops, I should point out that sessions are really easy to use. Just do the following:
session_start(); // This MUST be at the very top of every page that accesses the session
// Store something in the session with the key 'something'
$_SESSION['something'] = "Hi, I'm a session!";
// Retrieve 'something' from the session
$myString = $_SESSION['something'];
The standard rule of 'never trust posted data' applies to cookies too. I suggest storing just the user ID as well as a hash of the ID and some secret known only to the server.
For that case, I'd say store the user-id in the cookie and that's it. Then, upon first load of the page you load everything you need from the database and go on using a session as long as the user stays on your page.
To test if the page is loaded the first time, I just set a bool in the session if it has been loaded. If the bool doesn't exist, your user loads it initially.
There are probably better ways of doing this, but it works nice and easy. :)
Only store a session id! Never meaningful data such as user id. Imagine that you have a site with 10,000 users. Chances are that you have at least one user called superman and batman - if yous tore a username in a cookie to access your session information - it is potentially feasible for me to manipulate that cookie to change stored info from my username to batman and gain access to batman's account if his session is still alive. If you store some sort of randomly generated session id - it's pretty much impossible for me to figure out a session number that would work for another user to hijack that session.
You can trust information in the cookie if you use something like Hmac. Users could still see the data, but you would know if they had tampered with it (for example, changing their username to someone's else's in an attempt to see another user's data). If you don't want them to see the data, you could also symettrically encrypt the data you're sending. Obviously there's a CPU overhead to all of this, and a bandwidth overhead the more stuff you cram in there, but it's entirely legitimate to do what you're asking.
You can't assume the username being passed from a cookie is the actual username you wrote to the cookie. That is why they suggested using the sessionID. Using the sessionID you can go get the username and like he said is only good for 20 minutes or whatever you set your session timeout to be. SessionID doesn't reveal any private data. I had your same thought before I found this post though.

Resources