【问题标题】:Using MD5 and Password hash function when storing in database在数据库中存储时使用 MD5 和密码哈希函数
【发布时间】:2016-04-21 07:58:59
【问题描述】:

如果我有这个用于登录系统的 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 哈希。

  1. 现在我的问题是我应该像在这个脚本中使用的那样使用password_hashpassword_verify 吗?还是使用MD5 就足够了?

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

【问题讨论】:

  • 不要使用 MD5,它是一个旧的弱哈希。
  • 但是当我使用脚本的 password_hash 部分时它是正确的吗?为什么你对我投了反对票?
  • 所以您正在使用 password_hash 但询问是否可以使用 md5 代替。这个问题对我来说毫无意义。不,如果你真的需要答案。
  • 如果你尝试使用一个组合,你最终会得到远更少的安全性。
  • (尽管每个人都有条件投反对票,但这是一个关于密码哈希迁移的问题。他们已经知道不要使用MD5。)

标签: php encryption pdo hash


【解决方案1】:

是的,您应该立即迁移到新的 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. 修改您的身份验证代码以处理旧标志。

当用户尝试登录时,首先检查是否设置了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无关。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-01-30
    • 2020-05-13
    • 1970-01-01
    • 2012-11-25
    • 1970-01-01
    • 1970-01-01
    • 2019-03-17
    • 2011-06-10
    相关资源
    最近更新 更多