使用 password_hash 來雜湊密碼

zhangbao發表於2017-07-03

使用

PHP 5.5 時引入一個給密碼加密的方法,叫 password_hash。它的使用方法如下:

$passwordHash = password_hash('123456', PASSWORD_BCRYPT);

// to do with $passwordHash ...

不可逆

上面的操作是將明文密碼 123456 使用 CRYPT_BLOWFISH 演算法處理成一個由 60 個字元組成的字串,類似 $2y$10$3qI4IKS6XOiisBDTTgp17eruMdcd3dDJaqaB6pQkEHR0Uk7od2A1a,這稱之為「雜湊值」。

經過 password_hash 方法加密得到的雜湊值有個特點:不可逆——不能從這個雜湊值反推出明文密碼(也就是之前的 123456)。你可能傲嬌了,心想我就知道你密碼設定不復雜,直接用 password_hash('123456', PASSWORD_BCRYPT) 得到雜湊值,再細心的和 $2y$10$3qI4IKS6XOiisBDTTgp17eruMdcd3dDJaqaB6pQkEHR0Uk7od2A1a 比對,發現一樣,不就 OK 了……這也行不通,因為每次執行 password_hash('123456', PASSWORD_BCRYPT) 語句後,得到雜湊值都不一樣

鹽值

這是因為 password_hash 再給密碼做雜湊之前,會先加入一個隨機子串,因為加入的隨機子串每次是不一樣的,所以得到的雜湊值自然就不一樣了。這就讓在不同的服務中使用同一個密碼的使用者,他的密碼的安全性變高了。

這個隨機子串就叫「鹽值」,加入鹽值的過程就是「加鹽處理」。

password_verify

password_hash 加密的密碼,可以用 password_verify 方法驗證。

<?php
// $hash 值從 `password_hash()` 方法得到 
$hash = '$2y$07$BCryptRequires22Chrcte/VlQH0piJtjXl.0t1XkA8pw9dMXTpOq';

if (password_verify('rasmuslerdorf', $hash)) {
    echo 'Password is valid!';
} else {
    echo 'Invalid password.';
}
?>

在做使用者更新密碼功能時,驗證舊密碼就是用 password_verify 方法。

Laravel 中的應用

Laravel 中的密碼儲存、驗證就是使用 password_hashpassword_verify 方法,不過對它們做了封裝。加密密碼用 bcryptHash::make,驗證密碼用 Hash::check。下面是它們封裝原生方法的地方:

  1. bcryptHash::make 方法底層指向的都是同一個方法 make
// see: \Illuminate\Hashing\BcryptHasher
public function make($value, array $options = [])
{
    $hash = password_hash($value, PASSWORD_BCRYPT, [
        'cost' => $this->cost($options),
    ]);

    if ($hash === false) {
        throw new RuntimeException('Bcrypt hashing not supported.');
    }

    return $hash;
}
  1. Hash::check 實現形式如下:
/**
 * Check the given plain value against a hash.
 *
 * @param  string  $value
 * @param  string  $hashedValue
 * @param  array   $options
 * @return bool
 */
public function check($value, $hashedValue, array $options = [])
{
    if (strlen($hashedValue) === 0) {
        return false;
    }

    return password_verify($value, $hashedValue);
}
本作品採用《CC 協議》,轉載必須註明作者和本文連結

相關文章