34

I am developing an application in PHP and it uses bcrypt encryption to store passwords. I want to keep the history of hashes whenever the user changes the password. By doing this I want to stop the user from entering the previous passwords in some scenarios.

Is it safe to keep the history of hashes?

According to my observation, if a user changes his password and keeps the same as a previous one, the hash values become different. How can I stop him from keeping the same password from the previous history? Is it possible while using bcrypt encryption?

Hassan Saqib
  • 516
  • 4
  • 12
  • 26
    I'm pretty sure I've read that forcing password changes actually decreases security, by leading people to use weaker passwords. (Except in cases of known or suspected compromise.) – Tyler Apr 01 '15 at 23:32
  • 2
    You're assuming they don't just change their passwords n+1 times to bypass your history and keep the same password anyway. It's not clear what underlying problem you're trying to solve, but things like allowing very long passwords, offering two factor authentication or even authentication through federated services such as oauth may be an appropriate solution to your problem – wireghoul Apr 02 '15 at 03:20
  • 2
    Somewhat related to this is http://security.stackexchange.com/questions/53481/does-facebook-store-plain-text-passwords. If you want to prevent users from using *similar* passwords as well as the same password (e.g. preventing them from using `password1`, then `password2`, then `password3`, you could use the same approach as Facebook does (previous link) and store hashes of variations of the password as well. – Matt Apr 02 '15 at 12:20
  • 1
    @Tyler: I don't doubt that you've read that. I suspect you've also read the opposite, that changing passwords semi-regularly reduces the likelihood of an offline attack finding the correct password before the next password change. Then, unfortunately, every programmer makes their own decision which factor they believe predominates! I certainly agree that the side I present is kind of unconvincing, since it can only be true for passwords that are guessable in 6 or 12 months but not in 3. I just mean to point out that having read a hypothesis is not grounds for believing it ;-) – Steve Jessop Apr 02 '15 at 23:20

4 Answers4

43

Security of storing Hash History

Is it safe to keep the history of hashes?

Relatively. I can imagine some scenarios where this would harm the security of the user, eg:

  • A user uses a relatively weak password, realizes this and updates the password to a better password, based on the previous password (simple example: superawesome -> !sup3eraw3s0m3!), this would lead to an attacker being able to easier crack the now more secure password (they first crack the easy password, have it in their wordlist now, and then apply basic rules to it such as e -> 3, etc).
  • They previously used a password on your website that they also use at a lot of other websites, stopped trusting your website, and thus changed the password at your website. An attacker could get your database, crack their old password (which they thought would be deleted from your database), and then try the login credentials at a different website.
  • After a while, you have a lot of history on a user that changes passwords frequently. An attacker cracks lets say 30% of the history hashes, and now has a pretty good idea how that specific user creates passwords. If the user doesn't create passwords truly random, it will be a lot easier to break the current password.

So I would not recommend keeping a password hash history.

Alternative

How can I stop him to keep the same password from the previous history?

Don't keep a history. When a user changes their password, you still have the original password hash in the database. You can compare it to that to prevent exact duplicates.

But using bcrypt, this happens:

According to my observation, if a user changes his password and keeps the same as a previous one, the hash values become different

It happens because bcrypt automatically manages salts for you. So when you hash a new password, it is hashed with a different salt, and thus the hash is different. You could retrieve the old salt, and then pass it onto password_hash as argument to get the same hash.

Better Alternative

You could also require the user to submit their old password when changing passwords (which also increases security[*]), and then you can even check if the new password is similar to the old password (eg using hamming distance or similar).

Both of my alternatives do not prevent cyclic changes though (eg super-secure-password -> another-awesome-credential -> super-secure-password), but I'm not sure if I would really be worried about that.

[*] someone highjacking a session can't change the password, and the password can't be changed by CSRF (even if there is an XSS vulnerability).

tim
  • 29,018
  • 7
  • 95
  • 119
  • 1
    Thanks Tim your answer is helpful. Keeping in view your answer I have another question. Google asks to apply some previous passwords when we forget password and email both. Facebook stops us keeping any previous passwords again if we claim our password was changed not by us.. What the possible view point of it can be? – Hassan Saqib Apr 01 '15 at 21:36
  • @HassanSaqib I've never seen that option for Google (and I would be very surprised if it existed, as it seems like an extremely bad idea). I don't know about Facebook, but it sounds as if they have an option to "ban" passwords set by a possible attacker, which doesn't really hurt, but I don't see the advantage in it either. – tim Apr 01 '15 at 21:45
  • 2
    Google asks "Enter the last password that you remember" and Facebook also stops users entering the previous passwords. – Hassan Saqib Apr 01 '15 at 21:50
  • @HassanSaqib You are right, that option does seem to exist. But it seems that you can also [enter](http://blog.securestate.com/gmail-password-resets-the-quiet-things-that-almost-no-one-ever-knows/) completely [random](https://webapps.stackexchange.com/questions/27258/) data. I don't know what exactly is happening there, but if this still exists, it's quite worrying. – tim Apr 01 '15 at 21:57
  • This "You could also require the user to submit their old password when changing passwords" does not worth when the user are changing password because they lost it. – Rémi Apr 02 '15 at 12:23
  • 1
    @Rémi that's true. But the question isn't really about storing old hashes for password recovery, it's about password policy and users changing passwords to old passwords (the original title contained `prevent user to keep same passwords again and again`, which made this a bit more explicit). And if the user lost their password, the chance of them reusing the same password is pretty low ;) – tim Apr 02 '15 at 12:51
  • 1
    @tim, throughout your post you use the word "decrypt". I think you should change all of them to "guess". – TTT Apr 02 '15 at 19:11
  • @TTT Thanks, you are right that `decrypt` really isn't the right word. I changed it to `crack` instead (this actually seems like a legitimate word for it, it appears in some papers, and it has a wiki page and all), because I think `guess` sounds a bit like manual (instead of automated) testing. – tim Apr 02 '15 at 19:19
  • 1
    Dont you mean `!sup3raw3s0m3!` instead of `!sup3eraw3s0m3!`? – Loko Apr 03 '15 at 07:36
  • I wouldn't trust Facebook as an example of secure practices. Try logging in with an old password and they will give you this message. "Looks like you are trying to use an old password. You changed that n time ago. Try those same credentials in banking applications." – Nick Apr 07 '22 at 15:28
11

Actually, the comments on how Google deals with old passwords (still recognising them to retrieve a locked-out account), got me thinking on the pro's and con's of this, and whether you could use it to avoid people re-using old passwords in a relatively secure way. Not that I actually think you would want that (personally I think that 99% of "enforced best practices" for password use just result in people writing down their password; this is true unless the person involved really really recognises the importance of the password (e.g. it allows operation of a nuclear power plant), in which case there is no need to enforce the best practices in a technological way).

First let's look at how Google may have implemented their system in a relatively secure way. From the comments above I understand that when one loses access to their email and forgets their current password, some sort of recover-workflow is started, where one provides "evidence" of their identity. Probably at some point a human will make a decision on whether to restore access to that account. At that point they need as much evidence as they can find that you are you! Knowledge of a previous password can provide a hint.

Now the problems of storing old password hashes are as @tim mentions in his elaborate reply -- even through I suspect Google secures their databases a lot better than most others, a data breach can always happen. If however instead of storing a full 128-bit/256-bit password hash (salted), they only store the first 16 bits (for old passwords), then it will be impossible for an attacker to extract a password from this*. At the same time, if someone provides 2 passwords that match 2 of the 4 16-bit hashes stored, this is a large hint that the person is not a completely random hacker**.

Say that your requirement is to not allow any password that has ever been used before on the system for that user (e.g. your boss read somewhere that its a good idea and won't allow anyone to change his mind). Again I fully agree with @tim's assessment that storing hashes for old passwords is a really bad idea. So what if we use the suggested Google solution, and store only a small hash for a password? Problem is that if we use 16 bits hashes, we have a reasonable change of disallowing a password that was not used before, but has the same 16-bit hash. The birthday attack shows that for 16 bits, after 36 passwords there is a 1% chance that at least one new password gets rejected --- this may or may not be acceptable. More bits means that this chance gets smaller, but the information exposed by a hacked database gets bigger.

* If your old passwords are "monkey1", "monkey2", "monkey3", a hacker may still be able to pick up this pattern. On the other hand, since Google doesn't require monthly passwords changes, I expect people that use simple patterns, not to care about changing their google password at all.

** Again I want to make clear that it's nothing more than a hint! The whole idea of old passwords is that they have been changed because they might have been compromised. So knowledge of an old password is not even that strong a hint; probably they'll want you to scan your ID card or something before restoring access. It does however add a first layer of protection against some 16 year old kid trying to hack into a teacher's account, or a computer script trying to hack many accounts at the same time. 16 bits will mean that only 1 in 64k random password attempts pass.

Claude
  • 241
  • 1
  • 3
  • If someone obtained the list of shortened hashes without being noticed, they could very easily find passwords that match as many of the 16-bit hashes as they want and even look "plausible". Won't that allow them to hijack any account? – Hagen von Eitzen Apr 03 '15 at 12:28
  • Not really. In neither scenario the 16-bit passwords are used to log in. In Google's case you may have a point, but if the "old password" is just being used to allow you to move to the next level where a human will look at the evidence (basically to filter out bots) there is nothing to be gained. You're still not going to get access to the account without some other type of proof. – Claude Apr 03 '15 at 12:32
1

Most of the comments here are pretty good and identify the key issues. However, one point which needs to be considered is that you need to assess these types of questions in context and be very careful regarding generalisations which state that it is either good or bad.

Questions of password history are related to the concept of password aging and requiring users to regularly change their password. At one time, it was recognised best practice to age passwords and maintain a history to ensure users didn't re-use a previous password. This was, in most cases, appropriate for the times and enviornments most prevelant at the time. However, things have changed and for many, being forced to regularly change your password and prventing password re-use is of little benefit and possibly even detramental.

There has been some research which presents the premise that password aging and password history may actually decrease security rather than increase it. The basic assumptions and ideas are

  • Most people only have a set number of good passwords they are able to remember
  • When forced to change their password regularly and are prevented from re-cycling passwords, they use /patterns/ to help make the requirement manageable
  • If you are able to obtain enough password history information, identifying these patterns may become possible. This could not only make the search space for guessing a password smaller, it could even allow prediction of future passwords.

So, does this mean password aging and history is a bad idea? Possibly and possibly not. It depends on the environment.

In my private life, I use a large number of web services. I try to adopt good password practices - I use different passwords on different sites, I use strong passwords and I use two factor verification where possible. I don't communicate passwords over insecure channels etc. In this enviornment, being forced to change my password and being prevented from re-using a password is unlikely to improve my security. If the service provider is not protecting this information appropriately, it could even be reducing my security as attackers may be able to guess my clever password 'pattern'.

On the other hand, I at one time worked in an environment where many of the staff travelled a lot and frequently used unknown and possibly insecure networks. In this situation, there was a much higher risk that a password has been compromised. For this scenario, requiring users to change their passwords regularly may be justified as it will reduce the attack surface i.e. the amount of time where a compromised password may be used by unauthorised 3rd parties. Enforcing password history will ensure the user does not re-cycle a password which may already have been compromised. (in reality, probably much more benefit would be achieved through user education and teaching people how to recognise possibly dangerous networks and letting them change their password when they can accurately assess the risks rather than force a one size fits all type solution, but user education and awareness is a very hard nut to crack!).

The extent to which password history may be a security issue really depends on how well the history is secured. The danger is that people may think that because it is only a history of past passwords, it doesn't require the same level of protection that the actual password data requires. This would usually be a mistake. The password history needs to be treated with the same level of protection as the current password data. If this is done effectively, then it probably at no more of a risk than the actual password hash and of course, if the actual current password data is not adequately protected, then concerns about password history are probably irrelevant.

Tim X
  • 3,242
  • 13
  • 13
-4

Passwords should be hashed using an approved stretching algorithm, such as PBDKF2 or bcrypt. Furthermore, they should be combined with a unique salt which is then saved with the hash. Since the salt is unique, attacks may only occur against the given hash and its salt.

Since the hashing function is computationally prohibitive (when implemented correctly), there is no additional harm observed by keeping old hashes and salts of previous passwords.

Since a history must be kept to insure password best practices, then the only appropriate solution is to save the hash and it's salt, rotating them out as the user updates their passwords.

W1T3H4T
  • 338
  • 1
  • 6
  • 6
    you appear to use "encrypt" and "hash" interchangeably? – schroeder Apr 01 '15 at 23:02
  • encrypting is generally a reversable process; you encypt and decrypt a file. Hashing (in this context) is an irreversible process (or very difficult to reverse), you hash a password then it is impossible (very difficult) to get the password back. When the user enters their password it is hashed and the two hashes are compared – Richard Tingle Apr 02 '15 at 10:17
  • 1
    "Since the encryption function is computationally prohibitive": I think that you mean the inverse is computationally prohibitive, not that the actual hashing function is computationally prohibitive. – Patrick M Apr 02 '15 at 16:10
  • 1
    Passwords are usually hashed and not encrypted, which is a 1 way function. You don't 'decrypt' them. You verify by hashing what the user inputs as the password and comparing that to the hashed version which is on record. This means the risks are different. Understanding this difference is a prerequisite for assessing whether maintaining a history of password hashes is possibly a risk – Tim X Apr 02 '15 at 21:25
  • You're right - I had my mind on other things; will correct! thank you! – W1T3H4T Apr 09 '15 at 13:08
  • 1
    "I think that you mean the inverse is computationally prohibitive, not that the actual hashing function is computationally prohibitive." - no, not inversely prohibitive. A hashing function will always reproduce identical results when provided the text, or text plus the salt. The purpose of using a computationally prohibitive hash function is to reduce the likelihood that a rainbow table could be produced. The salt provides an additional layer of defense should all of the hashes be exposed: a rainbow table has to be corrected for each hash. – W1T3H4T Apr 09 '15 at 13:16