2

I use a token generated from bin2hex() for a user to reset their password. This token is stored as is in the db and when a user uses it their token is searched against the one in the db and if they are the same they can reset their password.

I was reading here (PHP - How to implement password reset and token expiry) that I should hash the password before storage. This seems like a good idea, but I was wondering how I would search against the hashed password, would I also need to include the username/email in the token-based url that is sent to the user so that they can be searched again and then the hashed token is checked?

Is it okay to include an obvious identifier in the reset link (I suppose that it is because it is sent to their email address).

JMP
  • 4,417
  • 17
  • 30
  • 41
MartynW
  • 641
  • 2
  • 7
  • 23
  • Reset tokens are just random strings. They should not contain any information and thus there is nothing to hash. Your user table would have a reset_token column which stores the unique token. If you want your token to expire then add a reset_token_expire column as well. I think you may be overly complicating the issue. – Cerad Jan 30 '19 at 13:42
  • I guess I was worrying based on the discussion in this link (https://stackoverflow.com/questions/3164978/php-how-to-implement-password-reset-and-token-expiry) saying that if the token is stored in plain text and someone gained access to the db then they would have the token which would have consequences for security. You are right that it is probably over complicated for a small app. – MartynW Jan 30 '19 at 13:50

1 Answers1

2

Yes, you should hash password reset tokens because

  • reset tokens expire and not every user has an active one
  • users notice when their passwords are changed, but not when their passwords are cracked, and can thus take steps to limit the damage (change password and other sensitive data, etc).

Additionally, as users reuse passwords, an attacker can try a cracked passwords for other accounts, such as the users email, thus increasing the damage.

Key points:

If your token has enough entropy, lets say 20 random characters 0-9 a-z A-Z, then you can calculate an unsalted fast hash (e.g. SHA-256 or SHA-512) and store it. This is safe, because it is not possible to successfully brute-force such strong "passwords". Salting is done, because passwords choosen by people are often relatively weak, because they have to be remembered.

If a "password reset token" allows someone to reset a password with other clear text information, then it's effectively the same as a password and Should be treated as such. Make them expire of a few minutes or hours, and treat them like secrets, because they are.

I hope this will help

Muhammad Hasham
  • 273
  • 1
  • 6
  • 14
  • Thank you for your answer. My token is from bin2hex(random_bytes(64))so should be secure against brute force attack. I am still not entirely clear how I would search the db using the users plaintext token against the hashed token that is stored though? Maybe I am missing something. – MartynW Jan 30 '19 at 08:51
  • Okay, I think I understand now: 1. Generate a long random string, $token and send this as plaintext to the user as part of a url 2. Hash the string using hash(md5, $token) and store this in the db 3. when the user uses the token-based url grab the plaintext token, hash it and find the result in the db and then check if it is still valid. It was the fact that md5 hashing always produces the same string that I had missed. Once again, thank you – MartynW Jan 30 '19 at 15:15