使用
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_hash
和 password_verify
方法,不過對它們做了封裝。加密密碼用 bcrypt
和 Hash::make
,驗證密碼用 Hash::check
。下面是它們封裝原生方法的地方:
bcrypt
和Hash::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;
}
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 協議》,轉載必須註明作者和本文連結