首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 網頁程式設計 >> PHP 程式設計 >> PHP 相關知識

MD5 + crypt:構建更安全的密碼儲存方案

     編輯:PHP 相關知識

背景與風險

許多早期 PHP 專案直接使用 md5($password) 儲存密碼。MD5 屬於快速雜湊演算法,配合彩虹表、線上解密網站(如 cmd5.com、xmd5.org),弱密碼極易被逆向破解。SQL 注入導致雜湊值洩露後,攻擊者可離線暴力破解,進而奪取管理權限。

進階方案:crypt() + Blowfish (bcrypt)

PHP 內建 crypt() 支援多種演算法,若鹽值以 $2y$ 開頭,將使用 **bcrypt**(基於 Blowfish),具備:

  • 慢速雜湊:可透過 cost 參數調整運算成本,抵禦 GPU/ASIC 暴力破解。
  • 內建鹽值:每次雜湊自動生成唯一鹽值,防禦彩虹表。
  • 標準化格式:$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(...))?

  1. 降低安全性:MD5 將 bcrypt 的輸出(含鹽值、cost)再雜湊,變回快速單向函數,失去 bcrypt 的慢速特性。
  2. 增加碰撞風險:MD5 已知存在碰撞漏洞,雖對預像攻擊仍有一定強度,但屬不必要風險。
  3. 違背最佳實踐:OWASP、NIST 均建議直接使用 bcrypt/Argon2/scrypt 等專用慢速雜湊,不要自行組合。

現代最佳選擇:Argon2id (PHP 7.2+)

<?php
// Argon2id:記憶體硬化,抵禦 GPU/ASIC 並行攻擊
$hash = password_hash($password, PASSWORD_ARGON2ID, [
    'memory_cost' => 65536,   // 64 MB
    'time_cost'   => 4,       // 迭代次數
    'threads'     => 3        // 並行度
]);
?>

遷移舊系統建議

  1. 新增 password_hash 欄位,舊欄位保留。
  2. 用戶登入時,先用 password_verify 驗證新欄位;失敗再驗證舊 MD5,通過後重新雜湊存入新欄位,清空舊欄位。
  3. 定期清理仍未遷移的帳號(強制重設密碼)。

總結

「無敵加密」不存在,只有「提高攻擊成本」。請拋棄 MD5/SHA1,直接使用 password_hash()(bcrypt/Argon2id),這是目前 PHP 生態最安全、最省心的選擇。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved