PHP 密码哈希函数

PHP password_hash() 函数使用强大的单向哈希算法创建密码哈希。它与 crypt() 兼容。因此,由 crypt() 创建的密码哈希可以与此函数一起使用。

以下算法是目前支持:

  • PASSWORD_DEFAULT - 从 PHP 5.5.0 开始默认使用 BCRYPT 算法。请注意,随着新的和更强大的算法被添加到 PHP 中,此常量可能会随着时间的推移而改变,因此允许存储扩展到超过 60 个字符(建议 255 个)。
  • PASSWORD_BCRYPT - 使用 CRYPT_BLOWFISH创建哈希的算法。这将使用"$2y$"标识符生成标准的 crypt() 兼容哈希值。结果始终是 60 个字符的字符串,失败时返回 false。
  • PASSWORD_ARGON2I - 使用 Argon2i 哈希算法创建哈希。仅当 PHP 编译时支持 Argon2 时,此算法才可用。
  • PASSWORD_ARGON2ID - 使用 Argon2id 哈希算法创建哈希。仅当 PHP 编译时支持 Argon2 时,此算法才可用。

PASSWORD_BCRYPT 支持的选项:

  • salt(字符串)- 手动提供在散列密码时使用的盐。这将覆盖并阻止自动生成盐。

    如果省略,password_hash()将为每个散列的密码生成随机盐。这是预期的操作模式,从 PHP 7.0.0 开始,salt 选项已被弃用。

  • cost (int) - 表示应使用的算法成本。

    如果省略,将使用默认值 10。这是一个不错的基准成本,但您可能需要考虑根据您的硬件增加它。

PASSWORD_ARGON2I 支持的选项PASSWORD_ARGON2ID:

  • memory_cost (int) - 可用于计算 Argon2 哈希值的最大内存(以字节为单位)。默认值为 PASSWORD_ARGON2_DEFAULT_MEMORY_COST。
  • time_cost (int) - 计算 Argon2 哈希所需的最长时间。默认值为 PASSWORD_ARGON2_DEFAULT_TIME_COST。
  • threads (int) - 用于计算 Argon2 哈希值的线程数。默认值为 PASSWORD_ARGON2_DEFAULT_THREADS。仅适用于 libargon2,不适用于 libsodium 实现。

语法

password_hash(password, algo, options) 

参数

passwrod

必填。 指定用户的密码。

使用 PASSWORD_BCRYPT 作为算法,将导致 password 参数被截断为最大长度 72 个字符。
algo必填。 指定密码算法常量,表示对密码进行哈希处理时使用的算法。
options

可选。 指定包含选项的关联数组。有关每种算法支持的选项的文档,请参阅密码算法常量

如果省略,则将创建随机盐并使用默认成本。

返回值

返回哈希密码。

使用的算法、成本和盐作为哈希的一部分返回。因此,验证哈希所需的所有信息都包含在其中。这允许 password_verify() 函数验证哈希值,而无需单独存储盐或算法信息。

示例:password_hash()示例

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

<?php
//使用当前默认值对密码进行哈希处理
//目前是BCRYPT的算法,以及
//产生 60 个字符的结果。请注意,默认值
//可能会随着时间的推移而改变,因此允许存储
//扩展过去60个字符(推荐255个)
echo password_hash("myPassword", PASSWORD_DEFAULT);
?> 

上述代码的输出将是类似于:

$2y$10$Hm6KC1/82.P4Nq.BxTRHt.2W38QueusDaa6rCvO5KhP79RyDyXq7C 

示例:手动设置cost

在下面的示例中,手动设置 BCRYPT 算法的成本。

<?php
//将BCRYPT的默认成本增加到11
$options = array('cost' => 11);

//使用BCRYPT算法对密码进行哈希处理
echo password_hash("myPassword", PASSWORD_BCRYPT, $options);
?> 

上述代码的输出将类似于:

$2y$11$qy1hDCTAxJ7WL7pZn0H4Le6oWEgo63nTGzrpxSCpP3MK1yJzc/O1G 

示例:找到一个好的成本

下面的示例解释了如何为 BCRYPT 哈希算法找到一个好的成本.

<?php
//下面的代码将对服务器进行基准测试以确定
//在不减慢速度的情况下可以承受多高的成本
//太多了。 8-10 是一个很好的基线,越多越好
//如果服务器足够快。下面的代码旨在
//对于≤50毫秒的拉伸时间,这是一个很好的
//系统处理交互式登录的基线

$timeTarget = 0.05; // 50 毫秒

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

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

上述代码的输出将类似于:

Appropriate Cost Found: 10 

示例:使用 Argon2i

再考虑一个使用 ARGON2I 散列的示例算法用于创建哈希。

<?php
//使用ARGON2I算法对密码进行哈希处理
echo "Argon2i hash: \n";
echo password_hash('myPassword', PASSWORD_ARGON2I);
?> 

上述代码的输出将类似于(为了便于阅读而自动换行):

Argon2i hash: 
$argon2i$v=19$m=65536,t=4,p=1$ZUl3S2V6LnJBWS5EM1FybQ$E
fVOU5v98/oM1EExvYUM0mFcWUHZ+QrWLqsohVvuixs 
注意:建议在您的服务器上测试此功能,并调整成本参数,使该功能在交互式系统上的执行时间少于100毫秒。