在PHP中, crypt()函數是一個用於加密密碼的傳統方法,它支持多種加密算法,通過傳入不同格式的鹽值(salt)來啟用特定的加密機制。儘管近年來推薦使用更現代的密碼散列API(如password_hash() ),但在某些老系統中, crypt()依然被廣泛使用。因此,了解如何為crypt()函數選擇合適的算法和鹽值格式,是保障安全性與系統兼容性的關鍵。
crypt()函數通過鹽值的前綴識別所用的算法。以下是主流算法及其對應的鹽值格式:
DES(傳統算法)
鹽值格式: 2個字符(例如:"xy")
安全性:極低,已不推薦使用。
MD5
鹽值格式: $1$ + 最多8個字符(例如: $1$abc12345 )
安全性:弱,容易被暴力破解。
Blowfish
鹽值格式: $2y$ + 2位cost因子+ 22位base64編碼(例如: $2y$10$abcdefghijklmnopqrstuu )
安全性:高,廣泛使用。
兼容性:推薦使用$2y$而不是$2a$ ,因為$2y$修復了歷史上的安全問題。
SHA-256 和SHA-512(glibc)
鹽值格式:
SHA-256: $5$ + 可選rounds參數+ salt(例如: $5$rounds=5000$mysaltvalue )
SHA-512: $6$ + 可選rounds參數+ salt(例如: $6$mysaltvalue )
安全性:高
兼容性:在glibc支持的平台上可用(如大多數Linux系統),但Windows不支持。
選擇加密算法時,應考慮以下幾點:
安全性要求:如係統需抵禦現代硬件的暴力破解,建議使用Blowfish( $2y$ )或SHA-512( $6$ )。
跨平台兼容性:若係統需在Linux和Windows之間遷移,應優先使用Blowfish算法,因SHA變種在Windows上不兼容。
計算成本控制:Blowfish支持cost參數(2–31),可根據服務器性能調整。例如, $2y$12$意味著2^12次迭代。
鹽值用於防止相同密碼產生相同的哈希,因此必須具備以下特性:
唯一性:每個用戶的密碼應使用不同的鹽。
不可預測性:應使用安全的偽隨機源生成鹽。
示例代碼,使用Blowfish生成帶鹽的哈希:
function generateSalt($cost = 10) {
$salt = substr(strtr(base64_encode(random_bytes(16)), '+', '.'), 0, 22);
return sprintf('$2y$%02d$%s$', $cost, $salt);
}
$password = 'MySecurePassword123';
$salt = generateSalt(12);
$hash = crypt($password, $salt);
echo "加密後的密碼為: " . $hash;
使用crypt()進行密碼校驗時,應將用戶輸入與原哈希一起傳給crypt() ,如:
function verifyPassword($password, $hash) {
return crypt($password, $hash) === $hash;
}
這樣可以確保校驗過程使用相同的算法和鹽值。
不要手動指定鹽值格式不明的字符串,應使用程序自動生成的安全鹽值。
避免使用DES或MD5 ,即使它們仍被支持。
優先遷移到password_hash()和password_verify() ,這些函數由PHP維護,自動處理算法和鹽值,能更好地抵抗現代攻擊。
一個舊系統在用戶註冊時保存密碼:
$password = $_POST['password'];
$salt = generateSalt(12);
$hashed = crypt($password, $salt);
// 保持 $hashed 到數據庫
登錄時驗證密碼:
$input = $_POST['password'];
$stored_hash = getPasswordFromDatabase(); // 假設已從數據庫取出
if (verifyPassword($input, $stored_hash)) {
echo "登錄成功";
} else {
echo "密碼錯誤";
}
儘管crypt()函數在現代PHP中不再是首選工具,但了解其算法與鹽值機制仍然重要,尤其在維護老舊系統時。推薦使用Blowfish( $2y$ )算法搭配安全生成的鹽值,以確保在兼容性和安全性之間取得平衡。並建議長期來看將系統過渡到password_hash()這一更現代和安全的方案。