許多早期 PHP 專案直接使用 md5($password) 儲存密碼。MD5 屬於快速雜湊演算法,配合彩虹表、線上解密網站(如 cmd5.com、xmd5.org),弱密碼極易被逆向破解。SQL 注入導致雜湊值洩露後,攻擊者可離線暴力破解,進而奪取管理權限。
crypt() + Blowfish (bcrypt)PHP 內建 crypt() 支援多種演算法,若鹽值以 $2y$ 開頭,將使用 **bcrypt**(基於 Blowfish),具備:
$2y$10$SaltHash...,包含演算法、cost、鹽值、雜湊,無需額外儲存欄位。password_hash() / password_verify() (PHP 5.5+)這是官方提供的高階 API,底層封裝 crypt(),自動處理鹽值生成、演算法升級、時序安全比對。
<?php
// 註冊/修改密碼時
$hash = password_hash($password, PASSWORD_DEFAULT); // 目前為 bcrypt,cost=10
// 儲存 $hash 到資料庫(VARCHAR(255))
// 登入驗證時
if (password_verify($inputPassword, $hashFromDb)) {
// 密碼正確
// 若演算法過舊(如 cost 過低),password_needs_rehash() 會提示重新雜湊
if (password_needs_rehash($hashFromDb, PASSWORD_DEFAULT)) {
$newHash = password_hash($inputPassword, PASSWORD_DEFAULT);
// 更新資料庫
}
} else {
// 密碼錯誤
}
?>
md5(crypt(...))?<?php
// Argon2id:記憶體硬化,抵禦 GPU/ASIC 並行攻擊
$hash = password_hash($password, PASSWORD_ARGON2ID, [
'memory_cost' => 65536, // 64 MB
'time_cost' => 4, // 迭代次數
'threads' => 3 // 並行度
]);
?>
password_hash 欄位,舊欄位保留。password_verify 驗證新欄位;失敗再驗證舊 MD5,通過後重新雜湊存入新欄位,清空舊欄位。「無敵加密」不存在,只有「提高攻擊成本」。請拋棄 MD5/SHA1,直接使用 password_hash()(bcrypt/Argon2id),這是目前 PHP 生態最安全、最省心的選擇。