在現代Web 應用開發中,用戶密碼的安全存儲至關重要。 PHP 提供了多種密碼加密手段,其中crypt()函數是一個靈活且強大的加密工具。本文將介紹如何使用PHP 的crypt()函數安全地加密和驗證用戶密碼,並說明如何避免常見的安全陷阱。
crypt()是一個密碼哈希函數,支持多種加密算法,具體算法取決於你傳入的“鹽”(salt)。不同算法有不同的鹽格式,如SHA-256 、 SHA-512等。合理使用crypt()可以生成強壯的密碼哈希,增加破解難度。
string crypt(string $password, string $salt);
$password是用戶輸入的明文密碼。
$salt用於指定加密算法及隨機鹽值,確保每次加密結果不同。
鹽的作用是防止彩虹表攻擊,每個密碼都應該有唯一的鹽值。對於現代算法,鹽應包含算法標識、迭代次數和隨機字符。
以下示例生成一個基於SHA-512 算法的鹽:
function generateSalt($length = 16) {
$randomBytes = random_bytes($length);
return '$6$rounds=5000$' . substr(strtr(base64_encode($randomBytes), '+', '.'), 0, 16) . '$';
}
$6$表示使用SHA-512。
rounds=5000控制哈希迭代次數,越大越安全但越耗時。
隨機字符串確保鹽的唯一性。
結合上面生成的鹽,可以這樣加密密碼:
$password = 'user_password_here';
$salt = generateSalt();
$hash = crypt($password, $salt);
$hash就是存儲到數據庫中的密碼哈希字符串。
驗證時,不能直接比較密碼和哈希,而是用用戶輸入密碼調用crypt() ,傳入存儲的哈希作為鹽,函數會自動提取鹽並加密輸入密碼:
function verifyPassword($inputPassword, $storedHash) {
$hash = crypt($inputPassword, $storedHash);
return hash_equals($hash, $storedHash);
}
使用hash_equals()是為了防止時序攻擊,確保比較安全。
<?php
// 生成鹽函數
function generateSalt($length = 16) {
$randomBytes = random_bytes($length);
return '$6$rounds=5000$' . substr(strtr(base64_encode($randomBytes), '+', '.'), 0, 16) . '$';
}
// 註冊時密碼加密
function encryptPassword($password) {
$salt = generateSalt();
return crypt($password, $salt);
}
// 登錄時驗證密碼
function verifyPassword($inputPassword, $storedHash) {
$hash = crypt($inputPassword, $storedHash);
return hash_equals($hash, $storedHash);
}
// 示例
$userPassword = 'MySecurePass123';
$storedHash = encryptPassword($userPassword);
echo "加密後的哈希: " . $storedHash . "\n";
$inputPassword = 'MySecurePass123';
if (verifyPassword($inputPassword, $storedHash)) {
echo "密碼驗證成功!";
} else {
echo "密碼錯誤!";
}
?>
盡量使用PHP 7.2+ 的password_hash()和password_verify() ,它們封裝了更現代和安全的算法,但如果因特殊原因必須使用crypt() ,請參考以上方法。
定期更新密碼哈希策略,增加迭代次數。
數據庫中存儲的哈希字符串即包含鹽和算法信息,無需單獨存儲鹽。