PHP 密码哈希函数

PHP crypt() 函数使用基于标准 Unix DES 的算法或替代算法返回散列字符串。

salt 参数是可选的。但是,此函数会在没有盐的情况下创建弱哈希,并且在没有盐的情况下引发 E_NOTICE 错误。确保指定足够强的盐以获得更好的安全性。

哈希类型由盐参数触发。如果未提供盐,PHP 会自动生成标准的两个字符 (DES) 盐或十二个字符 (MD5),具体取决于 MD5 crypt() 的可用性。 PHP 设置 CRYPT_SALT_LENGTH 常量,指示可用哈希所允许的最长有效盐。

基于标准 DES 的 crypt() 将盐返回为输出的前两个字符。它还只使用字符串的前八个字符,因此以相同的八个字符开头的较长字符串将生成相同的结果(当使用相同的盐时)。

支持以下哈希类型:

  • CRYPT_STD_DES - 基于标准 DES 的哈希,带有来自字母表"./0-9A-Za-z"的两个字符盐。在盐中使用无效字符将导致此函数失败。
  • CRYPT_EXT_DES - 扩展的基于 DES 的哈希。 "salt"是一个 9 个字符的字符串,由下划线后跟 4 个字节的迭代计数和 4 个字节的 salt 组成。这些被编码为可打印字符,每个字符 6 位,最低有效字符在前。值 0 到 63 编码为"./0-9A-Za-z"。在 salt 中使用无效字符将导致函数失败。
  • CRYPT_MD5 - 使用以 $1$ 开头的 12 个字符 salt 进行 MD5 哈希
  • CRYPT_BLOWFISH - 使用带有"$2a$"、"$2x$"或"$2y$"、两位数成本参数、"$"和 22 个字符的盐进行 Blowfish 散列来自字母表"./0-9A-Za-z"。在盐中使用此范围之外的字符将导致此函数返回零长度字符串。两位数成本参数是基于 Blowfish 的哈希算法的迭代计数的以 2 为底的对数,并且必须在 04-31 范围内,超出此范围的值将导致该函数失败。 "$2x$"哈希值可能很弱; "$2a$"哈希是兼容的并减轻了这个弱点。对于新的哈希值,应使用"$2y$"。
  • CRYPT_SHA256 - SHA-256 哈希值,带有 16 个字符的盐,前缀为 $5$。如果盐字符串以"rounds=<N>$"开头,则 N 的数值用于指示哈希循环应执行的次数,就像 Blowfish 上的成本参数一样。默认轮数为 5000,最小为 1000,最大为 999,999,999。任何超出此范围的 N 选择都将被截断为最近的限制。
  • CRYPT_SHA512 - SHA-512 哈希,带有 16 个字符的盐,前缀为 $6$。如果盐字符串以"rounds=<N>$"开头,则 N 的数值用于指示哈希循环应执行的次数,就像 Blowfish 上的成本参数一样。默认轮数为 5000,最小为 1000,最大为 999,999,999。任何超出此范围的 N 选择都将被截断为最接近的限制。
注意:没有解密函数,因为 crypt() 使用单向算法。
注释:password_hash() 使用强哈希,生成强盐,并自动应用适当的轮次。 password_hash() 是一个简单的 crypt() 包装器,与现有的密码哈希值兼容。

语法

crypt(string, salt) 

参数

string

必填。 指定要进行哈希处理的字符串。

注意:使用 CRYPT_BLOWFISH 算法将导致 string 参数被截断为最大长度 72 个字符。
salt

可选。 指定散列所基于的盐字符串。如果未提供,则该行为由算法实现定义,并可能导致意外结果。

注意:从 PHP 8.0.0 开始,该参数不再是可选的。

返回值

返回哈希字符串或小于 13 个字符的字符串,并保证与盐值不同失败。

示例:使用具有不同哈希类型的 crypt()

下面的示例显示了 crypt() 函数的用法。

<?php
//2个字符盐
echo 'Standard DES: ',
    crypt('mypassword', 'ac'),
    "\n";

//4字符盐
echo 'Extended DES: ',
    crypt('mypassword', '_A4..acsm'),
    "\n";

//以$1$开头的12个字符盐
echo 'MD5:          ',
    crypt('mypassword', '$1$mypasswo$'),
    "\n";

//以$2a$开头的盐。两位成本参数:09。22个字符
echo 'Blowfish:     ',
    crypt('mypassword', '$2a$07$usesomesillystringforsalt$'),
    "\n";

//16 个字符的盐,以 $5$ 开头。默认轮数为 5000。
echo 'SHA-256:      ',
    crypt('mypassword', '$5$rounds=5000$usesomesillystringforsalt$'),
    "\n";

//以$6$开头的16个字符盐。默认轮数为 5000。
echo 'SHA-512:      ',
    crypt('mypassword', '$6$rounds=5000$usesomesillystringforsalt$'),
    "\n";
?> 

上述代码的输出将是:

Standard DES: acxwGbTpy.Z22
Extended DES: _A4..acsm5imlfzZfEkY
MD5:          $1$mypasswo$gP5WtaHnASiKctngsVs2e.
Blowfish:     $2a$07$usesomesillystringforeP9DkYeBci44xgF1uJmwup2ZMGjpx/Z.
SHA-256:      $5$rounds=5000$usesomesillystri$36krcUEy2oAY5YFLl52aUa7fXbx6WMAH7llQCX/qk8A
SHA-512:      $6$rounds=5000$usesomesillystri$9sGqw8yRnx47zvLmqor/MmDMoRmQBC/fSLybwKnI3NHrscdA9hBOcTBeFEN6niDykgCe.0e3oUHZR53HdDneO/ 

示例:crypt() 示例

再考虑一个示例,说明如何使用此函数验证密码。

<?php
//以$1$开头的12个字符盐
$hashed_password = crypt('mypassword', '$1$password$');

if (hash_equals($hashed_password, crypt($user_input, $hashed_password))) {
  echo "Password verified!";
}
?>