PHP中的密码恢复过期时间
我正在为我正在开发的网站编写一个简单的密码恢复功能,我想知道过期时间 说到这里,我想为我要发送的重置密码链接添加大约48小时的过期时间。我是否必须创建一个新列来存储当前时间,并在稍后检查它是否仍然有效,或者是否有更简单的方法 这是我目前的代码:PHP中的密码恢复过期时间,php,password-recovery,Php,Password Recovery,我正在为我正在开发的网站编写一个简单的密码恢复功能,我想知道过期时间 说到这里,我想为我要发送的重置密码链接添加大约48小时的过期时间。我是否必须创建一个新列来存储当前时间,并在稍后检查它是否仍然有效,或者是否有更简单的方法 这是我目前的代码: public function forgotPass($email) { $bd = new Bd(); $conn = $bd->connect(); $stt = $conn->prepare("SELECT *
public function forgotPass($email) {
$bd = new Bd();
$conn = $bd->connect();
$stt = $conn->prepare("SELECT * FROM Users where email=?");
$stt-> bind_param("s",$email);
$stt-> execute();
$result = $stt->get_result();
if (mysqli_num_rows($result) == 1) {
$stt = $conn->prepare("INSERT INTO Users(recovery) VALUES(?)");
$recovery = $this->randHash(8);
if (!$recovery)
return false;
$stt-> bind_param("s",$recovery);
$stt-> execute();
}
}
这是我的randHash
代码:
private static function randHash($lenght) {
if (!filter_var($lenght, FILTER_VALIDATE_INT)) {
return false;
}
$allowed = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
$max = strlen($allowed) - 1;
for ($i=1;$i<=$lenght;$i++) {
$hash .= $allowed[mt_rand(0, $max)];
}
return $hash;
}
私有静态函数randHash($lenght){
如果(!filter\u var($lenght,filter\u VALIDATE\u INT)){
返回false;
}
$allowed=“0123456789abcdefghijklmnopqrstuvxyzabcdefghijklmnopqrstuvxyz”;
$max=strlen($allowed)-1;
对于($i=1;$i只需将过期时间与重置令牌一起保存在数据库中,当时间过期时,不再接受重置令牌。这是迄今为止最简单、最安全的方法
另一种方法是创建重置散列,附加时间,并使用密钥加密。在检查散列时解密并检查时间戳。但是,如果密钥泄漏,此方法变得像将其以纯文本形式放入URL一样弱。将当前日期存储在数据库中是一种方法。然后,您可以轻松地检查如果休息时间少于48小时,另一种方法是在电子邮件中加入时间
public function forgotPass($email) {
$bd = new Bd();
$conn = $bd->connect();
$stt = $conn->prepare("SELECT * FROM Users where email=?");
$stt-> bind_param("s",$email);
$stt-> execute();
$result = $stt->get_result();
if (mysqli_num_rows($result) == 1) {
$hash1 = md5(microtime().$email.'xx'); //create a unique number for email
$ctime = time();
$hash2 = md5($hash1.$ctime); //create a unique hash based on hash1 and time
$stt = $conn->prepare("INSERT INTO Users(recovery) VALUES(?)");
$recovery = $hash2;
if (!$recovery)
return false;
$stt-> bind_param("s",$recovery);
$stt-> execute();
//send email with link
// http://www.example.com/resetpass.php?hash=$hash1&time=$ctime
}
}
//and then in resetpass.php
//NEEDS CHECKS FOR VALID QUERYVALUES
if (time()-$_GET['time'] <= 48 * 60 * 60) {
$checkhash = md5($_GET['hash'].$_GET['time']);
//check database for hash
}
放弃通行证的公共功能($email){
$bd=新bd();
$conn=$bd->connect();
$stt=$conn->prepare(“从电子邮件=?”的用户中选择*”;
$stt->bind_参数(“s”,$email);
$stt->execute();
$result=$stt->get_result();
if(mysqli_num_rows($result)==1){
$hash1=md5(microtime().$email.xx');//为电子邮件创建一个唯一的号码
$ctime=时间();
$hash2=md5($hash1.$ctime);//基于hash1和时间创建唯一的哈希
$stt=$conn->prepare(“插入用户(恢复)值(?);
$recovery=$hash2;
如果(!$recovery)
返回false;
$stt->bind_参数(“s”,$recovery);
$stt->execute();
//发送带有链接的电子邮件
// http://www.example.com/resetpass.php?hash=$hash1&time=$ctime
}
}
//然后在resetpass.php中
//需要检查有效的查询值
if(time()-$\u GET['time']编辑:我今天早上收到一封关于这个答案的电子邮件,询问我答案的哈希部分是否只是为了制作一个真正唯一的ID。以下是我的回答:
我仔细阅读并重新阅读了关于堆栈溢出的问题。该代码不仅用于生成真正唯一的ID(尽管没有冲突很重要)。它还使其他人很难编写自己的密码恢复链接来访问用户帐户
通过创建一个包含用户名和电子邮件的散列(并且不散列整个代码),我们可以对用户的身份进行额外的验证。也就是说,仅仅拥有链接是不够的;还需要一个有效的用户名和电子邮件地址组合来重置密码
在用户名、当前时间和电子邮件前面加上字符串,基本上是为了击败rainbow表。现在回想起来,最好分别用base64_编码($row['username'])和base64_编码($email)替换“”salt
我建议创建两列:recovery和recovery\u expiry。recovery\u expiry在链接过期时有效,recovery保留必须比较的哈希值。它由用户名、当前时间附加的salt和用户的当前电子邮件地址组成
function forgotPass($email)
{
$currTime = time();
$expiryTime = 60 * 60 * 24 * 2; // Two days
$bd = new Bd();
$conn = $bd->connect();
$stt = $conn->prepare("SELECT * FROM Users where email=?");
$stt->bind_param("s", $email);
$stt->execute();
$result = $stt->get_result();
if (mysqli_num_rows($result) == 1)
{
$row = mysqli_fetch_array();
$stt = $conn->prepare("INSERT INTO Users(recovery, recovery_expiry)"
. " VALUES(?,?)");
$hash = hash("sha256", " " . $row['username'])
. hash("sha256", "vivid" . $currTime)
. hash("sha256", " " . $email);
$stt->bind_param("s", $hash);
$stt->bind_param("i", $currTime + $expiryTime);
$stt->execute();
}
else
{
// Return that the given email address did not match any records
}
// Here would be the logic to send the forgotten password link to the user
}
function checkHash($hash)
{
$row = null;
$currTime = time();
$bd = new Bd();
$conn = $bd->connect();
$stt = $conn->prepare("SELECT * FROM Users WHERE recovery=? AND recovery_expiry < $currTime");
$stt->bind_param("s", $hash);
$stt->execute();
$result = $stt->get_result();
if (mysqli_num_rows($result) == 1)
{
$row = mysqli_fetch_array();
}
return $row;
}
放弃通行证功能($email)
{
$currTime=time();
$expiryTime=60*60*24*2;//两天
$bd=新bd();
$conn=$bd->connect();
$stt=$conn->prepare(“从电子邮件=?”的用户中选择*”;
$stt->bind_参数(“s”,$email);
$stt->execute();
$result=$stt->get_result();
if(mysqli_num_rows($result)==1)
{
$row=mysqli_fetch_array();
$stt=$conn->prepare(“插入到用户中(恢复、恢复和到期)”
“价值(?,)”;
$hash=hash(“sha256”,即“.$row['username']))
.hash(“sha256”,“生动”。$currTime)
.hash(“sha256”和“.$email”);
$stt->bind_参数(“s”,$hash);
$stt->bind_参数(“i”,$currTime+$expiryTime);
$stt->execute();
}
其他的
{
//返回给定的电子邮件地址与任何记录不匹配
}
//下面是将忘记的密码链接发送给用户的逻辑
}
函数checkHash($hash)
{
$row=null;
$currTime=time();
$bd=新bd();
$conn=$bd->connect();
$stt=$conn->prepare(“从恢复=?和恢复到期<$currTime的用户中选择*);
$stt->bind_参数(“s”,$hash);
$stt->execute();
$result=$stt->get_result();
if(mysqli_num_rows($result)==1)
{
$row=mysqli_fetch_array();
}
返回$row;
}
您可以在链接中包含发出请求的时间戳。然后,在处理密码恢复链接时,只需选中abs(time()-$request\u time)@Pateman提供的保护非常非常少。任何人都可以编辑that@ThomWiggers,没错,但这是最简单的方法,因为他想避免在数据库中存储过期时间。唯一简单的方法是什么都不做Pateman,这同样安全:)“如果密钥泄漏”是的,很明显,但是密钥就像密码一样。如果泄露数据库密码,所有安全性都会失败。没有理由不使用它。