建立密碼的雜湊(hash)

password_hash

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

password_hash建立密碼的雜湊(hash)

說明

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

password_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_ARGON2IPASSWORD_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 的實現,則無法使用。

參數

password

使用者的密碼。

警告

使用PASSWORD_BCRYPT 做演算法,將使 password 參數最長為72個字元,超過會被截斷。

algo

一個用來在雜湊密碼時指示演算法的密碼演算法常量

options

一個包含有選項的關聯陣列。詳細的參數說明,請參考文件 密碼演算法常數

省略后,將使用隨機鹽值與預設 cost。

返回值

返回雜湊后的密碼。

使用的演算法、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,等等),不能是在修訂版。 唯一的例外是:在目前預設演算法里發現了緊急的安全威脅。

參見

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *