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.
Related
I was using the Node library https://github.com/expressjs/session and noticed that it requires a secret to be specified for signing the session ID cookie.
If just the session ID is being stored in the cookie, and not any data, what is the use in signing the cookie?
My reasoning is that if someone wanted to modify a session ID cookie, then that's fine if the session ID sufficiently long to prevent brute force attacks. Am I missing something?
I questioned this as well and the only answers I could think of were,
a) If someone (for no good reason?) changes the default session ID
generation to a non-cryptographically random session ID, signing it
helps prevent attackers generating valid session IDs.
b) Reduce round trips to the session store by validating the session
ID using the signature/HMAC. (I can only imagine this being a problem
for DoS attacks).
Both seem like valid reasons though using good session caching would negate the need for b) and assuming your library's users are daft enough to change the default session ID generation, it seems a bit much to safe-guard against their own stupidity when the majority of users would just use the default generation algorithm.
If you store just id of session there is not reason to encrypt it. You are right.
You need to encrypt if you store some session data inside cookie, not only id.
This will prevent users of changing session data.
A session_id cookie is anything (number or alphanumeric) which identifies a client to a server, which in turns stores (usually temporary) data on the server accessed through this session_id/key.
The point is, if the cookie is going to be passed forth and back over HTTP, it doesn't matter whether you have "signed" it or not. Any man-in-the-middle could get your "signed/encrypted session_id" and make further requests pretending be the proper user. And I mean, this attacker doesn't have to care which information is inside the encrypted data, he could pass the exactly same signed/encrypted data, and the server couldn't figure out if it comes really from the right user.
In cases like these, you have to figure out if the privacy is important, if so, don't think too much, you got have to use HTTPS. If you understand it is not so important, don't waste your "processing time" signing/encrypting and decrypting your session id.
This answer is valid only for signed session_id.
I believe the reason it is signed is so that it is not easily guessable. For instance if someone decided to use integers as session id's, you could easily impersonate another user's session by trying multiple numbers. I believe that the signing makes it so that changing your session id value client side will not be valid (that is it prevents tampering).
To counteract login session cookie theft, sniffing etc i've been thinking about this scheme.
i already read http://jaspan.com/improved_persistent_login_cookie_best_practice and what i wish to do is something less-complicated, maybe performance-wise faster too and something that blends well with both remember me functionality and normal session'ed login.
when registration is successful add session id to user(:uid) table and generate session cookie id for example d6c89ddba79b4f68be07bd874c5ff566 and store it in user browser.
When user visits another,the same page,refreshes it; another id will be generated and the current id in the user(:uid) table, the cookie in the user browser will be updated with the new one making the old one useless || invalid.
If an observer tries to steal the cookie, be it in unprotected connection, for example non-https website it will be rendered useless at user's next visit or refresh.
But... i'm sure there's a flaw somewhere in this logic. can the observer create a sort of time warping technique or do something locally to annihilate the benefits of such a scheme?
One concern comes to mind now.. i think it will be a possible situation that an observer steals the cookie when the user is afk or idle, then the observer refreshes the current page with that cookie or visits another one. the problem is that now the user is logged out while the observer has full grip of his account and can therefore change password if it's not a system where password change is confirmed through email or inserting current password before.
is that right? in that case, how could this scheme be enforced without bringing possibly extra complexity?
Yes, this is a good way to prevent session sharing:
the server will generate a new Session ID to store in the cookie every n number of requests. The Set-Cookie header will only be sent once, so if there are two browsers logged into the same session, one of them will be using the old, invalid session
is that right? in that case, how could this scheme be enforced without bringing possibly extra complexity?
As you say, you can get the user to confirm their password whenever a high security function is invoked such as password change. You could also get the system to confirm their password to continue the session in the case that session sharing is detected (i.e. some requests have been logged using the old session ID).
in web application like a society networks users log in and do some works for long times like 2 hours or more, now i store some data like user ID (identity number in member table) in session and found users details data by this id .
and when each user log in to site i store this data for that user on session for 2 hours.
for this work i set my session time out on 120minutes and i want to know is this work good?
i mean storing session for 2hours.
in another hand i can store that ID on encrypted cookie on client and i want to know is this way secure and if user/hacker can decrypt my cookie and retrieve user id (this id is my identity table id) can attack to my site and do some thing or not?
In the world of Web, information storage connections in the session variable is wrong path. You do not control the session variable and can be lost at all momments.
I do not know the architecture used, but on an IIS server you can configure the encryption key for the authentication cookie in your Web.config file on your site web
<machineKey validationKey = "AutoGenerate, IsolateApps"
decryptionKey = "AutoGenerate, IsolateApps"
validation = "SHA1" decryption = "Auto" />
It is not possible that this information is hack on client side.
This is the better way
The problem with storing identification with a cookie is probably not decrypting the cookie but steeling the cookie as whole. This is common session and permanent cookies.
If you want to not to bother user with new login while the site is still active in browser consider shorter session timeout combined with a javascript keep alive (e.g. page refresh each 10min). Otherwise you have on server lot of sessions no longer needed.
If you want to keep user loged in even if browser window is closed. Consider including a browser identification information in the cookie (e. g. Is browser fingerprinting a viable technique for identifying anonymous users?) with good server encryption.
Don't forget to force https.
Do not store in an encrypted cookie. Store in a signed cookie. It's different, here is the why:
https://spring.io/blog/2014/01/20/exploiting-encrypted-cookies-for-fun-and-profit#modifying-the-decrypted-value
The 'old' alternative of having a session, is a bit less scalable than relying on a signed cookie, but it should be more secure, even if someone like NSA has all kinds of ways to go around signing/encryption. ** ˆˆparanoid statement ˆˆ ** but then again, if they have that, they will most likely also have man in the middle access and all sorts of sessions would be pointless.
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.
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.