基本上,我正在尝试制作一个简单但安全的忘记密码脚本。
有两个脚本,一个允许用户输入其电子邮件地址。然后,这将向他们发送一封电子邮件,其中包含他们必须访问的链接以保存新密码。
第二个脚本是链接所在的位置。此脚本保存新密码。
出于安全考虑,我在我的数据库中创建了一个名为'token'的新表。它有三个领域;令牌,电子邮件,使用。令牌是随机生成的10个字母和数字的字符串,电子邮件只是用户的电子邮件地址,并且使用的是1或0的整数,表示令牌是否已被使用。
阅读完这两个脚本后,您将能够了解更多我的结构。它们不长,也不复杂。
出了什么问题
好的,所以只有一件小事出错了,这是在reset-password.php脚本中。这是用户收到电子邮件后来到的地方。基本上,我输入一个新密码,然后单击“重置密码”,但没有任何反应。没有显示任何错误或确认,也没有在我的数据库中发生任何变化。我似乎无法调试这个,现在已经搜索并尝试了几个小时。非常感谢所有的帮助和建议。
请尽量记住,我仍然是PHP和MySQL的新手。已经使用PHP大约8周了,MySQL只用了2个。
忘记-password.php
<?php
//Forgotten password script
//Variable to save errors
$errors = array();
$email = $_POST['email'];
include 'config.php';
mysql_connect("$db_host", "$db_username", "$db_password")or die("cannot connect");
mysql_select_db("$db_name")or die("cannot select DB");
$query = "SELECT email FROM users WHERE email='" . $email . "'";
$result = mysql_query($query);
$num = mysql_num_rows($result);
if($num==0)
{
echo ("<div style='color:red;'>Email address is not registered</div>");
die();
}
$token = getRandomString(10);
$query = "INSERT INTO tokens (token,email) VALUES ('".$token."','".$email."')";
mysql_query($query);
//function to renerate the token
function getRandomString($length)
{
$validCharacters = "ABCDEFGHIJKLMNPQRSTUXYVWZ123456789";
$validCharNumber = strlen($validCharacters);
$result = "";
for ($i = 0; $i < $length; $i++)
{
$index = mt_rand(0, $validCharNumber - 1);
$result .= $validCharacters[$index];
}
return $result;
}
//Send the reset link to the user
function mailresetlink($to,$token)
{
$subject = "Password Reset";
$message = '
<html>
<head>
<title>Password Reset</title>
</head>
<body>
<p>Click on the given link to reset your password <a href="http://domain.com/reset-password.php?token='.$token.'">Reset Password</a></p>
</body>
</html>
';
$headers = "MIME-Version: 1.0" . "\r\n";
$headers .= "Content-type:text/html;charset=iso-8859-1" . "\r\n";
$headers .= 'From: Password Reset <noreply@domain.com>' . "\r\n";
if(mail($to,$subject,$message,$headers))
{
echo "We have sent the password reset link to your email at <strong>".$to."</strong>";
}
}
//If email is posted, send the email
if(isset($_POST['email']))
{
mailresetlink($email,$token);
}
?>
<table align="center" style="padding-bottom:40px;">
<form action="<?php $_SERVER['PHP_SELF']; ?>" method="post">
<tr>
<td>Email Address: </td>
<td><input type="text" name="email" /></td>
</tr>
<tr>
<td colspan="2" align="center"><input type="submit" value="Reset My Password" /></td></tr>
<input type="hidden" name="register" value="TRUE" />
</form>
</table>
重置-password.php
<?php
//Reset password script
$token = $_GET['token'];
$email;
include 'config.php';
mysql_connect("$db_host", "$db_username", "$db_password") or die("cannot connect");
mysql_select_db("$db_name")or die("cannot select DB");
if(!isset($_POST['newpassword']))
{
$query = "SELECT email FROM tokens WHERE token='" . $token . "' AND used = 0";
$result = mysql_query($query);
while($row = mysql_fetch_array($result))
{
$email = $row['email'];
}
if ($email != '')
{
$_SESSION['email'] = $email;
}
else
{
echo "Invalid link or Password already changed";
}
}
$pass = $_POST['newpassword'];
$email = $_SESSION['email'];
//Save new password
if(isset($_POST['newpassword']) && isset($_SESSION['email']))
{
$query = "UPDATE users SET password = SHA('$password') WHERE email='" . $email . "'";
$result = mysql_query($query);
if($result)
{
mysql_query("UPDATE tokens SET used=1 WHERE token='" . $token . "'");
}
echo "Your password has been changed successfully";
if(!$result)
{
echo "An error occurred. Please try the again or contact us at admin@domain.com";
}
}
?>
<table align="center" style="padding-bottom:40px;">
<form action="<?php $_SERVER['PHP_SELF']; ?>" method="post">
<tr>
<td>New Password:</td>
<td><input type="password" name="newpassword" id="password"/></td>
</tr>
<tr>
<td colspan="2" align="center"><input type="submit" value="Change Password"></td></tr>
<input type="hidden" name="reset" value="TRUE" />
</form>
</table>
如果您需要更多信息或代码,请随时询问。
提前致谢!
答案 0 :(得分:5)
在输入新密码参数后,我没有看到您在重置页面上将令牌参数传递到服务器的任何位置。你应该有另一个隐藏的<input />
控件。 $_SERVER['PHP_SELF']
不返回查询字符串参数。这可能是您当前问题的原因。
具体来说,
<table align="center" style="padding-bottom:40px;">
<form action="<?php echo $_SERVER['PHP_SELF']; ?>" method="post">
<tr>
<td>New Password:</td>
<td><input type="password" name="newpassword" id="password"/></td>
</tr>
<tr>
<td colspan="2" align="center"><input type="submit" value="Change Password"></td></tr>
<input type="hidden" name="reset" value="TRUE" />
</form>
</table>
应该是
<table align="center" style="padding-bottom:40px;">
<form action="<?php echo $_SERVER['PHP_SELF']; ?>" method="post">
<tr>
<td>New Password:</td>
<td><input type="password" name="newpassword" id="password"/></td>
</tr>
<tr>
<td colspan="2" align="center"><input type="submit" value="Change Password"></td></tr>
<input type="hidden" name="reset" value="TRUE" />
<input type="hidden" name="token" value="<?php echo $_REQUEST['token']; ?>" />
</form>
</table>
确保您还将$_GET['token']
更改为$_REQUEST['token']
,因为它将是第一次获取,然后POST第二次。
话虽这么说,你更大的问题是我能够通过将' or 1=1 or '
指定为我的令牌来绕过所有安全性。或者,我可能是卑鄙的,做一个不错的'; update users set password = SHA('IKnowThisPassword') where username = 'admin'; --
故事的道德是参数化SQL(How can I prevent SQL injection in PHP?)