PHP Passwort Vergessen Button

Zneaf

Erfahrenes Mitglied
Hey Leute =)

ich habe auf meiner Website einen "Passwort vergessen?" Button eingefügt.

Er funktioniert wie folgt:
Ein Benutzer gibt seine E-Mail-Adresse, seine Geheimfrage und seine Geheimantwort" ein. Sind die Angaben korrekt, wird ihm sein Passwort per Email zugeschickt.

Soweit so gut.

Ich habe dabei allerdings folgendes Problem:
Das Passwort wird bei der Registrierung des Benutzers verschlüsselt (md5) und daher wird ihm momentan das verschlüsselte Passwort zu gesandt....was natürlich nicht so sein sollte ;)

Hier der Code mit dem ich das Passwort aus der Datenbank auslesen lasse:
PHP:
// Die userspezifischen Daten werden ausgelesen und in Variablen gespeichert.
$user = mysql_fetch_object($res);
$password = $user->password;

Habt ihr vielleicht ne Ahnung, wie ich den Code abändern müsste, damit das Passwort entschlüsselt versendet wird?

Vielen Dank für Eure Mühen ;)

LG Zneaf =)
 
So ein verschlüsseltes Passwort lässt sich nicht wiederherstellen (-> Einwegverschlüsselung).
Aber auch wenn du es unverschlüsselt speichern würdest, würde ich nicht empfehlen das "alte" per Email zu schicken.

Bei fast allen Websites wird ein eindeutiger Link per Email gesendet, bei dem du dann ein neues Passwort eingeben kannst.
Also im Prinzip musst du eine zufällige ID für diese "Passwort vergessen"-Aktion generieren, diese irgendwo speichern und auch per Email zuschicken.
 
Hey ComFreek =)

erstmal vielen Dank für diese extrem schnelle Antwort :D

Also ich hab ungefähr verstanden, was du meinst....allerdings habe ich keine Ahnung, wie man soetwas umsetzt.

Bin halt ein Hobby-Programmierer ;)

Ich weiß...es ist viel Arbeit, aber hättest du vllt. nen Beispiel-Code und kannst mir das ganze etwas näher erklären? =)

Wäre echt super nett von dir :)

Vielen Dank im Voraus ;)

LG Zneaf =)
 
Bitte Zneaf ;)

Zuerst könntest du deiner Benutzertabelle in der DB eine neue Spalte hinzufügen, in die du im Falle die eindeutige ID zum Zurücksetzen speicherst:
Code:
username | .... | pw_reset_id

pw_reset_id VARCHAR(40)
Nachdem der Nutzer "Passwort vergessen" gedrückt hat und die Sicherheitsfrage richtig beantwortet hat, muss diese ID generiert werden, z.B. mit [phpf]sha1[/phpf] (erzeugt einen Hash mit 40 Zeichen):
PHP:
$id = sha1($username.time().rand(-3000,3000));

/* ID einfügen */
$sql = "UPDATE users SET pw_reset_id='".$id."' WHERE username='".$username."'";
mysql_query($sql);
Der Hash sollte so zufällig wie möglich sein!

So und in der Email schickst du eben einen Link zu einem PHP-Skript, welches eben die ID prüft und eine Eingabe eines neues Passwortes zulässt.
PHP:
$email = "............"

$email .= "http://www.example.org/reset-pw.php?username=".$username."&id=".$id;

Schließlich noch das Skript, welches hinter dem Link steckt, z.B.:
PHP:
$id = mysql_real_escape_string($_GET['id']);
$username = mysql_real_escape_string($_GET['username']);

$sql = "SELECT id FROM users WHERE username='".$username."' AND pw_reset_id='".$id."'";
$result = mysql_query($sql);

if (mysql_num_rows($result) > 0)
{
  /* Einblenden eines Formulares zum Ändern des Passwortes */
}
else
{
  /* Falsch! */
}

Das ist hier eine einfache Variante. Zusätzlich könntest (solltest) du noch ein Zeitlimit einbauen (zus. Spalte 'pw_reset_time' und Prüfung im letzten Skript).

Beachte außerdem, dass ich viele Prüfungen weggelassen habe (z.B. Benutzernamen vor MySQL-Query, Variableninhalte in URLs).
 
Zuletzt bearbeitet:
Hey ComFreek ;)

wow...hast dir ja ne Menge Arbeit gemacht =)

Vielen Dank erstmal dafür ;)

Das mit $email hab ich allerdings nicht ganz verstanden (hauptsächlich die erste Zeile).
Also der folgende Code:
PHP:
$email = "............"
$email .= "http://www.example.org/reset-pw.php?username=".$username."&id=".$id;
Sobald ich etwas Zeit habe (denke mal bis Wochenende oderso) werd ich etwas daran arbeiten und Rückmeldung geben, ob ichs hin gekriegt hab ;)

Es könnte also sein, dass ich noch weitere Fragen habe^^ (ist sogar sehr warscheinlich :D)

LG Zneaf =)
 
Das mit $email hab ich allerdings nicht ganz verstanden (hauptsächlich die erste Zeile).
Diese Variable soll einfach nur den Inhalt der zu verschickende Email beinhalten.
Du hast doch gesagt, dass du jetzt schon Emails mit MD5-Passwörtern geschickt hast, das ist genau das gleiche, nur mit einem Link.

Falls du die Punkte nicht verstehst, das könnte irgendein Text sein (z.B. "Lieber Kunde, ...").

Es könnte also sein, dass ich noch weitere Fragen habe (ist sogar sehr warscheinlich )
Einfach stellen, wenn du welche hast ;)
 
Hey ComFreek,

also hat etwas länger gedauert....sry.

Hab das jetzt mal ausprobiert. Also die erste Datei (pwforgotten.php) funktioniert einwandfrei.
Dort wird ja die pwresetid erzeugt und abgespeichert und eine Mail mit dem Link versendet.
Die zweite Datei (pwreset.php) funktioniert allerdings nicht so richtig^^

Hier mal die pwforgotten.php:

PHP:
<?php
// Überprüfen, ob das Formular abgeschickt wurde und ob alle Angaben gemacht wurden.
if( isset($_POST['username'], $_POST['email'], $_POST['gfrage'], $_POST['gantwort'])
    AND
		strcmp(trim($_POST['username']),'') != 0
	AND
		strcmp(trim($_POST['email']),'') != 0
	AND
		strcmp(trim($_POST['gfrage']),'') != 0
    AND
		strcmp(trim($_POST['gantwort']),'') != 0 ) {

	// Einbinden der Konfigurationsdatei.
	require_once 'config.php';

	// SQL-Anweisung an die Datenbank senden, um erstens herauszufinden, ob 
	// diese Kombination von Daten überhaupt existiert.
	$sql = "SELECT 
				username,
				email,
				gantwort,
				gfrage
			FROM         
				user
			WHERE
				username = '" . trim($_POST['username']) . "'
			AND
				email = '" . trim($_POST['email']) . "'
			AND
				gfrage = '" . trim($_POST['gfrage']) . "'
			AND
				gantwort = '" . trim($_POST['gantwort']) . "'";

			$res = mysql_query($sql) or die( 'Error[SELECT|User]: <br /><pre>' . $sql . '</pre><br />MySQL-Error: ' . mysql_error() );

			// Nur wenn genau ein Datensatz selektiert wurde, wird eine E-Mail an den User versendet.
			// Ansonsten wird ihm eine Fehlermeldung angezeigt.
			if( mysql_num_rows($res) != 1 ) {
				echo "<font face=\"Arial\" color=\"#333333\">Die angegebenen Benutzerdaten sind nicht korrekt!</font>";
				exit();
			}else{
				// Mail - From festlegen
				$from = "From: \n";
				$from .= "Reply-To: \n";
				$from .= "Cc: \n";
				$from .= "Bcc: \n";
				$from .= "X-Mailer: PHP/" . phpversion(). "\n";
				$from .= "X-Sender-IP: $REMOTE_ADDR\n";
				$from .= "Content-Type: text/html";

				// Benutzerdaten in Variablen speichern
				$username = $_POST['username'];
				$email = $_POST['email'];
				
				// ID erzeugen
				$id = sha1($username.time().rand(-3000,3000));

				// Einbinden der Konfigurationsdatei.
				require_once 'config.php';

				// ID einfügen
				$sql = 	"UPDATE user
						SET pw_reset_id='".$id."'
						WHERE username='".$username."'";

				$res = mysql_query($sql) or die( 'Error[SELECT|User]: <br /><pre>' . $sql . '</pre><br />MySQL-Error: ' . mysql_error() );
					
				// Mail - Daten zusammenfassen
				$nachricht = "<table border=\"0\" cellpadding=\"0\" cellspacing=\"2\">
								<table border=\"0\" cellpadding=\"0\" cellspacing=\"2\">
									<tr>
										<td><font face=\"Arial\" color=\"#333333\" size=\"+2\">Hallo <b>$username</b>,</font></td>
									</tr>
								</table>
							<br>
								<table border=\"0\" cellpadding=\"0\" cellspacing=\"2\">
									<tr>
										<td><font face=\"Arial\" color=\"#333333\">Verwende bitte den unten stehenden Link, um Dein Passwort ändern zu können.</font></td>
									</tr>
									<tr>
										<td><font face=\"Arial\" color=\"#333333\">pwreset.php?username='.$username.'&id='.$id;</td>
									</tr>
								</table>
							<br>
								<table border=\"0\" cellpadding=\"0\" cellspacing=\"2\">
									<tr>
										<td><font face=\"Arial\" color=\"#333333\">Viel Spaß wünscht Dir das Team von <a href=\"\"></a></font></td>
									</tr>
								</table>";

				//E - mail versenden
				mail("$email", "Passwort vergessen", "$nachricht", "$from");

				// Mail wurde versandt und der User bekommt eine Mitteilung angezeigt, in der er erfährt wie es weitergeht.
				echo "<font face=\"Arial\" color=\"#333333\">Du hast soeben eine Mail von uns erhalten, mit der Du Dein Passwort ändern kannst.</font>";
				exit();                                            
			}
}
?>

<!-- Eingabemaske -->
<form action="<?php $_SERVER['PHP_SELF']; ?>" method="post">
<table border="0" cellpadding="0" cellspacing="2">
	<tr>
		<td><font face="Arial" color="#333333">Username:</font></td>
	</tr>
	<tr>
		<td><input type="text" name="username" size="30" maxlength="30"></td>
	</tr>
	<tr>
		<td><font face="Arial" color="#333333">E - Mail:</font></td>
	</tr>
	<tr>
		<td><input type="text" name="email" size="30" maxlength="30"></td>
	</tr>
	<tr>
		<td><font face="Arial" color="#333333">Geheim - Frage:</font></td>
	</tr>
	<tr>
		<td><input type="text" name="gfrage" size="30" maxlength="50"></td>
	</tr>
	<tr>
		<td><font face="Arial" color="#333333">Geheim - Antwort:</font></td>
	</tr>
	<tr>
		<td><input type="password" name="gantwort" size="30" maxlength="30"></td>
	</tr>
	<tr>
		<td>&nbsp;</td>
	</tr>
	<tr>
		<td><input type="submit" name="submit" value="Absenden">&nbsp;<input type="reset" value="Abbrechen" name="reset"></td>
	</tr>
</table>
</form>

Hier mal die pwreset.php:
PHP:
<?php
$id = mysql_real_escape_string($_GET['id']);
$username = mysql_real_escape_string($_GET['username']);

require_once("config.php");

$sql = "SELECT id
		FROM user
		WHERE username='".$username."'
		AND pw_reset_id='".$id."'";
		
$res = mysql_query($sql) or die( 'Error[SELECT|User]: <br /><pre>' . $sql . '</pre><br />MySQL-Error: ' . mysql_error() );

if (mysql_num_rows($res) > 0){

?>

<center>
<form action="<?php $_SERVER['PHP_SELF']; ?>" method="post">
	<table border="0" width="500" cellpadding="0" cellspacing="2">
		<tr>
			<td><font face="Arial" color="#333333">Neues Passwort:</font></td>
		</tr>
		<tr>
			<td><input type="password" name="password1" size="30" maxlength="30"></td>
		</tr>
	</table>
<hr>
	<table border="0" width="500" cellpadding="0" cellspacing="2">
		<tr>
			<td><font face="Arial" color="#333333">Passwort wiederholen:</font></td>
		</tr>
		<tr>
			<td><input type="password" name="password2" size="30" maxlength="30"></td>
		</tr>
		<tr>
			<td>&nbsp;</td>
		</tr>
		<tr>
			<td><input type="submit" name="submit" value="Absenden">&nbsp;<input type="reset" value="Abbrechen" name="reset"></td>
		</tr>
	</table>
</form>
</center>

<?php
	// Daten auslesen
	$password1 = $_POST['password1'];
	$password2 = $_POST['password2'];
	$password = $password1;
	
	// SQL-Anweisung basteln, um Daten in die DB-Tabelle einzufügen.
	if ($password1 == "" or $password2 == "") {
		echo "<hr><center><font face=\"Arial\" color=\"#333333\"><b>Bitte trage Dein neues Passwort ein.</b></font></center><hr>";
	}else{
		if ($password1 != $password2) {
			require_once("config.php");
		
			$sql = "UPDATE user
					SET password=\"MD5('".$password."'),\"";

			// SQL-Anweisung an die DB schicken und im Fehlerfall eine Meldung ausgeben.
			$res = mysql_query($sql) or exit( __LINE__.', '.__FILE__.'<br />' .mysql_error());
		
			// Wenn kein Fehler aufgetreten ist auf die Startseite weiterleiten.
			echo "<meta http-equiv='refresh' content='0; url=index.php?site=home'>" ;
		}else{
			echo "<font face=\"Arial\" color=\"#333333\">Die angegebenen Passwörter sind nicht identisch!</font>";
		}
}else{
	echo "<font face=\"Arial\" color=\"#333333\">Die angegebenen Benutzerdaten sind nicht korrekt!</font>";
}
?>

Um das Problem genauer zu beschreiben: irgendwas stimmt mit dem link nicht.

Hast du vllt. ne Idee, wo der Wurm drin sein könnte?^^

Vielen Dank im Voraus =)

LG Zneaf
 
Mir tränen gleich die Augen vor lauter Suchen. Welchen Link meist du?

Was aussieht wie ein Link ist das hier "pwreset.php?username='.$username.'&id='.$id;"
Das sieht aber auch nur so aus weil ja die Domain sleber fehlt und das < a > -Tag ist auch nicht vorhanden.
 
Abgesehen von deinem momentanen Problem:
  • Der User muss die Geheim-Frage selbst eingeben? Also wenn ich für alle Webseiten, bei denen ich ein Account habe, nicht nur die Antwort sondern auch noch die Frage im Kopf haben müsste, dann Prost! Vielleicht erinnere ich mich gerade noch an "irgendwas mit dem Mädchennamen meiner Mutter", aber dann auf die korrekte Formulierung samt Interpunktion und Groß-/Kleinschreibung zu kommen ist schlicht unmöglich. Sprich: Dein direkter Stringvergleich in der SQL-Abfrage wird NIE zutreffen, da sich kein User die konkrete Frage merken kann, die er vor ewig langer Zeit bei dir angegeben hat.
  • Die benutzt die $_POST Variable direkt in deiner SQL-Abfrage, was SQL-Injections erlaubt. Du solltest vorher unbedingt soetwas wie mysql_real_escapte_string() anwenden.
 
Hallo,

wie tombe sagte, welchen Link meinst du? Und zeig mal bitte den Quelltext her, der generiert wird.

Außerdem habe ich einen Fehler entdeckt: Du vergleichst im SQL-Query einen Integer mit einer Zeichenkette:
PHP:
$sql = "SELECT id 
        FROM user 
        WHERE username='".$username."' 
        AND pw_reset_id='".$id."'";  /* hier */
Entferne mal die Anführungsstriche.
 
Zurück