My one time reset password link is like this with a token http://url.com/token. The payload of the token contains a password (hashed)
When the user request forgot password, then this token is generated like this
jwt.sign({ password, email }, secret, {expiresIn: "1d"})
When the user clicks the link and fills out the reset form. The password reset request is sent to the server and in the body contains the token from the url and the new password.
jwt.verify(req.body.token, secret)
Then I just checked if the hashed password in the database matches the one shown in the jwt payload. If it does, I will change the password in the database. If it doesnt,the one time link has been used already so I error (returns 400 error).
How to do this without storing password?
I would definitely refrain from sending the old password hash in the JWT. If someone were to get access to a bunch of these, they could use them to try to brute-force hack your authentication.
What I would do is have a separate table for password reset requests. So every time someone asks for a reset link
You create a new password reset request entry in your DB with the reset token
If there already was an existing password reset request for that user in your DB, you delete it
The user submits the reset request with their new password and the token
You query your password reset request table and verify that the token they provided matches the token in your DB (i.e. because you only keep the most up-to-date one, you know that it is the correct one)
You action the password change and delete the password reset request from the DB
Good luck!
People can try to crack a password hash even if it takes a long time:
https://security.stackexchange.com/questions/199494/how-to-crack-a-password-given-its-hash-and-its-possibilities
This makes your password hash sensitive which means you should not put it in your JWT token.
https://stackoverflow.com/questions/43496821/is-it-safe-to-store-sensitive-data-in-jwt-payload#:~:text=Ideally%20you%20should%20not%20store,by%20simply%20base64%20decoding%20it.
The time complexity/security risk depends on a lot of things(be sure you are salting your password).
This is a common problem with JWT tokens:
Here is a link to some solutions:
Invalidating JSON Web Tokens
One that was missed would be adding a password version(some number that increments when the password is changed) to your password. Then passing this version back in your token, instead of the password hash. Since you are already querying your database(to make sure the password is the same) you can just query to make sure the password version is the most recent version without any extra time complexity. If it is the same change the password. If it is not the same do not change the password.
Related
I've been trying to understand the real differences between session and token authentication.
What I have gathered so far:
In token authentication, nothing is stored in the server side. What this means is, that the actual token includes the password and username, as well as other possible information. And the server just decrypts the token, and then checks whether the username and password are correct. Am I right about this?? If the token includes the password and username, then how can the token still be different everytime?
In session-based authentication, the session token is just a random (unique in time) id, that is mapped to the user in the server side. So that when the server receives the session_id (in cookie for example), it will check whether it maps to any user, and if it does, then the user is authenticated. So the session_id does not contain any user related information, that could be decrypted?
In session authentication, the server will send back the user related information (not password) without encryption (unless https is used).
In token authentication, the server will not send back direct user information, but just the token, which contains the user information, once decrypted?
I have a feeling that I haven't really understood how token and session authentication works. Something is definitely wrong in the statements above.
But, let's play along that the statements would be correct. Then wouldn't session-based authentication be more secure? Because in session based authentication, you do not reveal user password (in browser for example). Since it's just a random id, one cannot get information from it. But this is not the case with Token authentication. Since token authentication contains the password, if someone manages to decrypt it, he will get your password. So isn't the session authentication actually more safe than the token authentication, as it doesn't reveal password nor username information?
Your question has not an absolute answer YES/NO. For example session cookies are vulnerable to CSRF and tokens can be stolen with XSS injection. Both mechanism are also vulnerable to ManInTheMiddle if you do not use HTTPS. Therefore additional security measures are needed usually for each solutions. Depends on your use case.
I guess you are talking about a token mechanism like JWT which is self-contained and protected to alterations because you said
In token authentication, nothing is stored in the server side.
But you are confusing some concepts. I will try to answer your additional questions using JWT tokens as reference. If not, most concepts also can be applied to opaque tokens
In token authentication, nothing is stored in the server side. What this means is, that the actual token includes the password and username, as well as other possible information. And the server just decrypts the token, and then checks whether the username and password are correct. Am I right about this??
The token is issued by server (not client) requiring users to present their credentials and digitally signed with server private key. The token includes an identifier of the principal in the sub claim and other fields of interest like expiration time or issuer. Never the password
When the client send to token to authenticate, the server verifies the signature to determine the authenticity an has not been altered
If the token includes the password and username, then how can the token still be different everytime?
The token does not include the password. The token will be different due to some variant claims like expiration time exp or issued at iat. Also the computed signature will be different
So the session_id does not contain any user related information, that could be decrypted?
Yes, it is a ramdom sequence. Relationship with user server is stored on server
In token authentication, the server will not send back direct user information, but just the token, which contains the user information, once decrypted?
The JWT token includes some user information, but it is not encrypted, it is signed. If you need to hide the payload, JWT also allows to use JWE encryption
But, let's play along that the statements would be correct. Then wouldn't session-based authentication be more secure? Because in session based authentication, you do not reveal user password (in browser for example). Since it's just a random id, one cannot get information from it. But this is not the case with Token authentication. Since token authentication contains the password, if someone manages to decrypt it, he will get your password. So isn't the session authentication actually more safe than the token authentication, as it doesn't reveal password nor username information?
The base approach is wrong. Password is never included in the token. If you do not want to reveal user data you can use opaque tokens or JWE encryption with JWT. The proper solution depends on your use case. See my first paragraph
Sensitive information such as password or items like Social Security Numbers shouldn't be stored in a token.
A typical example of token signing is this
function createToken(user) {
return jwt.sign(_.omit(user, 'password'), config.secret, { expiresIn: 60*60*5 });
}
Here, we are creating a signed token with the user's details but we are leaving out the password.
I gave a very detailed information about this in this thread How is JSON Web Token more secure than cookie/session?
Check it out. I hope this information helps!
This is a question about generating a token for a user to reset his/her password, without storing said token in the database. This token would be part of a "reset password" URL sent by e-mail.
An answer posted by sudo explains that you can send the user a token with the following information
name
expiration date
hash(secret + user name + expiration date)
The problem with this method is that the user could change his password several times before the token expires. I think this is quite bad because it means that if the user accesses the URL from a shared computer that retains history, anyone could reset our user's password (even if just for a limited amount of time).
So my question is: is it possible to have a token that is usable only once, and that is not stored in the database?
Yes. An easy approach to getting a one-time use token you don't have to store or manage is to offload user management to a microservice like Stormpath where it takes care of all the user management for you-- password reset, password storage, user profiles, authentication, etc.
For password reset here's what it would look like:
User initiates password reset work on a web page
You make API call to stormpath with user's email address or username
Stormpath sends out reset email to user (your "from" address, custom HTML, etc) with a link + token. The reset token that is unique, one-time use, and expires if not used within 24 hours
User clicks on the link and lands on the reset page
You pull the token from the URL and check Stormpath for token verification
User submits new password
Stormpath sends out reset success message (your "from" address, custom HTML, etc)
You can build your own UIs in this flow or use an out of the box, customizale id site (id.mydomain.com) that Stormpath includes.
User never knows Stormpath exists and you don't have to manage or store any passwords or reset tokens.
Full Disclosure - I work at Stormpath
A possible solution is to use a slightly different token:
user name
expiration date
hash(secret + user name + password_hash + expiration date)
When the user accesses the password reset page for the first time, you can retrieve his password hash from the database, and check the hash. It matches, the user can reset his password.
When the user accesses the password reset page for the second time with the same link, it won't work: password_hash has changed, therefore the hash won't match.
But.... There is a problem if the user actually types his original password. In that case password_hash will stay unchanged and the token will remain valid. Because of this edge case, this solution isn't really viable.
I'm trying to change a user's password by saving the user document with a password field. I see in Futon that a new hash and salt are created and I can independently verify the hash and salt matches the new password
However when I try to use the new password CouchDB only responds to the old one. I have tried changing the password manually by editing the document in Futon and I get the same behaviour: the hash and salt update but CouchDB does not respond to the new password.
The only means I have found so far to change a password is with Futon's change password facility. Is it not possible to change the password via HTTP or is there a step I'm missing?
Read this: http://wiki.apache.org/couchdb/Security_Features_Overview
Likely you're trying to change admin's password.
User documents that represent server admins do not need to have the
"password_sha" and "salt" attributes defined - their authentication
credentials are stored in the .ini configuration files.
UPD: You can change admin's password via /_config API: http://wiki.apache.org/couchdb/Complete_HTTP_API_Reference#configuration
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 :)
What is the most secure way to handle forgotten passwords/password resets? Should I email the password to the user? If so do you then force them to reset it? Or do you let them reset it immediately (without sending an email) and require some other information to verify that it is them? Or is there a better method?
You can't email the password to the user, because you don't know it. You've "hashed" it by applying something like PBKDF2 or bcrypt to it for storage, right?
If you reset the password without confirming it with the owner of the account, an attacker can deny the owner access to his account, at least until he checks his email, by using the victim's email address to request a reset.
A method safe enough for many applications is to email a link to the account owner, containing a large, randomly generated number. This token should only be valid for a limited time. If the owner wishes to reset their password, they click the link and this authenticates them as the account owner. The account owner can then specify a new password.
You shouldn't send passwords via email. Here is a step by step process I've used:
Give users a reset password option.
This option saves a unique token for a user. The token eventually expires (hours, day or days).
A link is emailed to the user which includes the token.
User clicks on the emailed link.
If the token exists and isn't expired, the link loads a new password form. If not, don't load the new password form.
Once the user sets a new password, delete the token and send the user a confirmation email.
Until the new password is set, the old password should remain active. Don't forget to hash and salt the passwords!
I suppose you are going to do it programmatically? Or is it a question for Server Fault?
One of the ways is to send a link to the user's email account. He/she clicks on the link and is redirected to your secure web form where they reset the password.
Do NOT email the password to the user