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

PHP crypt() 單向加密實現用戶認證:原理、代碼與安全遷移指南

     編輯:PHP 綜合知識

前言

crypt() 是 PHP 早期提供的單向加密函數,基於系統底層 crypt(3) 實現。雖曾廣泛用於密碼存儲,但現已不推薦用於新專案。本文解析其原理、實現認證流程、安全缺陷及遷移路徑。

crypt() 函數詳解

string crypt(string $string, string $salt = ''): string
  • $string:待加密明文
  • $salt:干擾串,影響加密結果,防彩虹表攻擊
  • 返回:$salt + 哈希值(驗證時需用完整返回值作 salt)

支援算法與 Salt 格式

算法常量Salt 長度/前綴備註
CRYPT_STD_DES2 字符預設,極不安全
CRYPT_EXT_DES9 字符擴展 DES
CRYPT_MD512 字符,以 $1$ 開頭MD5-based
CRYPT_BLOWFISH16 字符,以 $2$/$2a$/$2y$ 開頭Bcrypt,較安全
CRYPT_SHA25616 字符,$5$SHA-256 crypt
CRYPT_SHA51216 字符,$6$SHA-512 crypt

原文認證代碼分析(含安全問題)


⚠️ 致命安全缺陷盤點

  1. Salt 來源錯誤:substr($password, 0, 2) 使 salt 與密碼綁定,失去隨機性,等同無 salt
  2. 算法不受控:依賴系統預設(可能是弱 DES),無法指定 bcrypt
  3. SQL 注入:直接拼接變量進 SQL
  4. 已棄用 API:mysql_* 函數 PHP 7.0+ 已移除
  5. 時序攻擊:== 比較字符串,可被側通道攻擊
  6. 無密碼策略:允許任意弱密碼
  7. 會話管理缺失:直接 require 頁面,無 Session、CSRF 保護

正確使用 crypt() 的姿勢(僅限維護舊系統)

現代標準:password_hash / password_verify

PHP 5.5+ 內建,自動處理算法選擇、Salt 生成、成本因子、驗證:

 12]);
// $2y$12$xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

// 驗證(自動從 hash 解析算法、salt、cost)
if (password_verify('input_pass', $hash)) {
    echo '驗證通過';
}

// 檢查是否需重新哈希(算法升級、cost 變更)
if (password_needs_rehash($hash, PASSWORD_DEFAULT, ['cost' => 14])) {
    $newHash = password_hash('StrongPass123!', PASSWORD_DEFAULT, ['cost' => 14]);
    // 更新資料庫
}

遷移指南:從 crypt() 到 password_hash

prepare("SELECT id, password_hash FROM users WHERE username = ?");
    $stmt->execute([$username]);
    $user = $stmt->fetch();
    
    if (!$user) return null; // 用戶不存在(用固定時間延遲防枚舉)
    
    // 情況1:已是 password_hash 格式
    if (str_starts_with($user['password_hash'], '$2y$') || 
        str_starts_with($user['password_hash'], '$argon2')) {
        if (password_verify($password, $user['password_hash'])) {
            // 檢查需否升級
            if (password_needs_rehash($user['password_hash'], PASSWORD_DEFAULT)) {
                $newHash = password_hash($password, PASSWORD_DEFAULT);
                $pdo->prepare("UPDATE users SET password_hash = ? WHERE id = ?")
                    ->execute([$newHash, $user['id']]);
            }
            return $user;
        }
    }
    // 情況2:舊 crypt() 格式(如 $1$ MD5 或 DES)
    elseif (verifyLegacyCrypt($password, $user['password_hash'])) {
        // 驗證通過,升級為現代哈希
        $newHash = password_hash($password, PASSWORD_DEFAULT);
        $pdo->prepare("UPDATE users SET password_hash = ? WHERE id = ?")
            ->execute([$newHash, $user['id']]);
        return $user;
    }
    
    return null; // 密碼錯誤
}

function verifyLegacyCrypt(string $password, string $hash): bool {
    // 兼容舊 crypt 驗證
    return hash_equals(crypt($password, $hash), $hash);
}

總結

  • crypt() 是歷史產物,新代碼嚴禁使用
  • 現代標準:password_hash() + password_verify() + PASSWORD_DEFAULT
  • 資料庫欄位:VARCHAR(255) 足夠存儲所有算法哈希
  • 遷移策略:登入時驗證舊哈希 → 升級為新哈希 → 覆蓋存儲
  • 防禦深度:HTTPS、速率限制、雙因子認證、密碼策略、日誌審計
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved