在PHP 中, crypt()函數常用於對密碼進行加密。它可以支持多種哈希算法,如標準DES、MD5、SHA-256 和SHA-512 等,其行為依賴於傳入的“鹽值”(salt)。鹽值不僅增加了密碼的複雜度,還決定了哈希的方式和結果。一旦鹽值錯誤,即便用戶輸入了正確的原始密碼,也無法通過驗證。
crypt()的基本語法如下:
$hashed_password = crypt('原始密碼', '鹽值');
驗證時,通常會使用之前存儲的哈希作為鹽值重新加密用戶輸入的密碼:
if (crypt($input_password, $stored_hash) === $stored_hash) {
// 密碼正確
}
注意這裡的關鍵點是:哈希本身作為鹽值的一部分傳入,以保證使用的是完全一致的算法和鹽值。
鹽值的主要作用有兩個:
防止彩虹表攻擊(Rainbow Table Attack):即使兩個用戶使用相同的密碼,加入不同的鹽值後其哈希結果也會不同。
告訴crypt()使用哪種加密算法及其參數。
比如以下鹽值指定了使用SHA-512 算法並迭代5000 次:
$salt = '$6$rounds=5000$usesomesillystringforsalt$';
如果你嘗試用不同的鹽值(即使只有一位不同)重新加密同一個密碼,結果也會完全不同。這正是哈希函數的特性:微小變化將導致輸出結果巨大差異。
設想這樣一個場景:
$original_hash = crypt('mySecretPassword', '$6$rounds=5000$m66.net$');
用戶再次登錄時,程序這樣驗證:
if (crypt('mySecretPassword', '$6$rounds=5000$wrongdomain.com$') === $original_hash) {
echo '密碼正確';
} else {
echo '密碼錯誤';
}
雖然用戶輸入了正確的密碼,但由於鹽值不同, crypt()會生成一個完全不同的哈希,導致驗證失敗。
這就像是你用同一個食譜(密碼),但使用了不同的配料(鹽),最終做出來的菜(哈希)自然不一樣。
錯誤做法:
每次驗證時生成新的隨機鹽值。
驗證時不使用原始哈希值作為鹽值。
手動截斷或修改存儲的哈希值。
正確做法:
使用如password_hash()和password_verify()這樣的高層API,它們會自動管理鹽值和算法。
如果使用crypt() ,在驗證時始終使用原始哈希作為鹽值。
$stored_hash = crypt('userPassword', '$6$rounds=5000$m66.net$'); // 註冊時生成並存儲
// 登錄時驗證
if (crypt('userPassword', $stored_hash) === $stored_hash) {
echo '驗證通過';
} else {
echo '驗證失敗';
}
在密碼安全處理中,鹽值看似只是一個字符串,實則是哈希算法行為的決定性參數。使用錯誤的鹽值,就等於告訴crypt()用完全不同的方式去處理密碼,最終注定無法得到相同的哈希結果。因此,確保鹽值的一致性,是使用crypt()函數驗證密碼時最基本的前提。若條件允許,建議優先使用PHP 的password_hash()與password_verify()接口,以避免因鹽值處理錯誤而引發的安全問題。