當前位置: 首頁> 最新文章列表> 使用crypt() 與hash_equals() 安全地比較密碼

使用crypt() 與hash_equals() 安全地比較密碼

M66 2025-05-20

在構建用戶認證系統時,安全地處理密碼是開發者必須重視的問題。錯誤地比較密碼,可能導致系統受到時序攻擊(Timing Attacks)等安全威脅。 PHP 提供了一些內建函數,可以幫助我們安全地處理密碼驗證。其中, crypt()hash_equals()的組合使用,是一種相對安全的實踐方式。

一、什麼是crypt() 函數?

crypt()是PHP 的一個加密函數,用於基於某種算法(如bcryptSHA-512等)對密碼進行哈希加密。它的語法如下:

 string crypt(string $string, string $salt)

salt參數決定了加密算法及其行為。對於現代應用,推薦使用bcrypt ,可以通過以下方式自動生成適當的salt

 $salt = '$2y$10$' . substr(strtr(base64_encode(random_bytes(16)), '+', '.'), 0, 22);
$hash = crypt('mypassword', $salt);

二、為什麼不能直接使用=====來比較密碼哈希?

很多初學者會寫出如下代碼來驗證密碼:

 if (crypt($inputPassword, $storedHash) == $storedHash) {
    // 登錄成功
}

這在功能上看似可行,但存在嚴重的安全隱患——時序攻擊(Timing Attack) 。攻擊者可以通過測量程序響應時間的微小差異,逐步猜出正確的密碼哈希。

三、安全的做法:使用hash_equals()

為了解決時序攻擊的問題,PHP 從5.6 開始提供了hash_equals()函數,用於安全地比較兩個哈希值:

 bool hash_equals(string $known_string, string $user_string)

它使用恆定時間算法,不會根據字符串內容提前返回,避免了時間差洩露。

四、結合crypt() 與hash_equals() 的完整示例

<?php
// 假設我們從數據庫獲取了加密後的密碼哈希
$storedHash = '$2y$10$9YzyYtVht3tcGEn.7PiF2OlRM0HDTrM7Z5D.yPi8hdm0fJeFVKH4K'; // 由 crypt() 生成的 bcrypt 哈希
$inputPassword = $_POST['password'] ?? '';

// 用 crypt() 對用戶輸入的密碼進行哈希,使用存儲哈希作為 salt
$inputHash = crypt($inputPassword, $storedHash);

// 使用 hash_equals() 安全比較
if (hash_equals($storedHash, $inputHash)) {
    echo "登錄成功!";
} else {
    echo "密碼錯誤!";
}
?>

五、推薦的現代做法(補充)

雖然crypt()仍然可以安全使用,但PHP 官方更推薦使用password_hash()password_verify() ,因為它們封裝了算法選擇與安全比較過程,使用更加簡單安全。例如:

 // 創建密碼哈希
$hash = password_hash('mypassword', PASSWORD_BCRYPT);

// 驗證密碼
if (password_verify($inputPassword, $hash)) {
    echo "驗證通過";
}

但在某些場景下(如維護舊系統或有特殊需求), crypt()hash_equals()的組合仍然是一個可接受且安全的方案。

六、總結

  • 避免使用=====比較密碼哈希;

  • 使用crypt()哈希密碼時要正確選擇salt和算法(推薦bcrypt);

  • 使用hash_equals()進行安全比較,防止時序攻擊;

  • 如果沒有特定理由,推薦使用password_hash()password_verify()替代低層封裝。

在處理用戶密碼時,安全不是可選項,而是必需項。正確的做法不僅能保護用戶隱私,還能提升整個系統的抗攻擊能力。