3

I want to send emails to users when the forget their passwords that prompt them to reset their passwords. I know this is debatable and was looking for a few good options/suggestions/methods/articles to choose from.

I'm prompting users to press a 'forgot password' link with a simple script with the PHP portion doing this:

$Email = $_POST['email'];
$success = false;
$formError = false;

if(isset($_POST['sub_forgot_pw'])) {

    if(empty($_POST['email'])) {
        $formError = "true";
        $error = "Please enter your e-mail address.";
    }else{
        $to = $Email;
        $subject = "Password Help";
        $message = "To reset your password, please <a href='http://www.blahblahblah.org'>Click here</a><br /><br />Do LIFE,<br /> The Team";
        $from = "CysticLife <noreply@cysticlife.org>";
        $headers  = 'MIME-Version: 1.0' . "\n";
        $headers .= 'Content-type: text/html; charset=iso-8859-1' . "\n";
        $headers .= "From: $from";
        if(mail($to, $subject, $message, $headers));{
            $success = "true";
        }


    }

}
LightningWrist
  • 937
  • 4
  • 20
  • 37
  • 3
    In my opinion you should not be storing passwords and the user should not have to create YET another account to use your service. I created this simple openid helper library(uses LightOpenID and openid-selector) which you could use if you like instead? => https://github.com/alfredwesterveld/php-openid – Alfred Jan 31 '11 at 22:53
  • Just a side note. This query `SELECT * FROM `Users` WHERE `Status` = 'active'` looks wrong to me. It lacks of at least one condition. It should be something like `SELECT * FROM `Users` WHERE `Status` = 'active' AND email = '$email'` – Francesco Laurita Jan 31 '11 at 23:00
  • Those are really cool however I have about 3500 members on my site. Would just have to figure out a smooth transition. – LightningWrist Jan 31 '11 at 23:00
  • @Francesco - I am able to send the emails just fine. – LightningWrist Jan 31 '11 at 23:02
  • 1
    @LightningWrist : `SELECT * FROM Users WHERE status = 'active'` will return always at least a row until there is at least one active user. `$Email = $result['Email'];` is the email value of the first row returned from the query so I can't figure out how can it works but i'm glad it works for you! :) – Francesco Laurita Jan 31 '11 at 23:11
  • Oh man its Monday. Good eye. should get rid of that query all together and just do $_POST['emal']; – LightningWrist Jan 31 '11 at 23:17
  • @Francesco - +1 for helping me realize my grotesque over site. – LightningWrist Jan 31 '11 at 23:42
  • Or you could use [this solution](http://stackoverflow.com/questions/3784958/send-email-to-user-for-password-reset), it's C# but should fit your needs. – Marc Jan 31 '11 at 22:56

2 Answers2

11

Here's what I do:

I have reset_password table. When someone asks for a reset, they usually click a link on your site that says "forgot password" where they enter their email they registered with and your system sends a link. Of course you begin with finding out if the user is registered at all. by selecting from users where email = $_POST['email']. If they exist, make a randomly generated token, like

$token = md5($_POST['email'].time());

But as Buh Buh expressed in the comment below, you may want to use something a little less obvious to generate your token. crypt() can accept a salt pattern if you like.

Insert the request (email and token) in the reset_password table, then you send them a link like

http://www.domain.com/resetpassword.php?token=<?php echo $token; ?>

Then in that file you take the $_GET['token'] and cross reference it with the reset_password table. If the token is valid, you present them with a form that asks for their new password. Upon submit, select the user with the email address related to that token and update the user table.

Yahel
  • 8,522
  • 2
  • 24
  • 32
Kai Qing
  • 18,793
  • 5
  • 39
  • 57
  • At least for me $token = md5($_POST['email'].time()); is working better. Without the brackets the variable token it was depending only on the given e-mail address. – Leandro Dec 03 '12 at 03:05
  • 3
    (Originally posted by an anonymous user): Do NOT use this advice, it is very insecure. All someone would have to do to reset any password on your site is enter someone's email in the reset blank, and look at their wrist watch, then make the same token themselves. Anyone can know the time to the second, and anyone can take the exact same MD5. – Buh Buh Jun 20 '13 at 20:53
  • True, but it would have to be exact and they would also have to know this is definitely the method used, which may not be too hard to decipher if even a little effort was put into the hack. But the general concept is not particularly insecure so long as you create token rules that are not easily identified by just looking at the url. – Kai Qing Jun 20 '13 at 22:26
  • 1
    Buh, Buh: So instead of using `time()` it is better to create a completely random key like: `$key = uniqid(mt_rand(), true);` and then create the token like: `$token = md5($_POST['email'].$key);` or sha1/sha256? – TheYaXxE Mar 12 '14 at 09:17
  • @TheYaXxE - yes, pretty much. Point is to create a string and convolute the generation process enough to avoid people trying to guess your methods and hack away. – Kai Qing Mar 12 '14 at 18:18
  • @Kai Qing - Great :D But should the request also be deleted after the password has been reset? You know, to make sure that the request cannot be used again and again and again.... :) – TheYaXxE Mar 13 '14 at 08:42
  • I usually give the request a date time and treat it as invalid if it is over an hour old. I don't delete the record in case there's a reason to review the history of requests. This all depends on your own needs, so do what makes most sense to you. – Kai Qing Mar 13 '14 at 15:59
  • @Kai Qing can you please provide the script that you use for forgot your password since I have been searching hours for secure script for forgot ur password – Yousef Altaf Sep 15 '14 at 10:18
  • It's not really as simple as having a universal script to handle it. The script wouldn't likely match your database structure, site routing, or possibly mail handling anyhow. This answer has enough to guide you on creating the script for your site. Mine is always different depending on the projects because I never know who wrote the code I inherit. But I assure you, this is a pretty easy thing that you can write out in 20 minutes. – Kai Qing Sep 15 '14 at 15:59
1

There is a danger of loosing out the url to anyone who sniffs network. To avoid this, you may generate a random short key such as vX4dq and save it in your database. Ask user to remember this. When a user resets via the link, ask him/her to enter this key only known to him.

Advanced :- you may show this key in a captcha so that it doesn't get sniffed.