在使用PHP 的crypt()函數進行密碼哈希處理時,鹽值(salt)的安全性直接影響到密碼存儲的安全。鹽值的作用是防止相同密碼產生相同的哈希值,從而有效抵禦彩虹表攻擊。因此,生成一個安全可靠的鹽值非常重要。
鹽值是一個隨機字符串,它會被附加到密碼上,然後進行哈希計算。一個好的鹽值需要具備以下特點:
唯一且隨機:每個密碼對應一個獨特的鹽值。
足夠長:避免鹽值被輕易猜到。
適合哈希算法:不同算法對鹽值長度和格式有要求。
crypt()支持多種加密算法,不同算法對鹽值格式有不同要求。常見算法及鹽值格式如下:
DES :鹽值長度為2 個字符。
MD5 :以$1$開頭,鹽值最多8 個字符,例如$1$abcdefgh$ 。
Blowfish :以$2a$或$2y$開頭,後跟兩位成本因子和22 個字符的鹽值,例如$2y$10$abcdefghijklmnopqrstuv 。
SHA-256 :以$5$開頭,後跟鹽值,最長16 個字符。
SHA-512 :以$6$開頭,後跟鹽值,最長16 個字符。
建議使用Blowfish( $2y$ )或SHA-512( $6$ )算法,因為它們更安全且支持較長鹽值。
生成鹽值的關鍵是使用安全的隨機數生成函數,並且遵守對應算法的鹽值格式要求。
示例代碼:
<?php
function generateSalt($algo = 'bcrypt') {
switch ($algo) {
case 'bcrypt':
// Blowfish 需要 22 個 Base64 字符,成本為 10
$cost = 10;
// 使用隨機字節,轉換成可用的字符集
$randomBytes = random_bytes(16);
$base64String = substr(strtr(base64_encode($randomBytes), '+', '.'), 0, 22);
return sprintf('$2y$%02d$%s', $cost, $base64String);
case 'sha512':
// SHA-512 允許最長16字符鹽
$randomBytes = random_bytes(12);
return '$6$' . substr(strtr(base64_encode($randomBytes), '+', '.'), 0, 16);
default:
throw new Exception("Unsupported algorithm");
}
}
// 使用示例
$password = 'user_password';
$salt = generateSalt('bcrypt');
$hash = crypt($password, $salt);
echo "鹽值:$salt\n";
echo "哈希值:$hash\n";
?>
上述代碼中:
random_bytes()用於生成安全的隨機字節。
base64_encode()編碼後替換+為.以符合鹽值格式要求。
Blowfish 使用成本因子10,既安全又性能合理。
生成的鹽值嚴格按照crypt()需要的格式。
PHP 7.2 及以上版本強烈建議使用內置的password_hash()函數,它自動處理鹽值生成和算法選擇,簡化且更安全:
<?php
$password = 'user_password';
$hash = password_hash($password, PASSWORD_BCRYPT);
echo $hash;
?>
如果你非要手動使用crypt() ,務必保證鹽值安全隨機且格式正確,否則容易導致哈希弱化。