7

I've been looking into storing user passwords in mysql and the ubiquitous reply is to store it using an encryption algorithm like MD5 or SHA1. But what if user x forgets her password and wants it to be sent to her? What then? I can't send her the md5 hash! How is this issue dealt with in the real world. Are there two databases? One to compare hashes and another for forgotten passwords? But what's the difference, both would be read-only by the sql user connecting to it at that time. So how do you do it? Thanks!!

marc_s
  • 732,580
  • 175
  • 1,330
  • 1,459
eatonphil
  • 13,115
  • 27
  • 76
  • 133
  • 1
    Please Please just have a password as a one way street. i.e. from user to yourself, not the other way around. Have a few questions and captha. Also have enable a few tries before having a cooling off period to prevent somebody trying to hack it. – Ed Heal Nov 09 '12 at 14:41
  • 1
    Don't hash it using MD5 or SHA1. They are not meant for hashing passwords. Use bcrypt. If you want to make it easy for yourself use the [password_compat lib](https://github.com/ircmaxell/password_compat). – PeeHaa Nov 09 '12 at 14:42

3 Answers3

10

It's pretty standard security practice to never send users their password. Instead, you offer a password reset utility that is tied to their ability to access their e-mail account, and/or ability to answer question about their profile (like a security question or what postal code they live in).

Functionality Outline:

  1. User clicks "forgot password link"
  2. User enters security challenge information (e-mail address, security question if desired)
  3. System sends password reset e-mail with auto-generated link (with generated GUID in a querystring for instance)
  4. System creates a password reset record containing the reset GUID, what user it is for, and when the key will time out.
  5. User retrieves e-mail, clicks on link.
  6. System matches GUID, deletes password reset record, sends user to password reset page.
pseudocoder
  • 4,314
  • 2
  • 25
  • 40
  • It's a very good idea to add a security question. Otherwise, it's not hard for someone who has breached a user's email account to then gain access to your site (and the user's information). An additional layer of security (such as a security question) can help to prevent that. – JDB Nov 09 '12 at 15:49
  • I disagree with the security question - they add almost zero security – jah Nov 09 '12 at 15:55
  • 2
    A secondary credential (which may be a security question or something else) is required if the service being protected is more sensitive than just ownership of the e-mail channel. Since e-mails go in the clear to an account that is often itself compromised, lots of third parties potentially have access to the reset code. For a noddy web forum account, you aren't going to bother; for something like online banking, you are. – bobince Nov 09 '12 at 16:40
3

The best solution is to send the user a link where they can enter a new password without having to enter the forgotten one.

This link should only work once and it should work only for a few hours.

Don't create a new password and send that by mail; users will feel tempted to use that password (ignoring the fact that is has been transmitted over an insecure channel).

Aaron Digulla
  • 321,842
  • 108
  • 597
  • 820
  • Not sure why you think this is any better than regen'ing a new one and forcing a change on first use. – NotMe Nov 09 '12 at 14:36
  • 1
    Users are more likely to remember passwords they set themselves, and if someone intercepts the reset mail, at least you have a log of their IP address because they have to come to your site to perform the reset. – pseudocoder Nov 09 '12 at 14:39
  • @pseudocoder you wouldn't necessarily have a log of their IP address and it wouldn't help detection much even if you did – jah Nov 09 '12 at 15:54
  • 1
    @jah In both your comments on this QA you are assuming a case where the site operator has made no security preparations and the user's identity is completely compromised. In that case, you are correct, there's not much that can be done to prevent account theft. It's the job of the site operator to marginalize those situations, not eliminate them. – pseudocoder Nov 09 '12 at 16:19
  • @pseudocoder would you care to elaborate? I'm not sure what you're getting at, but I certainly did not assume any such thing. – jah Nov 09 '12 at 16:32
  • 1
    @jah What I'm getting at is no level of security is absolute, so commenting that a certain security measure is ineffective in some situations is really a moot point. The question is rather whether certain security measures provide protection for a significant percentage of scenarios given the sensitivity of what you want to protect. The model discussed in this thread, I believe, is appropriate for most general use password recovery situations; that belief is backed up, at least anecdotally, by the prevalence of websites that currently employ it. – pseudocoder Nov 09 '12 at 17:12
  • @pseudocoder My comments 1) corrected your false assertion about IP logging and 2) stated that I disagree with the employment of security questions (in the context under discussion) and that they provide almost zero additional security. In neither comment did I make assumptions about 'security preparations' or the extent of compromise of a 'user's identity' (whatever that may mean). You appear to me to be introducing fallacious argument into the discussion; but perhaps I am mistaken in that regard also. – jah Nov 09 '12 at 18:26
2

You are correct that passwords should not be stored in plain text (they should be hashed) and therefore cannot be delivered to users who have forgotten their password.

Essentially, what you desire is a way to circumvent your normal authentication scheme and you should first be aware that such a mechanism is a back door to the application.

Very often an assumption is made that only the desired user can access emails sent to the email address registered with your application. It is on this assumption that the 'standard' password reset mechanism is based. Here's my take on that:

  1. The forgotten password page is requested and the user is asked to enter their registered email address into a form which they then submit
    • The receiving code checks that the submitted email address is indeed registered and if it is:
      • delete any existing password reset tokens for this address from the appropriate storage
      • generate and store a new password reset token for this address
      • send an email to the user which informs them that
        • 'someone' has requested a password reset
        • to click the link if they do indeed wish to reset
        • to ignore the email if they did not request a reset
      • respond to the form submission with a page which says something along the lines of "if the address submitted was registered then a reset email has been sent"
    • If the submitted address was not one registered with the application then do nothing but respond to the submission with a page which says something along the lines of "if the address submitted was registered then a reset email has been sent" - just the same as if the address was a valid one (this is to make it more difficult for someone to discover email addresses registered with the application)
  2. The user then receives the forgotten password email and clicks the link within it. The link delivers the password reset token to the application.
  3. Upon receipt of a password reset token, the code checks that the token exists in storage and that it has not yet expired. If these hold true, then you assume that it must be the registered user who submitted the token and you can allow them to set a new password (a simple form with password and password confirmation inputs and a submit button and which contains zero personal information - not even their name).
  4. Once the password has been set, you can direct the user to the login page where they enter their credentials as normal.

This isn't a perfect scheme. It's a trade-off between security and convenience and make no mistake that it constitutes a back door to the application. For low value applications it is usually good enough.

Further reading:

Community
  • 1
  • 1
jah
  • 2,056
  • 1
  • 18
  • 35
  • I am just wondering at this point. How is it that big sites have password forget fallbacks? Instead of always requiring a new password? – eatonphil Nov 09 '12 at 15:50
  • @phileaton perhaps because they have decided upon a trade off between security and convenience that suits them better; perhaps because they know not what they do. – jah Nov 09 '12 at 15:53
  • I'm just trying to figure out how they can have incredible security and be able to get users a non-hashed password. I.e Google, Facebook, this site probably does it too. If you forget your password, they send you it. How is it they can do that in their databases? – eatonphil Nov 09 '12 at 15:59
  • 1
    I especially like point 3. It would be fairly easy for someone to develop a tool to hit a website with generated hashes, hoping to occasionally get a valid one. If they do, and they change the password, it's best that they not know who's password they have changed. If this happens, the user can always reset the password again via the normal mechanism. – JDB Nov 09 '12 at 16:01
  • 1
    @phileaton - Google does not send you your password. – JDB Nov 09 '12 at 16:03
  • @phileaton a site which sends out plain text passwords are doing one of three things (in decreasing order of likelihood) 1) storing passwords in plain text, 2) creating a new password and sending it to you before it's stored, 3) brute-forcing the hashed password and sending you the result (which is unheard of in my opinion). – jah Nov 09 '12 at 16:04
  • 1
    Just a note, a password should be **hashes**, not **encrypted**, encrypted implies it can be **decrypted** back into a plain-text password. Hashing is a one-way algorithm. – Madara's Ghost Nov 09 '12 at 18:09