1

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

言归正传,我想为我要发送的重置密码链接添加大约 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;
}
4

3 回答 3

3

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

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

于 2012-12-06T12:52:04.443 回答
0

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

我仔细阅读并重新阅读了 Stack Overflow 上的问题。该代码不仅用于制作真正唯一的 ID(尽管没有冲突很重要)。这也使其他人很难编写自己的密码恢复链接来访问用户帐户。

通过使用用户名和电子邮件创建散列(并且不散列整个代码),我们将能够包括对用户身份的额外验证。也就是说,仅仅拥有链接是不够的。重置密码也需要有效的用户名和电子邮件地址组合。

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


我建议创建两列:recovery 和 recovery_expiry。recovery_expiry 在链接过期时保存,recovery 保存必须比较的哈希。它由用户名、当前时间附加的盐和用户的当前电子邮件地址组成。

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;
}
于 2012-12-06T13:41:04.620 回答
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
}
于 2012-12-06T12:54:43.863 回答