在数据库中存储时使用MD5和密码散列函数 [英] Using MD5 and Password hash function when storing in database

查看:230
本文介绍了在数据库中存储时使用MD5和密码散列函数的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

If I have this PHP script for a login system:

    $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 哈希。

And as you see I am already saving my password in database as MD5 and I am using $pass = md5($_POST['user_pass']); to verify if the text input by the user is equal to MD5 hash.


  1. 现在我的问题是我在本脚本中使用的是 password_hash password_verify 或者使用 MD5 将足够?

而我的第二个问题是我可以使用哈希字符串结果或者可以使用md5吗?

And my second question is can I save passwords in database using the hash string result or it is okay to use the md5 one?


推荐答案

是的,您应该迁移到新的API,并且不要立即使用MD5。

Yes, you should migrate to the new API and never use MD5 for this purpose again, immediately.

不要使用 password_hash() / password_verify()并希望将您的代码无缝地迁移到更安全的方法

If you're not using password_hash()/password_verify() and want to migrate your code to a more secure method, seamlessly:


  1. 将一列添加到您的用户帐户表中,名为 legacy_password (或等价物)。

  2. 计算现有MD5哈希的的bcrypt哈希值,并将其存储在数据库中(将 legacy_password 设置为 TRUE )。

  3. 修改您的验证码以处理传统标志。

  1. Add a column to your user accounts table, called legacy_password (or equivalent).
  2. Calculate the bcrypt hash of the existing MD5 hashes and store them in the database (setting legacy_password to TRUE).
  3. Modify your authentication code to handle the legacy flag.

当用户尝试登录时,首先检查 legacy_password 标志设置。如果是,首先使用MD5预先加密密码,然后使用此预先设置的值代替其密码。之后,重新计算bcrypt哈希,并将新的哈希存储在数据库中,禁止进程中的 legacy_password 标志。 PHP 7+中的一个非常宽松的例子如下:

When a user attempts to login, first check if the legacy_password flag is set. If it is, first pre-hash their password with MD5, then use this prehashed value in place of their password. Afterwards, recalculate the bcrypt hash and store the new hash in the database, disabling the legacy_password flag in the process. A very loose example in PHP 7+ follows:

/**
 * 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,在示例代码中)

Proactively upgrading legacy hashes is a security win over an opportunistic strategy (rehashing when the user logs in, but leave the insecure hashes in the database for inactive users): With a proactive strategy, if your server gets compromised before everyone logs in again, their passwords are already using an acceptable algorithm (bcrypt, in the example code).

上面的示例代码也可以在 Bcrypt-SHA-384 味道。

The above example code is also available in Bcrypt-SHA-384 flavor.

此外,这无关紧要加密

这篇关于在数据库中存储时使用MD5和密码散列函数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆