The approach that I'm taking right now is:
take the PasswordSalt
hash it once more with SHA1 and some application-level salt
and then generate the Reset Password link from that
The advantage is that it is pretty straightforward, and I don't need to create any new database columns.
The disadvantage could be that the link is always the same for that user.
Is this a security problem?
This seems a big compromise simply to avoid extra database columns and to provide simplicity for you.
You should securely generate a token for use in the link and for storage in the DB. This has the advantage that it can be randomly generated each time and an expiry data can be associated to the token.
This will minimise the risk as the reset link has a limited life span and has less chance of falling into the wrong hands.
I disagree with security questions being used at all (in #Marcus Adams's answer) because these questions can usually be easily guessed if the attacker knows the victim (or can usually easily find out these days via publically available information such as Facebook profiles). Also, they have the disadvantage of not being able to be updated easily (e.g. your favourite pet's name will remain the same unless you buy a new, better pet - or if you make one up you'll probably forget it, defeating the object of it in the first place).
I'm assuming that you're emailing the password reset links and that the user has to enter a userid/email address to start the process.
Make sure you generate a new random salt each time the user resets their password, so that there can't be any replay attacks.
For example, if the salt doesn't change, the password reset link wouldn't change, even after a password reset. If a hacker were able to obtain the link, even a year later, the hacker would be able to re-use that link to reset the password to whatever they want.
Quite often, after clicking the password reset link, the user is asked to answer a security question that they setup previously. This helps mitigate the issue of a hacker obtaining and using the link before the user does.
The fact that you can reset a password at any time, even if it wasn't requested, smells, but since doing this requires the password salt, secret application-level salt (really, a key, since it's not random), and perhaps a security question, not to mention the fact that requesting a password reset link is trivial (only need userid/email address), it should be good enough.
You may have some performance issues down the road since in order to verify a password reset link, you'll have to scan all the rows in the user table, applying the hash to each row, until you find one that matches.
Related
I'm in the process of updating several projects from using various insecure/horribly insecure MD5-based password hashes. I'm now at least somewhat better informed on best practices, but I still wonder if I'm doing something wrong. I haven't seen the specific process I'm implementing used elsewhere, but at least one SO user seems to want to do something similar. In my case:
Password hashes are generated using bcrypt. (Since the proper options seem to be bcrypt, scrypt, or pbkdf2 and bcrypt was most easily accessible to me in PHP.)
A different, random, salt is used for each hash. (To prevent attackers from generating a custom rainbow table calculated with a single, static salt.)
The hash, algorithm settings, and salt are stored together. (Since that's what PHP's crypt function give me for the hash value.)
After a successful login, the hash is re-calculated with a new random salt.
It's that last step that I'm wondering about. My intention here to to allow updates to the hashing algorithm as time passes so users who regularly log in will have their passwords stored in the most secure format available.
My questions are:
Is this a waste of time?
Are there any dangers in doing this?
UPDATE
Re delnan's comment : If you are re-hashing the already hashed password, don't -- You never know what vulnerabilities may occur and be found in chaining up hashes. Obviously the other side of that is you need to compute the entire hash-chain every time you validate the user secret -- so just re-hash the cleartext.
ORIGINAL
I upvoted halfway through reading. It seems like you're someone who's asking the right kind of questions to be doing this kind of work.
Not a waste of time.
There are always dangers. Someone could obtain your users' passwords by torture or, more likely, social engineering. Someone could have access to vast resources and along with your shadow password file still manage to crack the passwords. Someone could compromise your server secretly insert a trojan that intercepts the users cleartext passwords at successful login.
So there is no guarantee of perfect security. Ever. But I'm sure you know that already. Which is why I'd like to add only one thing:
Encourage users to choose hard to crack passwords.
And, strictly speaking, if your only reason for rehashing at every login is so that passwords are always stored using the latest update then yes -- your method IS a waste of time, assuming you will not be updating your algorithm at every user's login. So there will be rehashes which use the same algorithm and (presumed) security for two logins in a row. A waste of a few clock cycles on rehashing. Strictly speaking it's not optimized. Why not just include an algo version in your password store, and at login rehash if the system algo is newer than the user's hash algo.
UDPATE
Sorry. Completely missed your point about the use of newer algo's. This is a good thing. :-) But as stated in my original answer below when the algo stays the same it is useless.
ORIGINAL
Rehashing passwords is useless, because if an attacker has already got hold of the hash you aren't preventing anything.
Consider the following:
I am a user on your site with the hash: 1234567890.
Some attacker gets hold of that hash.
I log in again and the hash is changed.
The attacker doesn't care the hash changes because he only needs one hash to try to break.
So nothing has been prevented. The attacker still has the hash and can still try to break it. A possible attacker is only interested in the final result (the password) and not in the hashes.
If someone gain access to the hash changing it every time will not help at all unless the person has access to every update and willingly start over. this isn't going to happen and if it did you would have a much bigger problem then that.
No there is no danger in it only waste of server resources.
Actually, it prevent novice cookie attacker to copy cookie into his browser just to impersonate...so if the owner later login, with a changed hash, it will log the attacker out thereby reducing havoc on the user account.
Does adding a constant string that is stored in the code to the password before hashing make it harder for an attacker to figure out the original password?
This constant string is in addition to a salt. So, Hash(password + "string in code added to every password" + randomSaltForEachPassword)
Normally, if an attacker gets their hands on the database, they can possibly figure out someone's password by brute force. The database contains the salts corresponding to each password, so they would know what to salt their brute force attempts with. But, with the constant string in code, the attacker would also have to obtain the source code to know what to append to each of their brute force attempts.
I think it would be more secure, but I wanted to get other people's thoughts, and also make sure I'm not inadvertently making it less secure.
Given that you already have a random salt, appending some other string neither adds nor detracts from the security level.
Basically, it's just a waste of time.
update
This was getting a little long to use the comments.
First off, if the attacker has the database and the only thing you've encrypted is the password then games over anyhow. They have the data which is the truly important part.
Second, the salt means that they have to create a larger rainbow table to encompass the larger password length possibilities. The time this takes becomes impractical depending on salt length and the resources available to the cracker. See this question for a bit more info:
How to implement password protection for individual files?
update 2
;)
It is true that users reuse passwords (as some of the latest hacked sites reveal) and it's good that you want to prevent your data loss from impacting them. However, once you finish reading this update you'll see why that's not entirely possible.
The other questions will have to be taken together. The entire purpose of a salt is to ensure that the same two passwords result in a different hash value. Each salt value would require a rainbow table to be created encompassing all of the password hash possibilities.
Therefore not using a salt value means that a single global rainbow table can be referenced. It also means that if you use just one salt value for all passwords on the site, then, again, they can create a single rainbow table and grab all of the passwords at once.
However, when each password has a separate salt value this means they have to create a rainbow table for each salt value. Rainbow tables take time and resources to build. Things that can help limit the time it takes to create a table is knowing the password length restrictions. For example, if your passwords must be between 7 and 9 characters then the hacker only has to compute hash values in that range.
Now the salt value has to be available to the function that is going to hash a password attempt. Generally speaking you could hide this value elsewhere; but quite frankly if they've stolen the database then they'll be able to track it down pretty easily. So, placing the values next to the actual password has zero impact on security.
Adding an extra bit of characters that is common to ALL passwords adds nothing to the mix. Once a hacker cracks the first one it will be obvious that the others have this value and they can code their rainbow table generator accordingly. Meaning that it essentially saves no time. Further, it leads to a false sense of security on your part which can lead to you making bad choices.
Which leads us back to the purpose of salting passwords. The purpose is not to make it impossible, as anyone with time and resources can crack them. The purpose is to make it difficult and time consuming. The time consuming part is to allow you the time to detect the break in, notify everyone you have to, and enforce password changes in your system.
In other words, once the database is lost then all users should be notified so that they can take the appropriate action of changing their passwords on yours and other systems. The salt is just buying you and them time to do this.
The reason I mentioned "impractical" before with regards to cracking them is that the question is really one of the hacker determining the value of the passwords versus the cost in cracking them. Using reasonable salt values you can drive the computational costs up enough that very few hackers would bother. They tend to be low hanging fruit kind of people; unless you have a reason to be a target. At which point you should look into other forms of authentication.
This only helps if your threat model includes a situation in which your attacker somehow obtains your password database, but cannot read the secret key stored in your code. For most, this isn't a terribly likely scenario, so it's not worth catering for.
Even in that limited case, it doesn't gain you a great deal of additional security, as the attacker can simply take their own password, and iterate over all possible secret key values. Once they find the right one (because it hashes their own password correctly), they can use that to attack all the other passwords in the database as they would normally.
If you're concerned about storing passwords securely, you should use a standard scheme like PBKDF2, which uses key stretching to make brute forcing much less practical.
I am looking for a password hash function that can stay with me for years. Picking the wrong one can be fatal, as it is impossible to upgrade the existing hashes without having the users log in.
It is often suggested to use bcrypt or sha256-crypt from glibc. These use
key stretching,
but I do not like the fact that I am unable to extend the stretching later on.
One should be able to keep up with Moore's law.
Right now, I am considering the simple algorithm from the Wikipedia link, with SHA-256 for the hash function. That one allows me to just keep adding iterations as I see fit.
However, that algorithm is not a standard. It is therefore unlikely that I will ever be able to use the password hash with LDAP, htaccess, and so on.
Is there a better option available?
You should use SHA1 for password hashing. However, more than algorithm, you should also consider adding salt to passwords. Ideally a random salt should be created for each password and stored along with password.
This is to defeat rainbow tables.
Great discussion on this : Non-random salt for password hashes
I may be coming at this from another angle, but if you are saying that you may have users who will not log in for long periods of time then that presents a big risk. The longer you allow a user to stick with the same password, the greater the risk of bruteforce from an attacker who manages to grab your password hash file somehow. Don't rely on security preventing that ever happening...
Hash functions don't go out of date that rapidly, so I would imagine you should be fine reviewing this annually, as hopefully you will have your users change passwords more often than that.
It all depends on your exact requirements, obviously, but have a think about it.
In general bcrypt or sha256 can suit the requirement nicely.
Update: You could think about popping this query across to security.stackexchange.com, as it is a security management question.
Some time ago I joined new project. It was under development for quite a long time.
The thing that surprised me was that all users' passwords are stored in non-encrypted form.
I explained huge security vulnerabilities of this to our management - it looks like they agree with that and want to make project more secure. Team members agree too.
We have about 20K users in the system.
Actually it is quite stressful to make this work - migrate non-encrypted passwords to encrypted form. If something goes wrong it can lead to project's disaster.
How can I lower this stress?
Backup?
Unit-tests(integrational tests)?
Well, be careful with your backup because it will contain unencrypted user passwords :-)
Assuming that the passwords are stored in a database, an easy solution would go something like this:
1) Make a secure backup of the entire table data
2) Create new column (PasswordEncrypted or similar name)
3) Use an UPDATE query to update each row's new column with an MD5 of the unencrypted password while using a 32 byte or larger salt. Pretty much every database system today has an MD5 function so you won't even have to leave your SQL prompt
4) Keep the plaintext column in the interim and update your application/scripts accordingly to work with the salted password.
5) Rename the plaintext old password column to temporarily take it out of play and test your application- if there are any problems then go back to step 4 and fix your mistakes.
6) When everything is working properly drop the plaintext password column
7) Encourage users to pick a new password now that you have some level of security in place to mitigate the effects of any previous attacks which may have been successful.
What sort of project is this? A web application, desktop application?
If you're going down the refactoring road, is there a reason that the passwords need to be stored in something reversible like encryption? In general, it's good practice to hash your passwords with something like SHA then hash the input with the same algorithm and compare the results. You only store the hashed values, not the actual passwords. This gives you the ability to check that someone has entered the correct password without exposing your users to the possibility of your encryption being broken and their passwords exposed.
Specific information about your approach isn't something I can provide (since I don't know how it works), but your best bet is to create an additional column to store the hashed passwords, hash the existing passwords, then keep them up to date with any password changes. Use this new column for all new development, then once the move is complete and tested, delete the column with the plaintext passwords.
Write lots of tests, that test lots of corner cases (upper and lower case, numbers, symbols, Unicode characters, long passwords, etc). When you're developing and testing, create a system to move back to the old system (by providing the old password list, of course, since once the passwords are hashed you won't be able to convert them back directly). Save a copy of the current password list. Convert the passwords over in a test file or test database, and then use the saved copied of the passwords to test that everything worked. Now move the system into production, and make sure it works for your users. If it does not, you have already tested the plan for migrating back to the old system. Once it has been demonstrated to work for a couple of weeks, you can delete the cleartext password list and you're all set.
I would just hash the current passwords, store them in a new database field, and begin using that field while deleting the password field. I would then notify my users that now would be a good time to change passwords as you've implemented more security mechanisms to keep their data safe.
To have a backup, just do SELECT * INTO Backup FROM UserData
You can get extra confidence by running both authentication methods (encrypted and unencrypted) for each login attempt, and if they yield a different outcome, get an alert e-mail sent to you. This change is not visible to your users, so it can run for weeks and even months. Once you see that the old and the new authentication works for a high enough percentage of your users, deactivate the old one.
If possible you can try this: Send out an email to all your users to update their passwords with a time-out period, after which they cannot work if they do not change their passwords. Hash these new passwords and store the hash. This would require some changes on the frontend (i.e. the data it sends back).
Ok, so the whole problem with hashes is that users don't enter passwords over 15 characters long. Most only use 4-8 characters making them easy for attackers to crack with a rainbow table.
Solution, use a user salt to make hash input more complex and over 50chars so that they will never be able to generate a table (way to big for strings that size). plus, they will have to create a new table for each user. Problem: if they download the db they will get the user salt so you are back to square one if they care enough.
Solution, use a site "pepper" plus the user salt, then even if they get the DB they will still have to know the config file. Problem: if they can get into your DB chances are they might also get into your filesystem and discover your site pepper.
So, with all of this known - lets assume that an attacker makes it into your site and gets everything, EVERYTHING. So what do you do now?
At this point in the discussion, most people reply with "who cares at this point?". But that is just a cheap way of saying "I don't know what to do next so it can't be that important". Sadly, everywhere else I have asked this question that has been the reply. Which shows that most programmers miss a very important point.
Lets image that your site is like the other 95% of sites out there and the user data - or even full sever access - isn't worth squat. The attacker happens to be after one of your users "Bob" because he knows that "Bob" uses the same password on your site as he does on the banks site. He also happens to know Bob has his life savings in there. Now, if the attacker can just crack our sites hashes the rest will be a piece of cake.
So here is my question - How do you extend the length of the password without any traceable path? Or how do you make the hashing process to complex to duplicate in a timely manner? The only thing that I have come up with is that you can re-hash a hash several thousand times and increase the time it would take to create the final rainbowtable by a factor of 1,000. This is because the attacker must follow that same path when creating his tables.
Any other ideas?
Solution, use a user salt to make hash
input more complex and over 50chars so
that they will never be able to
generate a table (way to big for
strings that size). plus, they will
have to create a new table for each
user. Problem: if they download the db
they will get the user salt so you are
back to square one if they care
enough.
This reasoning is fallacious.
A rainbow table (which is a specific implementation of the general dictionary attack) trades space for time. However, generating a dictionary (rainbow or otherwise) takes a lot of time. It is only worthwhile when it can be used against multiple hashes. Salt prevents this. The salt does not need to be secret, it just needs to be unpredictable for a given password. This makes the chance of an attacker having a dictionary generated for that particular salt negligibly small.
"The only thing that I have come up with is that you can re-hash a hash several thousand times and increase the time it would take to create the final rainbowtable by a factor of 1,000."
Isn't that exactly what the Blowfish-based BCrypt hash is about? Increasing the time it takes to compute a hash so that brute force cracking (and rainbow table creation) becomes undoable?
"We present two algorithms with adaptable cost (...)"
More about adaptable cost hashing algorithms: http://www.usenix.org/events/usenix99/provos.html
How about taking the "pepper" idea and implementing it on a separate server dedicated to hashing passwords - and locked down except for this one simple and secure-as-possible service - possibly even with rate-limits to prevent abuse. Gives the attacker one more hurdle to overcome, either gaining access to this server or reverse engineering the pepper, custom RNG and cleartext extension algorithm.
Of course if they have access to EVERYTHING they could just evesdrop on user activity for a little while..
uhmm... Okay, my take on this:
You can't get the original password back from a hash. I I have your hash, I may find a password that fits that hash, but I can not log in to any other site that uses this password, assuming they all use salting. No no real issue here.
If someone gets your DB or even your site to get your config, you're screwed anyway.
For Admin or other Super Accounts, implement a second mean of verification, i.e. limit logins to certain IP ranges, use Client-Side-SSL Certificates etc.
For normal users, you won't have much chance. Everything you do with their password needs to be stored in some config or database, so if have your site, I have your magic snake oil as well.
Strong Password limitations don't always work. Some sites require passwords to have a numeric character - and as a result, most users add 1 to their usual password.
So I'm not entirely sure what you want to achieve here? Adding a Salt to the front of the users password and protecting Admin accounts with a second mean of authentication seems to be the best way, given the fact that users simply don't pick proper passwords and can't be forced to either.
I was hoping that someone might have a solution but sadly I am no better off then when I first posted the question. It seems that there is nothing that can be done but to find a time-costly algorithm or re-hash 1,000's of times to slow down the whole process of generating rainbow tables (or brute-forcing) a hash.