密码散列流-特别是重置密码


Password hash flow - especially reset password

我正在更新我在我的网站上存储密码的方式,并想分享我的想法,以确保我做的正确:

首先,用户将选择一个我将散列的密码:

function generateHash($password) {
    if (defined("CRYPT_BLOWFISH") && CRYPT_BLOWFISH) {
        $salt = '$2y$11$' . substr(md5(uniqid(rand(), true)), 0, 22);
        return crypt($password, $salt);
    }
}
$passToStore = generateHash($userPassword);

然后我将把它存储在一个纯粹用于密码的表中,从users表中自动生成的userId作为键:

userId INT
hashedPassword VARCHAR(22)
forgottenHash VARCHAR(36)

当用户返回并尝试登录时,我将从他们输入的电子邮件(用户名)中提取连接选择查询中的密码。然后检查是否匹配他们输入的内容:

function verify($passwordEntered, $hashedPasswordStored) {
    return crypt($passwordEntered, $hashedPasswordStored) == $hashedPassword;
}

如果用户忘记了他们的密码,他们输入他们的电子邮件地址,我会生成一个随机哈希,并使其唯一添加strtotime当前时间/日期(进入forgottenHash),然后发送一个链接,让他们点击他们的电子邮件和随机哈希作为密钥和URL。

如果他们点击链接并且哈希值与该电子邮件地址的用户匹配,我将删除存储的哈希密码,并让他们创建一个新的密码。我很担心重置密码的过程,但对我来说似乎是正确的。但我不是黑客。

这是管理密码的好方法还是有更好的方法?

正如其他人在评论中已经提到的那样,有一些函数可以执行哈希。它们还会为你生成安全的盐:

// Hash a new password for storing in the database.
// The function automatically generates a cryptographically safe salt.
$hashToStoreInDb = password_hash($password, PASSWORD_BCRYPT);
// Check if the hash of the entered login password, matches the stored hash.
// The salt and the cost factor will be extracted from $existingHashFromDb.
$isPasswordCorrect = password_verify($password, $existingHashFromDb);

忘记密码功能应该按照您的建议做得稍微不同。虽然密码散列通常存储在"users"表中,但您应该为密码重置创建一个单独的表。当用户请求时,生成一个不来自其他用户数据的随机令牌,并将其散列与用户id一起存储在新表中。您发送给用户的令牌本身。如果用户单击带有令牌的链接,那么您可以再次计算该令牌的散列并在表中搜索它,如果它匹配,则允许用户更改密码。