(PHP 5 >= 5.5.0, PHP 7, PHP 8)
password_hash — 創(chuàng)建密碼的散列(hash)
$password
, string|int|null $algo
, array $options
= []): stringpassword_hash() 使用足夠強度的單向散列算法創(chuàng)建密碼的散列(hash)。 password_hash() 兼容 crypt()。 所以, crypt() 創(chuàng)建的密碼散列也可用于 password_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),則無法使用。
password
用戶的密碼。
使用PASSWORD_BCRYPT
做算法,將使 password
參數(shù)最長為72個字符,超過會被截斷。
algo
一個用來在散列密碼時指示算法的密碼算法常量。
options
一個包含有選項的關(guān)聯(lián)數(shù)組。詳細的參數(shù)說明,請參考文檔 密碼算法常數(shù)。
省略后,將使用隨機鹽值與默認 cost。
返回散列后的密碼。
使用的算法、cost 和鹽值作為散列的一部分返回。所以驗證散列值的所有信息都已經(jīng)包含在內(nèi)。 這使 password_verify() 函數(shù)驗證的時候,不需要額外儲存鹽值或者算法的信息。
版本 | 說明 |
---|---|
8.0.0 |
失敗時 password_hash() 不再返回 false 。
|
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)?nbsp;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è)置最高的值
* 8-10 是個不錯的底線,在服務(wù)器夠快的情況下,越高越好。
* 以下代碼目標為 ≤ 50 毫秒(milliseconds),
* 適合系統(tǒng)處理交互登錄。
*/
$timeTarget = 0.05; // 50 毫秒(milliseconds)
$cost = 8;
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: 10
示例 #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ā)行版里,手動提供鹽值的功能可能會被刪掉。
注意:
在交互的系統(tǒng)上,推薦在自己的服務(wù)器上測試此函數(shù),調(diào)整 cost 參數(shù)直至函數(shù)時間開銷小于 100 毫秒(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)了緊急的安全威脅。