在数据库中存储时使用MD5和密码哈希函数

时间:2016-04-21 07:58:59

标签: php encryption pdo hash

如果我有一个用于登录系统的PHP脚本:

    $user = $_POST['user_name'];
    $pass = md5($_POST['user_pass']);

    require_once("connection_file.php");
    $sql = "SELECT * FROM login_table WHERE user_n = :us AND user_p = :password";
    $stmt = $conn->prepare($sql);
    $stmt->bindValue(':us', $user, PDO::PARAM_STR);
    $stmt->bindValue(':password', $pass, PDO::PARAM_STR);
    $stmt->execute();
    $result = $stmt->fetchAll();
    if($result)
    {
        //echo $msg = "user exist";
        if(session_status() == PHP_SESSION_NONE)
        {
            session_start();
            foreach($result as $row)
            {
                $hash = password_hash($row['user_pass'], PASSWORD_BCRYPT);
                if(password_verify($row['user_pass'], $hash))
                {
                    $_SESSION['userid'] = $row['user_id'];
                    $_SESSION['role'] = $row['user_role'];
                    header("Location: homepage.php");
                }
            } 
        }
    }
    else
    {
        $msg = "Wrong credentials";
        header("Location: login_page.php");
    }

如您所见,我已将密码保存在数据库MD5中,并且我使用$pass = md5($_POST['user_pass']);来验证用户输入的文本是否等于MD5哈希。< / p>

  1. 现在我的问题是我应该使用password_hashpassword_verify,因为我在这个脚本中使用了吗?或者使用MD5就足够了?

  2. 我的第二个问题是我可以使用哈希字符串结果在数据库中保存密码,还是可以使用md5密码?

1 个答案:

答案 0 :(得分:3)

是的,您应该立即迁移到新API并且永远不再使用MD5用于此目的。

如果您未使用password_hash() / password_verify()并希望migrate your code to a more secure method, seamlessly

  1. 在您的用户帐户表中添加一列,名为legacy_password(或等效的)。
  2. 计算现有MD5哈希值的bcrypt哈希并将其存储在数据库中(将legacy_password设置为TRUE)。
  3. 修改您的身份验证代码以处理旧标志。
  4. 当用户尝试登录时,首先检查是否设置了legacy_password标志。如果是,首先使用MD5预先哈希其密码,然后使用此预先设置的值代替其密码。然后,重新计算 bcrypt哈希并将新哈希存储在数据库中,从而禁用进程中的legacy_password标志。 PHP 7+中一个非常宽松的例子如下:

    /**
     * This is example code. Please feel free to use it for reference but don't just copy/paste it.
     *
     * @param string $username Unsafe user-supplied data: The username
     * @param string $password Unsafe user-supplied data: The password
     * @return int The primary key for that user account
     * @throws InvalidUserCredentialsException
     */
    public function authenticate(string $username, string $password): int
    {
        // Database lookup
        $stmt = $this->db->prepare("SELECT userid, passwordhash, legacy_password FROM user_accounts WHERE username = ?");
        $stmt->execute([$username]);
        $stored = $stmt->fetch(PDO::FETCH_ASSOC);
        if (!$stored) {
            // No such user, throw an exception
            throw new InvalidUserCredentialsException();
        }
        if ($stored['legacy_password']) {
            // This is the legacy password upgrade code
            if (password_verify(md5($password), $stored['passwordhash'])) {
                $newhash = password_hash($password, PASSWORD_DEFAULT);
                $stmt = $this->db->prepare("UPDATE user_accounts SET passwordhash = ?, legacy_password = FALSE WHERE userid = ?");
                $stmt->execute([$newhash, $stored['userid']]);
    
                // Return the user ID (integer)
                return $stored['userid'];
            }
        } elseif (password_verify($password, $stored['passwordhash'])) {
            // This is the general purpose upgrade code e.g. if a future version of PHP upgrades to Argon2
            if (password_needs_rehash($stored['passwordhash'], PASSWORD_DEFAULT)) {
                $newhash = password_hash($password, PASSWORD_DEFAULT);
                $stmt = $this->db->prepare("UPDATE user_accounts SET passwordhash = ? WHERE userid = ?");
                $stmt->execute([$newhash, $stored['userid']]);
            }
            // Return the user ID (integer)
            return $stored['userid'];
        }
        // When all else fails, throw an exception
        throw new InvalidUserCredentialsException();
    }
    

    用法:

    try {
        $userid = $this->authenticate($username, $password);
        // Update the session state
        // Redirect to the post-authentication landing page
    } catch (InvalidUserCredentialsException $e) {
        // Log the failure
        // Redirect to the login form
    }
    

    主动升级旧版哈希是对机会主义策略的安全胜利(当用户登录时重新散列,但在数据库中为不活动的用户留下不安全的哈希):采用主动策略,如果您的服务器在每个人登录之前受到攻击再次,他们的密码已经使用了可接受的算法(bcrypt,在示例代码中)。

    以上示例代码也可以Bcrypt-SHA-384风格。

    此外,这与encryption无关。