Is it advisable to store a hashed password in a cookie? - security

I want user's to be able to select a "remember me" box on my website so they need not log in each time they come. So, I need to store a unique ID in a cookie to identify them. Is it safe to hash their password with sha512 and a long salt in PHP and store that value in the cookie?
If the cookie was stolen, would their password be at risk?
Obviously it must be connected to their password somehow, otherwise if the cookie value was guessed or stolen, the user would not be able to stop someone else logging in.
Also, is it advisable to use a GUID at all as the unique identifier?
Thanks,
Ben

Remember, the hash of the password is effectively the same as their password. Somebody who stole the hash would have the same access to the user's account as if they had stolen their password. Therefore it is not advisable to store a hash of the user's password in a cookie unless there was some other information not stored with the cookie that is used to authenticate (i.e. 2-factor authentication).

Here is an excellent article on this very topic. Many of the answers to your question are hitting on techniques outlined in it.

There's a low risk with a good algorithm and large salt, but why take any unnecessary risk?
If you just need to identify the user, then store something that can uniquely identify the user, like a guid along with some other stored verification code (not their password, some random long string). I wouldn't use a guid alone as it would not be a safe method of authentication.

It wouldn't hurt to have some kind of "password" in the cookie along with a user id (to prevent users from changing the uid to that of another user), just don't make the "password" the same as the actual user's password.
And just because it's a hash doesn't necessarily mean it's one-way (well, by definition it does, but there are utilities to generate MD5 plaintexts and I would guess it's only a matter of time before it happens to others). I would hash some kind of secondary password.

An alternative way of doing this might be use the cookie as an encrypted storage for only indirection data. You'd need some sort of unencrypted identifier that would serve as a pointer to the key (or the required information to derive the key) in the application's database, followed by a blob encrypted by the key obtained from the identifier, which itself would contain some sort of one-time-usable identifier that authenticates the session.
Given the following assumptions:
Your database is secure (e.g., your application can access it, but your user cannot directly do so, and also assuming that the application has been proofed against SQL injection)
Your salts are strong; that is, reasonably high-entropy enough that attempting to crack the salted password is infeasible even if the password is known
Then what this would provide is a method by which one can be reasonably certain that the session is not able to be hijacked or stolen in any way. That is to say that a copied cookie is only of limited usefulness, since the user must not have used the cookie between its theft and usage by an attacker.
While this protects against replay, it also means that if someone does manage to steal the cookie at exactly the right time, and manages also to use it before the original, legitimate user does, the attacker now is in control of the session. One can limit a session to an IP address to mitigate that risk (somewhat; if both the user and the attacker are behind the same NAT, which is the most likely scenario in any home or small-to-medium business network) then this point is pretty moot, since the IP address would appear to be the same anyway. Also useful might be limiting to the current user agent (though that can break unexpectedly if the user updates their browser and the session does not expire at browser close time), or finding some method by which one can identify the computer that the user is on just well enough that there is reasonable certainty that the user hasn't moved the cookie from one system to the next. Short of using some binary plugin (Flash, or Silver/Moonlight), I'm not sure that the latter is possible.
To protect against a permanent session hijacking, require that the user to reauthenticate him- or herself periodically (e.g., limit the allowed session lifetime or require something like a token/fob/dongle) and require that the user reauthenticates him- or herself upon entering sensitive areas of the application, such as password change and potentially dangerous actions, patterns or behaviors such as the deletion of data, unusual usage patterns, bulk actions, and so forth.
It is difficult to secure applications and yet retain their ease-of-use. If done carefully, security can be implemented in a manner which is minimally intrusive and yet still effective—well, for most Internet-facing applications, anyway.

It's not advisable, but if your gonna do it, at least salt your passwords before you do so. This will stop people from using hash crackers if they do manage to get hold of your visitor's cookies.

Related

Is storing a permanent access token as good as storing password?

If I want to persist the users' login such that they do not have to re-login even after, say 1 year of inactivity, then is storing a permanent access token as good as storing the password directly (perhaps hashed), since the (permanent) access token would essentially be the "alternative password"?
Storing an access token is surely safer than storing the password directly, but let's see why:
An attacker can only get this token, but not the original password. This is better, because passwords are often reused on other sites, and/or can reveal password schemes. ➽ Make sure the token is random and not derrived from the password.
The token is not just another password. While passwords choosen by a user are often weak, a token is very strong. They are so strong, that brute-forcing is impractical. ➽ Generate random, long enough tokens, they should be at least 20 characters a-z,A-Z,0-9.
Generally speaking, yes. But, with a lot of caveats.
A long, random token, generated by a CSPRNG (this is very important, there are different ways to generate "random" strings and not all of them are really random), is stronger than a password - yes. However, the way you intend to use this token means that it is effectively a password by itself, and that means the same criteria applies:
It can't be permanent.
A key property of passwords is that they are not constants and users can change their passwords when stolen, or otherwise over time. Any kind of token should be no different, except that it should be automatically changed (rotated) by your application, on regular intervals.
It MUST be hashed!
(with a strong algorithm: bcrypt, scrypt, Argon-2I, PBKDF2; anything else is plain wrong)
Don't ever store user passwords in plain-text format, anywhere. Even if it is guaranteed that the user doesn't use this password on any other site, a plain-text password means that anybody who gets their hands on the database (even for a brief time), can hijack user accounts.
You have a responsibility to protect your users not only from "hackers", but from yourself as well.
Don't store it in a cookie, even if hashed or encrypted.
The way you've worded the question implies that you would do something like this. Cookies are not a secure location to store passwords of any kind. Temporary, short-lived tokens - sure, but not passwords.
It looks like you're trying to design your own authentication protocol, which is not an easy thing to do. It may be easy to make it work, but that's about 5% of the job; there's just too many details to consider. And all of this, for the tiny benefit of saving the minor inconvenience of a user typing-in their password once in a while - people are used to this; it's not worth the security risks.
In case you are hell-bent on providing long-lived logins, I would recommend using an existing authentication protocol. Every such protocol uses on cryptographic signatures, avoiding reliance on user passwords altogether and thus eliminating all of the above problems almost entirely.
Personally, I would just allow the so-called "social logins" - via Facebook, Google, Twitter. You wouldn't have to handle passwords at all, and anybody can login with a single click of a button.
Is better to store an access token than storing the password or the hashed password (can always try brute force to find the password) and I think you should give a token a lifetime.
Although the answer is yes, but it also depends on the place you are storing the token. And you might want to auth the user with XSRF/CSRF token as well along with the token.
But storing token is better than storing password.

Need cookie to remember two-factor authentication success (not persistent login)

I've read a lot here and other places about using a cookie for a "remember me" option, but what I'm looking for is a way to design a cookie to record success of a two-factor authentication. This is what, for example, Google does: If the second step succeeds (e.g., you entered the code that you received via SMS), then it sets a cookie good for a period of time (e.g., 30 days) that means that the second step can be bypassed. Call this the "verification cookie." My understanding is that if in that time you logout and then in again, it won't do the second step, but only the first step. (I tested this and that seemed to be the case.)
My question is how to design this cookie. One idea is to put the user ID and a 128-bit random number in the cookie, and then to store that number in the database along with the user ID. This is what Charles Miller recommends (http://fishbowl.pastiche.org/2004/01/19/persistent_login_cookie_best_practice/) for persistent-login cookies.
However, that's not good enough, I think. The problem is that, since the user is using a two-factor authorization, whatever cookie is used to record that the second step was successful, should be safer than would be the case with a one-factor authorization.
What I want to avoid is this: The cracker has the hashed/salted passwords from the database, and has somehow gotten the password. If he/she has that much, I assume that the 128-bit random number that was in the verification cookie is available as well. (If the cracker has gotten the password some other way, and doesn't have the database, then the verification cookie is safe unless he/she has physical access to the computer. I'm only worried about the compromised database case.)
Maybe an idea is to encrypt the 128-bit random number? (Needs to be 2-way -- not a hash.) The encryption key would be accessible to the application, maybe stored however the database credentials are.
Has anyone implemented what I'm calling a verification cookie (not a persistent login cookie) and can tell me (us) how it was done?
UPDATE: Thinking about this, what would I think be secure enough would be this: Cookie consists of userID and 128-bit random number -- call it R.
Database contains password and R, each hashed and salted (e.g., using PhPass). R is then considered to be a second password. Benefit: Even if first password is bad (e.g., "password1"), R is a very good password. Database really can't be cracked, so it should not be a worry. (I was unnecessarily worried about it, I think.)
I think you have a pretty good plan here. Generally speaking the cookie should be completely random and should not contain any data that is used by the server. The idea is that anything that is client controlled can be tampered with. Even when the value is encrypted, I've seen attackers twiddle bits and get the tampered data to decrypt to a different user's ID (yeah that one scared me a bit). That being said I think Charlie Miller's suggestion is fine, because 128-bits is a good amount of entropy. Me personally, I would go with completely random bytes for a cookie such that no pattern emerges whatsoever.
Our last implementation of a verification cookie was a completely random 256 bit value printed in ascii-hex that was mapped to a user ID and session information in our DB. We kept the session information encrypted with a secret key, so if an attacker SQL injected our DB it would all be useless encrypted info. Of course a total compromise of the DB machine would provide access to the key, but that is a lot harder to do because it involves multiple exploits and pivots.
Some good advice is not to over-think it too much. We ran into implementation problems because we "over-engineered", and in the end we didn't get much security advantage anyway. A simple random number is the best you can do (as long as it is long enough to provide sufficient entropy).
There is a good answer to this problem on the security stackexchange site (which is maybe where this question belongs, anyway):
https://security.stackexchange.com/questions/31327/how-to-remember-a-trusted-machine-using-two-factor-authentication-like-googles

Hashes or tokens for "remember me" cookies?

When it comes to remember me cookies, there are 2 distinct approaches:
Hashes
The remember me cookie stores a string that can identify the user (i.e. user ID) and a string that can prove that the identified user is the one it pretends to be - usually a hash based on the user password.
Tokens
The remember me cookie stores a random (meaningless), yet unique string that corresponds with with a record in a tokens table, that stores a user ID.
Which approach is more secure and what are its disadvantages?
You should use randomly generated tokens if possible. Of course, the downside is that you have to write some extra code to store and use them on the server side, so this might not be warranted for all web applications. But from a security standpoint, this has distinct advantages:
An attacker cannot generate tokens from user IDs, but he can definitely generate hashes. This is a big problem, even if you use salt when generating hashes (and you should), your users are screwed if the salt ever gets into the wrong hands.
Giving out these tokens enables your users (or your admin if need be) to "log out" certain sessions that they might want to get rid of. This is actually a cool feature to have, Google and Facebook use it for example.
So, if you have time and budget: tokens, absolutely.
Typically you keep the token -> user mapping secure on the server side. So ultimately your security is all based around keeping the token safe and ensuring that its lifetime is controlled (e.g. it expires and/or is only valid when given to you from the same IP as that used by the original provider of the credentials - again, just an example)
Security of token based authentication
Hope this helps.
Yes tokens would be more secure if they produce a random string each time.
On the other hand, the whole point of remember me is that the user doesn't have to log in again, so unless they click log out your rarely going to need to re-produce a new token unless it expires.
I guess you should stick with tokens and not sacrifice security for lazyness :-p

Is it safe to store (hashed) passwords in a cookie?

I've read some articles and questions on SO (e.g. here) that say you shouldn't store a user's password in a cookie. If the password is salted and hashed, why is this insecure?
In particular, why is it less secure than using sessions, the alternative usually suggested? If the user wants to stay logged in then surely this new cookie (with a session ID/hash) is exactly as secure as the one with the user's password? If the cookie is "stolen" on some way the attacker can log in as the user in the same way.
EDIT: The main crux of the question is the part about the user staying logged in, i.e. via a "Remember Me?" checkbox. In this case, surely there is only ever one session?
By putting the hashed password + salt in the cookie, you:
Open up an unlimited bruteforce vector
Allow the cookie to be copied and used by anyone (it always lets access; whereas a session does so for a period of time).
Make it harder to change hashing schemes, if it becomes relevant
Further, you generally need to store something else, to identify the user (like their user id, so you can look up their password and match it). This may lead other obscure problems.
So you're best just going with the session id approach.
Among other distinctions, if a session is stored, you own this one session. If a pwd is taken, you own every session of that user from now on.
Sessions are usually keyed to IP addresses at some level somewhat preventing session theft.
Beyond that, the session ID doesn't contain any personal information; your password, even salted and hashed does. Passwords, salted and hashed as they may be, can be reused; session ID's can't. Once the session is over, it's over, you need a new session ID to be able to impersonate the user again.
How about letting someone else deal with and think about all these issues for you? That is, use OpenID, Windows Live ID, Facebook Connect, etc.

How does hashing and salting passwords make the application secure?

As much as I understand it is a good idea to keep passwords secret from the site administrator himself because he could try to take a user's email and log into his mailbox using the same password (since many users use the same password everywhere).
Beyond that I do not see the point. I know it makes more difficult the dictionary attack but... if someone unauthorized got into the database, isn't it too late to worry about passwords? The guy has now access to all tables in the database and in a position to take all the data and do whatever he wants.
Or am I missing something?
The bigger problem is that people tend to use the same password everywhere. So if you obtain a database of usernames and unsalted passwords, chances are good they might work elsewhere, like hotmail, gmail etc.
The guy might be in a position to do everything he/she wants to your system, but you shouldn't allow him/her to do anything with other systems (by using your users' passwords).
Password is a property of your users. You should keep it safely.
Many of your users use the same credentials (usernames/passwords) at your site as they do at their bank. If someone can get the credentials table, they can get instant access to a bunch of bank accounts. Fail.
If you don't actually store passwords, then attackers can't steal your users' bank accounts just by grabbing the credentials table.
It relies on the fact that a hash is a one way function. In other words, its very easy to convert a password into a hash, but very difficult to do the opposite.
So when a user registers you convert their chosen password into a hash and store it. At a later point they login using their password and you convert the password to its hash and compares it this is because, to a high level of probablity if (passwordhashA == passwordhashB) then passwordA=passwordB.
Salting is a solution to a related problem. If you know that someones passwordhash is, say ABCDEF, then you can try calcuolating hashes for all possible passwords. Sooner or later you may find that hash('dog') = ABCDEF, so you know their password. This takes a very long time, but the process can be speeded up by using pre-created 'dictionaries' where, for a given hash you can look up the corresponding password. Salting, however means that the text that is hashed isnt a simple english word, or a simple combinationofwords. For example, the case I gave above, the text that would be hashed is not 'dog', but is 'somecrazymadeuptextdog'. This means that any readily available dictionary is useless, since the likelyhood of it containing the hash for that text is a lot less than the likelihood of it containing the hash for 'dog' This likelihood becomes even lower if the salt is a random alphanumeric string.
The site admin may not be the only person who gets access to your password. There is always the possibility of a dump of the whole database ending up on a public share by accident. In that case, everybody in the world who has internet access could download it and read the password which was so conveniently stored in cleartext.
Yes, this has happened. With credit card data, too.
Yes, it is highly probable that it will happen again.
"if someone unauthorized got into the database, isn't it too late to worry about passwords?"
You're assuming a poor database design in which the authorization data is comingled with application data.
The "Separation of Concerns" principle and the "Least Access" principle suggest that user credentials should be kept separate from everything else.
For example, keep your user credentials in an LDAP server.
Also, your question assumes that database credentials are the only credentials. Again, the least access principle suggests that you have application credentials which are separate from database credentials.
Your web application username and password is NOT the database username and password. Similarly for a desktop application. The application authentication may not necessarily be the database authentication.
Further, good security suggests that access to usernames and passwords be kept separate from application data. In a large organization with lots of database users, one admin should be "security officer" and handle authentication and authorization. No other users can modify authorization and the security officer is not authorized to access application data.
It's a quick audit to be sure that the security officer never accesses data. It's a little more complex, but another audit can be sure that the folks with data authorization are real people, not aliases for the security officer.
Hashed passwords is one part of a working security policy.
Of course, storing hashes of passwords instead of plain-text does not make your application secure. But it is one measure that increases the security. As you mentioned if your server is comprised this measure won't save you, but it limits the damage.
A chain is only as strong as its weakest link
Hashing passwords is only strengthening one link of the chain. So you will have to do more than that.
In addition to what has already been said regarding salting, there's another problem salting solves :
If you use the same salt everywhere (or no salt at all), it's possible to say just by looking at the database that user foo and user bar both have the same password (even if you don't know what the password is).
Then, if one achieve to get foo's password (using social engineering for example), bar's password is known as well.
Also, if the salt is everywhere the same, one can build up a dictionary dedicated to this specific salt, and then run a brute-force attack using this 'salted' dictionary.
This may be a bit off topic, but once in a while, I notice some websites are not using hashing (for example, when I click the forgot password button, they send me my password in cleartext instead of allowing me to chose another one).
I usually just unsubscribe, because I don't think I can trust a website designed by people not taking the elementary precaution of hashing passwords.
That's one more reason for salting:)
People seem far too complacent about this! The threat isn't some guy with shell access to your system or to the backup media, it could be any script kiddie who can see the unprotected (but dynamic) part of your site(*) and a single overlooked SQL injection threat. One query and suddenly he can log in as any user, or even as an admin. Hashing the passwords make it far less likely that the attacker can log in as any particular user using their password -or- update a record with their own password.
(*) "unprotected" includes any part of the site that can be accessed as a self-registered user. Contrast this to a bank site, for instance, where you must have an existing bank account to gain access to much of the site. An attacker could still open a bank account to gain access to the site, but it would be far easier to send big guys with bigger guns after him when he tries to crack the system.

Resources