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

PHP 5.5+ 密碼哈希 API 完整指南:安全創建與驗證密碼哈希

     編輯:PHP 相關知識

背景

PHP 5.5.0 引入 Password Hashing API,提供 `password_hash()`、`password_verify()`、`password_needs_rehash()`、`password_get_info()` 四個函數,基於 bcrypt 預設算法,內建鹽值生成、成本因子控制,是當前 PHP 存儲密碼的標準方式。

核心函數詳解

1. password_hash() - 創建哈希

<?php
$password = 'user_password_123';

// 預設用法 (bcrypt, cost=10)
$hash = password_hash($password, PASSWORD_BCRYPT);
// 結果示例: $2y$10$uOegXJ09qznQsKvPfxr61uWjpJBxVDH2KGJQVnodzjnglhs2WTwHu

// 自定義選項
$options = [
    'cost' => 12, // 成本因子,越高越慢越安全,建議 10-12
    'salt' => random_bytes(22) // PHP 7+ 建議讓函數自動生成,手動指定鹽值已棄用
];
$hash = password_hash($password, PASSWORD_BCRYPT, $options);
// 結果示例: $2y$12$JDJ5JDEwJDhsTHV6SGVIQuprRHZnGQsUEtlk8Iem0okH6HPyCoo22
?>

重要:PHP 7.0+ `salt` 選項已棄用,由內部使用 `random_bytes()` 自動生成安全鹽值。`cost` 因硬件性能而異,建議測試單次哈希耗時 100-300ms。

2. password_get_info() - 獲取哈希信息

<?php
$info = password_get_info($hash);
/*
array(3) {
  ["algo"]=> int(1)           // 算法常量 PASSWORD_BCRYPT
  ["algoName"]=> string(6) "bcrypt"
  ["options"]=> array(1) {
    ["cost"]=> int(12)
  }
}
*/
?>

3. password_needs_rehash() - 檢查是否需重新哈希

<?php
// 例如:系統升級,cost 從 10 提高到 12
if (password_needs_rehash($hash, PASSWORD_BCRYPT, ['cost' => 12])) {
    // 用戶下次登錄驗證成功後,重新生成哈希並更新數據庫
    $newHash = password_hash($password, PASSWORD_BCRYPT, ['cost' => 12]);
    // UPDATE users SET password = $newHash WHERE id = $uid
}
?>

適用場景:算法升級、成本因子調整、鹽值策略變更。無需強制所有用戶重置密碼,漸進式遷移。

4. password_verify() - 驗證密碼

<?php
$hash = '$2y$10$JDJ5JDEwJDhsTHV6SGVIQuprRHZnGQsUEtlk8Iem0okH6HPyCoo22';

$auth = password_verify('user_password_123', $hash); // true
$auth = password_verify('wrong_password', $hash);    // false

// 完整登錄驗證流程
$stmt = $db->prepare("SELECT password FROM users WHERE email = ?");
$stmt->execute([$email]);
$user = $stmt->fetch();

if ($user && password_verify($inputPassword, $user['password'])) {
    // 登錄成功
    if (password_needs_rehash($user['password'], PASSWORD_BCRYPT, ['cost' => 12])) {
        $newHash = password_hash($inputPassword, PASSWORD_BCRYPT, ['cost' => 12]);
        $db->prepare("UPDATE users SET password = ? WHERE email = ?")->execute([$newHash, $email]);
    }
    // 設置會話...
}
?>

算法選擇

常量算法說明
PASSWORD_BCRYPTBCRYPT預設,支援 cost 參數,結果長度 60 字符
PASSWORD_ARGON2IArgon2iPHP 7.2+,抗側信道攻擊,支援 memory_cost/time_cost/threads
PASSWORD_ARGON2IDArgon2idPHP 7.3+,綜合 Argon2i/d 優點,推薦新項目使用
PASSWORD_DEFAULT當前預設PHP 版本升級時可能變更 (現為 BCRYPT),長度可能變化,字段建議 VARCHAR(255)

遷移舊項目 (MD5/SHA1) 方案

<?php
// 登錄時檢測舊哈希格式
if (strlen($row['password']) === 32 && ctype_xdigit($row['password'])) {
    // 疑似 MD5
    if (md5($inputPassword) === $row['password']) {
        // 驗證成功,升級為新哈希
        $newHash = password_hash($inputPassword, PASSWORD_DEFAULT);
        $db->prepare("UPDATE users SET password = ? WHERE id = ?")->execute([$newHash, $row['id']]);
        // 登錄成功...
    }
} elseif (password_verify($inputPassword, $row['password'])) {
    // 已是新哈希,正常驗證
    // ...
}
?>

常見誤區

  • ❌ 使用 `md5($pass.$salt)`、`sha1($pass)` 等自定義方案
  • ❌ 手動生成鹽值並存儲在單獨字段
  • ❌ 雙重哈希 `sha1(md5($pass))` 增加安全性
  • ✅ 直接使用 `password_hash()` / `password_verify()`
  • ✅ 數據庫字段 `VARCHAR(255)` 預留未來算法升級空間
  • ✅ 定期評估 `cost` 因子適應硬件性能提升

總結

Password Hashing API 解決了密碼存儲的核心難題:算法選擇、鹽值管理、成本控制、平滑升級。所有新項目應直接使用,舊項目應制定遷移計劃。安全無小事,密碼哈希是防禦數據洩露的最後一道防線。

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