在PHP 中, crypt()是一個用於哈希加密的函數,它廣泛應用於密碼處理和數據加密的場景中。然而,許多開發者在使用crypt()函數加密相同內容時,會驚訝地發現:
這篇文章將帶你深入理解這個現象背後的原因,並教你如何正確、安全地使用crypt() 。
crypt()的本質是一個哈希函數,它不是為了加密數據,而是為了生成不可逆的哈希值,常用於密碼驗證。
函數原型如下:
string crypt(string $string, string $salt)
它接收兩個參數:
$string :要加密的字符串。
$salt :加密時使用的“鹽值”,用於影響哈希結果。
如果你傳遞了相同的$salt ,那麼加密相同的$string ,自然會得到相同的結果。這正是你看到“加密結果總是一樣”的原因。
這是因為你在調用crypt()時,可能使用了固定的鹽值,或者乾脆沒有傳入第二個參數$salt 。
PHP 的crypt()在沒有提供$salt時,會嘗試使用某些系統默認機制,但這種機制可能在一些系統上表現為“默認使用相同的salt”,從而導致“同一個輸入,總是得到相同的輸出”。
看看下面的例子:
echo crypt("mypassword", "m6"); // 使用固定 salt
每次運行這段代碼,無論多少次,輸出都一樣。這意味著,如果攻擊者知道你使用的是固定的salt,他們也可以預計算哈希值表,對你的系統進行攻擊。
**正確做法是:使用隨機的salt 值。 **每次為用戶生成密碼哈希時,都生成一個獨立的salt,並把它存儲在數據庫中。這樣即使兩個用戶密碼相同,他們的哈希值也不同。
PHP 推薦使用帶有自動生成salt 的方式,例如使用password_hash()函數,這是從PHP 5.5+ 引入的更安全的方式:
$password = 'mypassword';
$hash = password_hash($password, PASSWORD_BCRYPT);
這個函數內部會自動為你生成一個獨特的salt,並將其附加在結果中。每次運行都會得到不同的結果:
// 每次輸出都不一樣
$hash1 = password_hash('mypassword', PASSWORD_BCRYPT);
$hash2 = password_hash('mypassword', PASSWORD_BCRYPT);
但它們仍然是可以通過password_verify()來驗證原始密碼的。
如果你非得用crypt() ,那就手動生成隨機的salt。下面是一個示例:
function generate_salt($length = 22) {
return substr(strtr(base64_encode(random_bytes($length)), '+', '.'), 0, $length);
}
$password = 'mypassword';
$salt = '$2y$10$' . generate_salt(); // 使用 Blowfish 演算法
$hash = crypt($password, $salt);
每次調用都會生成不同的salt,自然也會生成不同的加密結果。
加密後的結果應該存儲在數據庫中,用於後續驗證。示例代碼如下:
// 存儲時
$hash = crypt($password, $salt);
// 保存到數據庫
// 驗證時
if (hash_equals($hash, crypt($inputPassword, $hash))) {
echo "密碼正確";
} else {
echo "密碼錯誤";
}
注意crypt()的第二個參數可以直接傳入已加密的哈希值,PHP 會自動從中提取salt。
crypt()返回相同結果,是因為你用了相同的salt。
要想安全,應使用隨機salt,或直接用password_hash() 。
不建議在新項目中繼續使用crypt() ,除非有特別需求。
始終避免硬編碼salt,防止彩虹表攻擊。
在開發涉及用戶密碼處理的系統時,始終以安全為第一要務。正確理解crypt()的行為,有助於你構建一個更穩固、更可靠的應用系統。