I read about many old questions about this argument, and I thought that the best practice is to set up a cookie with username,user_id and a random token.
Same cookie's data is stored in DB at cookie creation, and when users have the cookie they are compared (cookie data, DB data).
Sincerely I can't understand where is the security logic if this is the real best practice.
An attacker who steals the cookie has the same cookie than the original user :|
Forgotten some step? :P
You should NEVER EVER store a users password in a cookie, not even if it's hashed!!
Take a look at this blog post:
Improved Persistent Login Cookie Best Practice (Nov 2006; by bjaspan) (orignal)
Quote:
When the user successfully logs in with Remember Me checked, a login cookie is issued in addition to the standard session management cookie.[2]
The login cookie contains the user's username, a series identifier, and a token. The series and token are unguessable random numbers from a suitably large space. All three are stored together in a database table.
When a non-logged-in user visits the site and presents a login cookie, the username, series, and token are looked up in the database.
If the triplet is present, the user is considered authenticated. The used token is removed from the database. A new token is generated, stored in database with the username and the same series identifier, and a new login cookie containing all three is issued to the user.
If the username and series are present but the token does not match, a theft is assumed. The user receives a strongly worded warning and all of the user's remembered sessions are deleted.
If the username and series are not present, the login cookie is ignored.
You should store the user_id and issue a random token in addition to the user's password. Use the token in the cookie and change the token when the password changes. This way, if the user changes their password then the cookie will be invalidated.
This is important if the cookie has been hijacked. It will be invalidated if the user detects the hijacking, and furthermore because the token is unrelated to the password the hijacker won't be able to derive and then change the user's account password and "own" the account (assuming you require the existing password before changing passwords, the hijacker doesn't own the email account so they can't use "Forgot my password" etc).
Take care that the tokens aren't easily guessable (i.e. they should consist of entirely random data, like from a CRNG).
If you want to go one step further, you can encrypt the cookie before sending it and decrypt it upon receipt. And further to that, don't assume that a hijacker doesn't know the encryption key used, so validate the cookie's contents upon decryption.
But all that said, prefer to use a library's persistent session management instead of rolling your own.
I wouldn't even store the username in a cookie, just a random token generated with a near impossible to crack technique and map that to the user in your database, and never store user's password even hashed in a cookie, it will be open to Brute Force Attack. Yes if someone steal the token he can access user's account but the password will not be compromised and the token will be invalidated as soon as the real user logs out. Also remember that you shouldn't allow sensitive tasks like changing password to a user who just have a valid token, you need to ask for the password again for such tasks.
if your cookies are stolen anyone can log into your accounts. it's actually what firesheep does. the security lies in the random token. the whole system assumes cookies can't be stolen. the only other way to get in then is to guess the random token. if you make it long enough it should be nigh-impossible.
The "step" that you seem to be forgetting is that if the cookie value is properly hashed it would be of a little value to an attacker.
EDIT:
Here's a couple of things you can do to protect your users against cookie theft related attacks:
Regenerate tokens over time, so that an attacker would not be able to impersonate a user unless she has a recent enough cookie. If security is top priority, regenerate tokens on each request (page load). If it isn't, regenerate tokens on password change.
Keep and validate hashes of user agents, so that an attacker would not be able to impersonate a user unless she has both the cookie and the user agent that of the user.
p.s. Cookies should hold (random) tokens and not password hashes (see Hashes or tokens for "remember me" cookies?).
I always knew that the "remember me" feature only converted the session cookie (i.e. the cookie with the session ID) from expiring when closing the browser to a future date, it doesn't involve saving additional data, only extending the session.
And yes, if an attacker gets the cookie, it can impersonate the user. But this is always valid, and has nothing to do with "remember me".
My approach is the following:
Hash the user_id
Generate an unique key for the user - md5(current_timestamp)
Save the key to the DB
Encode everything so it looks like a BS - base64
Save it in the cookie
So far, It has been working great for me :)
Related
I'm building a nodejs server with jwt authentication.
At the moment my jwts have a expiration time of 1 month.
If the user goes on the loggin page, I check if his request contains a valid jwt, if yes, he don't have to type in his username and password.
If he logs out, the jwt gets deleted on the clientside, so the user have to log in next time with his credentials.
What if an attacker listens to the connection (I'm already using ssl) and gets the token.
Even if the user logs out and gets a new token on his next session, the attacker can impersonate the user with the old token, as long as it is valid right?
Is it a good idea to store the IAT of the "current" token of the user in the DB and compare it to the IAT of the token in the request to avoid the access of the attacker?
I know, 1 month is quite a long time for a jwt. I also had the idea to generate a new token, every time the client logs in (with exp. time 2 days). But if an attacker gets only 1 valid token, he also gets the new tokens, isn't he?
Do you have any suggestions?
Thanks, Cheers!
Your concerns are exactly one of the reasons that security people advise against using JWTs for session data -- see section "You cannot invalidate individual JWT tokens". In other words, the only way to invalidate JWT tokens is to force a database lookup when it is presented -- but that defeats the entire point of the JWT in the first place (most people use them because they are trying to avoid a database lookup on the server).
Store the tokens and any session data (for example user ID for the logged in user) on the server. This gives you full control of the data, and the sessions. It also removes a lot of avenues for abuse (which the JWT standard allows).
When doing that, if you know a token is stolen, you can simply mark it as invalid on your server, and have your application ignore it.
In practice, this means just having a token in the cookie, and having the user ID and other session data stored in a database table or server side cache (for example a mysql table or redis cache).
I want to use JWT in my application.
Now I'm wondering if it is secure to use the users password in combination with a private secret as a key to sign my tokens. This way, tokens get invalidated if a user changes his/her password.
But maybe it makes my private secret vulnerable?
Thanks for your thoughts on that!
The secret is a preshared string exchanged between the client and the server.
So in your case:
SecretString= PresharedSecret + ClientPassword
So, everytime the client passes a JWT token, you would need to retrieve the password from the database or have some way of preloading it and a check in case of password changes for validating the token.
This might lead to the following scenarios:
Everytime the client forgets his password, you might need to make database calls that can be expensive
It would enhance security in one way, as anyone who changes the password will not be able to communicate with the server with knowledge of the previous SecretString.
A new preshared secret will need to be decided.. and validated with the new registered password.
Overall, it does increase security. However, it depends on the purpose or the usage of the infrastructure. If it is a system in which users frequently forget passwords.. this might not be a great option.
The usual thing is to sign all the tokens with the same key. Simplifies the management and avoids querying the database in each request.
Signing with a key+user password is feasible and has the advantage of allowing to revoke tokens (with the commented drawbacks).
Ensure that your signing key is enough secure deriving it from user's password and has the recommended length of the selected signature algorithm. Do not store or use user's password directly.
I plan not to use HTTPS for my web app. I used digest authentication as method to secure login to my system. And after user being authenticated, I simply send nonce to them periodically(1 min). When users make request, I simply check whether the nonce expires before I send them response.
I want to know whether it is necessary for me to protect users session_id in case the attackers replay the nonce or guess out the nonce generation mechanism? And if yes, how do I secure the session_id?
Take a look at Session Hijacking and Fixation
The best solutions to Session Hijacking/Fixation is:
Regenerate session identifier at key points. In your case after user login. So, after the user logins, we give him a new session identifier.
So,in case a hacker hijacked the session id, it would be useless and
would not work.
Save User Agent/IP address and compare it against
the User Agent/IP address used just before login. A hacker would not have the same User Agent/IP address as the legit user. But remember User Agent/IP address can sometimes be faked.
Last but not the least, destroy old session regularly.
Keeping these in mind, your program will be safe from Session Hijacking/Fixation.
Currently on our web-based apps we don't allow users to save their login information. The login itself is simply a secure cookie with a random hash which points to session information on the back end. There are no issues like HIPAA to be had, we just never implemented saving credentials, because it doesn't seem like a good idea to me.
What are the pros and cons from a security perspective on this? I worry about users getting saved cookies taken, though we do check session against IP address as well. I just don't want to miss anything.
Never 'save' the credentials, always generate a secure token that you will store on the client side and treat it as if it was the user's password (it kind of is, actually).
But first:
High value applications MUST NOT possess remember me functionality.
Medium value applications SHOULD NOT contain remember me functionality. If present, the user MUST opt-in to remember me. The system SHOULD strongly warn users that remember me is insecure particularly on public computers
Low value applications MAY include an opt-in remember me function. There should be a warning to the user that this option is insecure, particularly on public computers.
Always give the user an overview of active sessions once he is logged in and give him the option to terminate certain sessions.
You could use this strategy described here as best practice:
When the user successfully logs in with Remember Me checked, a login cookie is issued in addition to the standard session management cookie.
The login cookie contains the user's username, a series identifier, and a token. The series and token are unguessable random numbers from a suitably large space. All three are stored together in a database table.
When a non-logged-in user visits the site and presents a login cookie, the username, series, and token are looked up in the database.
If the triplet is present, the user is considered authenticated. The used token is removed from the database. A new token is generated, stored in database with the username and the same series identifier, and a new login cookie containing all three is issued to the user.
If the username and series are present but the token does not match, a theft is assumed. The user receives a strongly worded warning and all of the user's remembered sessions are deleted.
If the username and series are not present, the login cookie is ignored.
This web application will have a database table with columns uniqueid (64-bit int autoincrement field; key), token (64-byte binary field), and an accountid.
After logging in with "Remember Me" checked, a random token will be generated. Then the SHA-512 hash of this token will be inserted into the database and the generated uniqueid retrieved. A cookie that contains the uniqueid and unhashed token is sent to the client.
Every time a user visits the page with the cookie, the cookie's uniqueid and its token's SHA-512 hash with be checked against the database. If there is a row that matches the uniqueid, and that row's token hash matches the token hash, log in the user with the row's accountid. After every authentication attempt made by the cookie, delete the row that uses the old uniqueid and, if the authentication was successful, generate a new random token. Then the SHA-512 hash of this token will be inserted into the database and the generated uniqueid retrieved. A cookie that contains the uniqueid and unhashed token is sent to the successfully authenticated client.
I will be using the techniques described here as well. All failed cookie authentications will have the cookies set to blank values and expiration date set to sometime in the past.
I believe this method would address a few concerns regarding cookies. Namely:
The token in the database is hashed so that as long as an attacker does not have write access to the database, he/she will not be able to forge cookies of
all users.
Unique IDs are used instead of a user's account name because login
credentials should never be stored in a cookie.
A random token is generated every time the cookie is authenticated
so that if an attacker steals a cookie, it will only be valid until
the user next logs in rather than for the entire time the user is
remembered.
Cookies will be difficult to sniff because my entire application uses HTTPS.
I can further enhance security by allowing the user to specify how long he/she wants to be remembered for. The expiration date will be stored in the same database table that stores uniqueid and tokens. Every time a new cookie is created, this expiration will be sent with the cookie. If a user tries logging in with a cookie that the server deems expired but the client still holds, the log in will be denied.
I believe this solution is reasonably secure, but are there any pitfalls or things that I have overlooked when I designed this method?
Sources:
Hash token in database
Don't store account name in cookies and use new unique id after every authentication
When it comes to security, reasonable is always relative. :) It is reasonable if you think it is appropriate vs. the threats you face. That said, here are a few things I'd do if it were my app and I believed I was actually going to need to protect it from attack...
Stamp something in to the token / b/e that allows you to correlate back to the original authentication event, then log it in all cookie operations. This way you can do correlation if (when :)) people get hacked and you want to figure out what happened when.
On the b/e, make sure you implement "invalidate all of my outstanding tokens" as a feature of the system. Then wire this in to all "suspicious" events automatically.
Store geo information in the cookie / in the b/e with the row that corresponds with the cookie. Start by logging it. Eventually you'll want to do more. As you study people that get hacked you'll find more and more things you can do with this data. If you don't have the data, you can't learn.
Lots of instrumentation. Lots and lots of instrumentation. Retain it for years. Everything gets an event, log everything you know in that event when it happens. Good visualization / lookup tools that you can use to figure out what happened when.
There are of course zillions more things you could do, this is just a starter list...