Create a forgot password function

I have a login deal which uses encryption to store passwords, it has a registration and login page
The function to register

	 public function register() {
	$correct = false;
		try {
			$con = new PDO( DB_DSN, DB_USERNAME, DB_PASSWORD );
			$con->setAttribute( PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION );
			$sql = "INSERT INTO users(username, password) VALUES(:username, :password)";
			
			$stmt = $con->prepare( $sql );
			$stmt->bindValue( "username", $this->username, PDO::PARAM_STR );
			$stmt->bindValue( "password", hash("sha256", $this->password . $this->salt), PDO::PARAM_STR );
			$stmt->execute();
			return "Registration Successful";
		}catch( PDOException $e ) {
			return $e->getMessage();
		}
 }

The function to log a user in

	 public function userLogin() {
	 $success = false;
	 try{
		$con = new PDO( DB_DSN, DB_USERNAME, DB_PASSWORD ); 
		$con->setAttribute( PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION );
		$sql = "SELECT * FROM users WHERE username = :username AND password = :password LIMIT 1";
		
		$stmt = $con->prepare( $sql );
		$stmt->bindValue( "username", $this->username, PDO::PARAM_STR );
		$stmt->bindValue( "password", hash("sha256", $this->password . $this->salt), PDO::PARAM_STR );
		$stmt->execute();
		
		$valid = $stmt->fetchColumn();
		
		if( $valid ) {
			$success = true;
		}
		
		$con = null;
		return $success;
	 }catch (PDOException $e) {
		 echo $e->getMessage();
		 return $success;
	 }
 }

Something that just occurred to me, What if the user forgets the password?
I gather it would best to put a “Forgot password” link on the login page.
On the page ill just have a form to allow the users email. If the emails match I send them an email so they can reset their password, how (using the PDO method) do I make a function that will do this?

The same way as you made INSERT, just replace it with UPDATE

its that easy?

It’s more effort creating the link between email and site than it will be to change the password, as megazoid said, it’s just an UPDATE for that.

I’m trying to do it that way, heres my logic…
When the forgot passweord link is clicked and the user fills out their username, they are either sent an email or see a "hat email doesn’t exist message

$result = mysql_query("SELECT username FROM users WHERE username = ".$_POST['username']);
if(mysql_num_rows($result) == 0) {
	echo "Email is not recognized";	
} else {
  // the message
  $msg = "You are recieving this email because you requested your password to be reset, if you didn't just ignore this email.\nFollow the link below to reset your password.\n\n";
  $msg .= "<a href='http://www.dficorp.net/update_password.php?email={$_POST['username']}'>Reset password</a>\n\nThank you";
  
  // use wordwrap() if lines are longer than 70 characters
  $msg = wordwrap($msg,70);
  
  //sent HTMl
  $headers = "MIME-Version: 1.0" . "\r\n";
  $headers .= "Content-type:text/html;charset=UTF-8" . "\r\n";
  
  // send email
  mail($_POST['username'],"PASSWORD RESET",$msg,$headers);		
  
}	

then, if they get the email, they go to this page

<?php 
include_once("db/config.php");
?>

<?php if( (isset( $_GET['email'] ) ) ) { ?>
HTML
....
<?php 
} else {
$usr = new Users;
$usr->storeFormValues( $_POST );

if( $usr->updatePassword() ) {
  header( "location: password_updateed.php");
  exit();
} else {
  header("location: denied.html");
  exit();
}
}
?>

and the function…

 public function updatePassword() {
	$correct = false;
		try {
			$con = new PDO( DB_DSN, DB_USERNAME, DB_PASSWORD );
			$con->setAttribute( PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION );
			$sql = "UPDATE USERS SET password = :password WHERE username = :username";
			
			$stmt = $con->prepare( $sql );
			$stmt->bindValue( "username", $this->username, PDO::PARAM_STR );
			$stmt->bindValue( "password", hash("sha256", $this->password . $this->salt), PDO::PARAM_STR );
			$stmt->execute();
			return "Password Reset";
		}catch( PDOException $e ) {
			return $e->getMessage();
		}
 }

Am I on the right track?

K, well first let me blow up the track a bit.

Do not display a “that email doesn’t exist” message.

Doing that just opens the door for someone to start figuring out who’s registered on your site by hitting it repeatedly with every email they can program until they make a hit.

The standard would be, no matter what email is put in (since apparently email = username?) , to display a message that says “If there is a password associated with this account, an email has been sent to reset your password.” or whatever flowery language you want.

That way, the bots never know if they’ve made a hit. (You’ll see why this can be a VERY bad thing later in the post.)

Now. As to what do actually do;

The steps are: (It’s a 3 phase process)

Check for valid email.
If Valid:
Set updatetoken field for user to SomeRandomBigLongStringThatIsHexedOrSomethingLikeThat.
Send email to user with link to update_password.php?token=BigLongTokenThatWeGeneratedBefore
Display Thank You message.

When user goes to link:

Check for valid token.
If Valid:
Prompt user for new password. Pass token in as hidden form variable (or post back to same URL, works also)

When Form Data Received With Token:
Check for valid token.
If Valid:
Erase updatetoken field for user, set new password using hashing algorithm.

Why require a token? In your current code, i can go to update_password.php?email=TheEmail@IJustHacked (hey, remember that bot hit i got earlier?) and change someone’s password, even if they didnt REQUEST a password reset.

That sounds like a great way to do this, but im a little overwhelmed/confused on how to get this done Out of the three steps, im already stuck on the first, heres what I have

<?php 
include_once("db/config.php");
?>
HTML CODE
...
<?php if( !(isset( $_POST['username'] ) ) ) { ?>
	<p class="first" align="center">Please use this form to reset your password.</p>
	<form method="post" action="" style="box-shadow:none; margin:0 auto 100px; width:400px;">
	    <fieldset>
	    	<div class="leftForm" style="width:40%">
	        	<input type="email" name="username" id="username" maxlength="30" size="40" placeholder="Email" required>       	
	        </div>
<br clear="all">
	        <input id="submit" type="submit" name="register" value="Reset Paswword" style="width:40%">
	    </fieldset>
	</form>
<?php 
} else {

  echo "<br><br><br><br><p class='first' align='center'>If there is a password associated with this account, an email has been sent to reset your password.</p><br><br><br><br><br><br><br><br>";
  // the message
  $msg = "<p:>You are recieving this email because you requested your password to be reset, if you didn't just ignore this email.<br>Follow the link below to reset your password.</p>";
  $msg .= "<p><a href='http://www.dficorp.net/update_password.php?email={$_POST['username']}'>Reset password</a><br>Thank you</p>";
  
  // use wordwrap() if lines are longer than 70 characters
  $msg = wordwrap($msg,70);
  
  //sent HTMl
  $headers = "MIME-Version: 1.0" . "\r\n";
  $headers .= "Content-type:text/html;charset=UTF-8" . "\r\n";
  
  // send email
  mail($_POST['username'],"PASSWORD RESET",$msg,$headers);		
  
}
?>
HTML CODE
....

which seems pretty straightforward, except how do I generate the unique token so that I use that instead of the email to plug that hole?

Well, there’s a few different ways to just out and out get a unique string - the one recommended in the manual is a PHP function designed… specifically for doing this.

http://php.net/manual/en/function.openssl-random-pseudo-bytes.php

(the function name is being shortened to random_bytes in PHP 7)

This topic was automatically closed 91 days after the last reply. New replies are no longer allowed.