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

Php 在数据库中存储时使用MD5和密码哈希函数,php,encryption,pdo,hash,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);

如果我有用于登录系统的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($\u POST['user\u pass'])
验证用户输入的文本是否等于
MD5
hash

  • 现在我的问题是,我应该像在这个脚本中使用的那样使用
    password\u hash
    password\u verify
    ?或者使用
    MD5
    就足够了

  • 我的第二个问题是,我可以使用散列字符串结果在数据库中保存密码,还是可以使用md5


  • 是的,您应该立即迁移到新的API,并且不再为此目的使用MD5


    如果您没有使用
    password\u hash()
    /
    password\u verify()
    并希望:

  • 在用户帐户表中添加一列,名为
    legacy\u password
    (或等效项)
  • 计算现有MD5哈希值的bcrypt哈希值,并将其存储在数据库中(将
    legacy\u password
    设置为
    TRUE
  • 修改身份验证代码以处理旧标志
  • 当用户尝试登录时,首先检查是否设置了
    legacy\u 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)

    上面的示例代码在flavor中也可用



    此外,这与此无关。

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


    如果您没有使用
    password\u hash()
    /
    password\u verify()
    并希望:

  • 在用户帐户表中添加一列,名为
    legacy\u password
    (或等效项)
  • 计算现有MD5哈希值的bcrypt哈希值,并将其存储在数据库中(将
    legacy\u password
    设置为
    TRUE
  • 修改身份验证代码以处理旧标志
  • 当用户尝试登录时,首先检查是否设置了
    legacy_password
    标志。如果设置了,首先使用MD5对其密码进行预哈希,然后使用此预哈希值代替其密码。然后,重新计算bcrypt哈希并将新哈希存储在数据库中,在此过程中禁用
    legacy_password
    标志。aPHP 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)

    上面的示例代码在flavor中也可用



    另外,这与此无关。

    不要使用MD5。这是一个陈旧而脆弱的散列。但当我使用脚本中的密码散列部分时,这是正确的?为什么你否决了我?所以你使用密码散列,但问是否可以改为使用MD5。这个问题对我来说毫无意义。不,如果你真的需要答案。如果你尝试使用密码散列很有可能你最终会让它变得更加不安全。(尽管每个人都会本能地对此投反对票,但这是一个关于密码哈希迁移的问题。他们已经知道不要使用MD5。)不要使用MD5,这是一个古老而脆弱的散列。但是当我使用脚本中的密码散列部分时,它是正确的?为什么你否决了我?所以你使用密码散列,但问是否可以使用MD5。这个问题对我来说毫无意义。不,如果你真的需要答案。如果你尝试使用一个组合,很可能你最终会成功r不太安全。(尽管每个人都会本能地对此投反对票,但这是一个关于密码散列迁移的问题。他们已经知道不要使用MD5。)