password_hash
(PHP 5 >= 5.5.0, PHP 7, PHP 8)
password_hash — 建立密碼的雜湊(hash)
說明
$password
, string|int|null $algo
, array $options
= []): stringpassword_hash() 使用足夠強度的單向雜湊演算法建立密碼的雜湊(hash)。 password_hash() 相容 crypt()。 所以, crypt() 建立的密碼雜湊也可用於 password_hash()。
目前支援的演算法:
-
PASSWORD_DEFAULT
- 使用 bcrypt 演算法 (PHP 5.5.0 預設)。 注意,該常量會隨著 PHP 加入更新更高強度的演算法而改變。 所以,使用此常量產生結果的長度將在未來有變化。 因此,數據庫里儲存結果的列可超過60個字元(最好是255個字元)。 -
PASSWORD_BCRYPT
- 使用CRYPT_BLOWFISH
演算法建立雜湊。 這會產生相容使用 "$2y$" 的 crypt()。 結果將會是 60 個字元的字串, 或者在失敗時返回false
。 -
PASSWORD_ARGON2I
- 使用 Argon2i 雜湊演算法建立雜湊。 只有在 PHP 編譯時加入 Argon2 支援時才能使用該演算法。 -
PASSWORD_ARGON2ID
- 使用 Argon2id 雜湊演算法建立雜湊。 只有在 PHP 編譯時加入 Argon2 支援時才能使用該演算法。
PASSWORD_BCRYPT
支援的選項:
-
salt
(string) - 手動提供雜湊密碼的鹽值(salt)。這將避免自動產生鹽值(salt)。省略此值后,password_hash() 會為每個密碼雜湊自動產生隨機的鹽值。這種操作是有意的模式。
警告鹽值(salt)選項已廢棄(deprecated)。 現在最好僅選擇使用預設產生的鹽值。 從 PHP 8.0.0 起,明確指定的 salt 值會被忽略。
-
cost
(int) - 代表演算法使用的 cost。crypt() 頁面上有 cost 值的例子。省略時,預設值是
10
。 這個 cost 是個不錯的底線,但也許可以根據自己硬體的情況,加大這個值。
PASSWORD_ARGON2I
和 PASSWORD_ARGON2ID
支援的選項:
-
memory_cost
(int) - 計算 Argon2 雜湊時的最大記憶體(單位:KB)。預設值:PASSWORD_ARGON2_DEFAULT_MEMORY_COST
。 -
time_cost
(int) - 計算 Argon2 雜湊時最多的時間。預設值:PASSWORD_ARGON2_DEFAULT_TIME_COST
。 -
threads
(int) - 計算 Argon2 雜湊時最多的執行緒數。預設值:PASSWORD_ARGON2_DEFAULT_THREADS
。警告只有在 PHP 使用 libargon2 時可用;如果是 libsodium 的實現,則無法使用。
參數
返回值
返回雜湊后的密碼。
使用的演算法、cost 和鹽值作為雜湊的一部分返回。所以驗證雜湊值的所有資訊都已經包含在內。 這使 password_verify() 函式驗證的時候,不需要額外儲存鹽值或者演算法的資訊。
更新日誌
版本 | 說明 |
---|---|
8.0.0 |
失敗時 password_hash() 不再返回 false 。
|
8.0.0 |
參數 algo 可以為 null。
|
7.4.0 |
現在 algo 參數可支援 string 型別,但爲了向後相容也支援
int 型別。
|
7.4.0 | 擴充套件 sodium 提供了 Argon2 密碼的替代實現。 |
7.3.0 |
增加 PASSWORD_ARGON2ID ,支援 Argon2id 密碼演算法。
|
7.2.0 |
增加 PASSWORD_ARGON2I ,支援 Argon2i 密碼演算法。
|
範例
示例 #1 password_hash() 例子
<?php
/**
* 我們想要使用預設演算法雜湊密碼
* 目前是 BCRYPT,並會產生 60 個字元的結果。
*
* 請注意,隨時間推移,預設演算法可能會有變化,
* 所以需要儲存的空間能夠超過 60 字(255字不錯)
*/
echo password_hash("rasmuslerdorf", PASSWORD_DEFAULT);
?>
以上例程的輸出類似於:
$2y$10$.vGA1O9wmRjrwAVXD98HNOgsNpDczlqm3Jq7KnEd1rVAGv3Fykk1a
示例 #2 password_hash() 手動設定 cost 的例子
<?php
/**
* 在這個案例里,我們為 BCRYPT 增加 cost 到 12。
* 注意,我們已經切換到了,將始終產生 60 個字元。
*/
$options = [
'cost' => 12,
];
echo password_hash("rasmuslerdorf", PASSWORD_BCRYPT, $options);
?>
以上例程的輸出類似於:
$2y$12$QjSH496pcT5CEbzjD/vtVeH03tfHKFy36d4J0Ltp3lRtee9HDxY3K
示例 #3 尋找最佳 cost 的 password_hash() 例子
<?php
/**
* 這個例子對伺服器做了基準測試(benchmark),檢測伺服器能承受多高的 cost
* 在不明顯拖慢伺服器的情況下可以設定最高的值
* 8-10 是個不錯的底線,在伺服器夠快的情況下,越高越好。
* 以下程式碼目標為 ≤ 50 毫秒(milliseconds),
* 適合系統處理互動登錄。
*/
$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
註釋
強烈建議不要自己為這個函式產生鹽值(salt)。只要不設定,它會自動建立安全的鹽值。
就像以上提及的,在 PHP 7.0 提供 salt
選項會導致廢棄(deprecation)警告。
未來的 PHP 發行版里,手動提供鹽值的功能可能會被刪掉。
注意:
在互動的系統上,推薦在自己的伺服器上測試此函式,調整 cost 參數直至函式時間開銷小於 100 毫秒(milliseconds)。 上面指令碼的例子會幫助選擇合適硬體的最佳 cost。
注意: 這個函式更新支援的演算法時(或修改預設演算法),必定會遵守以下規則:
- 任何內核中的新演算法必須在經歷一次 PHP 完整發行才能成為預設演算法。 比如,在 PHP 7.5.5 中新增的新演算法,在 PHP 7.7 之前不能成為預設演算法 (由於 7.6 是第一個完整發行版)。 但如果是在 7.6.0 里新增的不同演算法,在 7.7.0 里也可以成為預設演算法。
- 僅僅允許在完整發行版中修改預設演算法(比如 7.3.0, 8.0.0,等等),不能是在修訂版。 唯一的例外是:在目前預設演算法里發現了緊急的安全威脅。
參見
- password_verify() - 驗證密碼是否和雜湊值匹配
- crypt() - 單向字串雜湊
- » 使用者的使用
- sodium_crypto_pwhash_str() - Get an ASCII-encoded hash