密码恢复在PHP中过期

时间:2012-12-06 12:45:45

标签: php password-recovery

我正在为我正在开发的网站编写一个简单的密码恢复功能,我想知道过期时间。

说实话,我想为我要发送的重置密码链接添加大约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) {
        $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;
}

3 个答案:

答案 0 :(得分:2)

只需使用数据库中的重置令牌保存到期时间,并且当时间到期时,不再接受重置令牌。这是迄今为止最简单,最安全的方法。

另一种方法是创建重置哈希,追加时间,并使用密钥加密。检查哈希值时解密并检查时间戳。但是,如果密钥泄露,则此方法变得像在URL中以纯文本形式一样弱。

答案 1 :(得分:0)

将当前日期存储在数据库中是一种方法。然后你可以轻松检查它是否少于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
}

答案 2 :(得分:0)

编辑:我今天早上收到了一封关于这个答案的电子邮件,并询问我的答案的散列部分是否只是为了制作一个真正独特的ID。以下是我的回复:

我经历了重新阅读Stack Overflow上的问题。代码不仅仅是用于创建一个真正唯一的ID(尽管重要的是没有冲突)。此外,其他人也很难编写自己的密码恢复链接来访问用户帐户。

通过使用用户名和电子邮件创建哈希(并且不对整个代码进行哈希处理),我们可以对用户的身份进行额外的验证。也就是说,仅仅拥有链接是不够的;重置密码也需要有效的用户名和电子邮件地址组合。

字符串被添加到用户名,当前时间和电子邮件中,以基本尝试击败彩虹表。回想起来,最好分别用base64_encode($ row ['username'])和base64_encode($ email)替换“”盐。


我建议创建两列:recovery和recovery_expiry。当链接到期时,Recovery_expiry成立,并且恢复保存必须比较的哈希。它由用户名,当前时间附加的盐以及用户的当前电子邮件地址组成。

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;
}