PHP8 password_hash

2024-03-13 11:25 更新

(PHP 5 >= 5.5.0, PHP 7, PHP 8)

password_hash — 創(chuàng)建密碼的散列(hash)

說明 

password_hash(string $password, string|int|null $algo, array $options = []): string

password_hash() 使用足夠強度的單向散列算法創(chuàng)建密碼的散列(hash)。

當前支持的算法:

  • PASSWORD_DEFAULT - 使用 bcrypt 算法 (PHP 5.5.0 默認)。 注意,該常量會隨著 PHP 加入更新更高強度的算法而改變。 所以,使用此常量生成結(jié)果的長度將在未來有變化。 因此,數(shù)據(jù)庫里儲存結(jié)果的列可超過60個字符(最好是255個字符)。
  • PASSWORD_BCRYPT - 使用 CRYPT_BLOWFISH 算法創(chuàng)建散列。 這會產(chǎn)生兼容使用 "$2y$" 的 crypt()。 結(jié)果將會是 60 個字符的字符串, 或者在失敗時返回 false。
  • PASSWORD_ARGON2I - 使用 Argon2i 散列算法創(chuàng)建散列。 只有在 PHP 編譯時加入 Argon2 支持時才能使用該算法。
  • PASSWORD_ARGON2ID - 使用 Argon2id 散列算法創(chuàng)建散列。 只有在 PHP 編譯時加入 Argon2 支持時才能使用該算法。

PASSWORD_BCRYPT 支持的選項:

  • salt(string) - 手動提供散列密碼的鹽值(salt)。這將避免自動生成鹽值(salt)。省略此值后,password_hash() 會為每個密碼散列自動生成隨機的鹽值。這種操作是有意的模式。警告鹽值(salt)選項已廢棄(deprecated)。 現(xiàn)在最好僅選擇使用默認產(chǎn)生的鹽值。 從 PHP 8.0.0 起,明確指定的 salt 值會被忽略。
  • cost (int) - 代表算法使用的 cost。crypt() 頁面上有 cost 值的示例。省略時,默認值是 10。 這個 cost 是個不錯的底線,但也許可以根據(jù)自己硬件的情況,加大這個值。

PASSWORD_ARGON2I 和 PASSWORD_ARGON2ID 支持的選項:

  • memory_cost (int) - 計算 Argon2 散列時的最大內(nèi)存(單位:KB)。默認值: PASSWORD_ARGON2_DEFAULT_MEMORY_COST。
  • time_cost (int) - 計算 Argon2 散列時最多的時間。默認值: PASSWORD_ARGON2_DEFAULT_TIME_COST。
  • threads (int) - 計算 Argon2 散列時最多的線程數(shù)。默認值: PASSWORD_ARGON2_DEFAULT_THREADS。警告只有在 PHP 使用 libargon2 時可用;如果是 libsodium 的實現(xiàn),則無法使用。

參數(shù)

password

用戶的密碼。

警告

使用PASSWORD_BCRYPT 做算法,將使 password 參數(shù)最長為72個字節(jié),超過會被截斷。

algo

一個用來在散列密碼時指示算法的密碼算法常量。

options

一個包含有選項的關(guān)聯(lián)數(shù)組。詳細的參數(shù)說明,請參考文檔 密碼算法常數(shù)。

省略后,將使用隨機鹽值與默認 cost。

返回值

返回散列后的密碼。

使用的算法、cost 和鹽值作為散列的一部分返回。所以驗證散列值的所有信息都已經(jīng)包含在內(nèi)。 這使 password_verify() 函數(shù)驗證的時候,不需要額外儲存鹽值或者算法的信息。

更新日志

版本說明
8.0.0失敗時 password_hash() 不再返回 false,如果密碼散列算法無效,則會拋出 ValueError,如果密碼散列因未知錯誤失敗,則會拋出 Error。
8.0.0參數(shù) algo 可以為 null。
7.4.0現(xiàn)在 algo 參數(shù)可支持 string 類型,但為了向后兼容也支持 int 類型。
7.4.0擴展 sodium 提供了 Argon2 密碼的替代實現(xiàn)。
7.3.0增加 PASSWORD_ARGON2ID,支持 Argon2id 密碼算法。
7.2.0增加 PASSWORD_ARGON2I,支持 Argon2i 密碼算法。

示例

示例 #1 password_hash() 示例

<?php
/**
 * 我們想要使用默認算法散列密碼
 * 當前是 BCRYPT,并會產(chǎn)生 60 個字符的結(jié)果。
 *
 * 請注意,隨時間推移,默認算法可能會有變化,
 * 所以需要儲存的空間能夠超過 60 字(255字不錯)
 */
echo password_hash("rasmuslerdorf", PASSWORD_DEFAULT);
?>

以上示例的輸出類似于:

$2y$10$.vGA1O9wmRjrwAVXD98HNOgsNpDczlqm3Jq7KnEd1rVAGv3Fykk1a

示例 #2 password_hash() 手動設(shè)置 cost 的示例

<?php
/**
 * 在這個案例里,我們?yōu)?BCRYPT 增加 cost 到 12。
 * 注意,我們已經(jīng)切換到了,將始終產(chǎn)生 60 個字符。
 */
$options = [
    'cost' => 12,
];
echo password_hash("rasmuslerdorf", PASSWORD_BCRYPT, $options);
?>

以上示例的輸出類似于:

$2y$12$QjSH496pcT5CEbzjD/vtVeH03tfHKFy36d4J0Ltp3lRtee9HDxY3K

示例 #3 尋找最佳 cost 的 password_hash() 示例

<?php
/**
 * 這個示例對服務(wù)器做了基準測試(benchmark),檢測服務(wù)器能承受多高的 cost
 * 在不明顯拖慢服務(wù)器的情況下可以設(shè)置最高的值
 * 10 是個不錯的底線,在服務(wù)器夠快的情況下,越高越好。
 * 以下代碼目標為 ≤ 350 毫秒(milliseconds),
 * 對于處理交互式登錄的系統(tǒng)來說,這是一個合適的延遲時間。
 */
$timeTarget = 0.350; // 350 毫秒(milliseconds) 

$cost = 10;
do {
    $cost++;
    $start = microtime(true);
    password_hash("test", PASSWORD_BCRYPT, ["cost" => $cost]);
    $end = microtime(true);
} while (($end - $start) < $timeTarget);

echo "Appropriate Cost Found: " . $cost;
?>

以上示例的輸出類似于:

Appropriate Cost Found: 12

示例 #4 使用 Argon2i 的 password_hash() 示例

<?php
echo 'Argon2i hash: ' . password_hash('rasmuslerdorf', PASSWORD_ARGON2I);
?>

以上示例的輸出類似于:

Argon2i hash: $argon2i$v=19$m=1024,t=2,p=2$YzJBSzV4TUhkMzc3d3laeg$zqU/1IN0/AogfP4cmSJI1vc8lpXRW9/S0sYY2i2jHT0

注釋 

警告

強烈建議不要自己為這個函數(shù)生成鹽值(salt)。只要不設(shè)置,它會自動創(chuàng)建安全的鹽值。

就像以上提及的,在 PHP 7.0 提供 salt選項會導(dǎo)致廢棄(deprecation)警告。 未來的 PHP 發(fā)行版里,手動提供鹽值的功能已經(jīng)在 PHP 8.0 移除。

注意:在交互的系統(tǒng)上,推薦在自己的服務(wù)器上測試此函數(shù),調(diào)整 cost 參數(shù)直至函數(shù)時間開銷小于 350 毫秒(milliseconds)。 上面腳本的示例會幫助選擇合適硬件的最佳 cost。
注意: 這個函數(shù)更新支持的算法時(或修改默認算法),必定會遵守以下規(guī)則:任何內(nèi)核中的新算法必須在經(jīng)歷一次 PHP 完整發(fā)行才能成為默認算法。 比如,在 PHP 7.5.5 中添加的新算法,在 PHP 7.7 之前不能成為默認算法 (由于 7.6 是第一個完整發(fā)行版)。 但如果是在 7.6.0 里添加的不同算法,在 7.7.0 里也可以成為默認算法。僅僅允許在完整發(fā)行版中修改默認算法(比如 7.3.0, 8.0.0,等等),不能是在修訂版。 唯一的例外是:在當前默認算法里發(fā)現(xiàn)了緊急的安全威脅。

參見 

  • password_verify() - 驗證密碼是否和散列值匹配
  • password_needs_rehash() - 檢測散列值是否匹配指定的選項
  • crypt() - 單向字符串散列
  • sodium_crypto_pwhash_str() - Get an ASCII-encoded hash


以上內(nèi)容是否對您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號
微信公眾號

編程獅公眾號