在PHP 5.5中生成密码哈希并设置成本选项

18

我知道PHP 5.5还处于alpha版本,但我正在提前创建这个类,以利用它的哈希特性,方法是使用function_exists()。

我查看了password_hash文档。第三个参数$options目前支持两个选项,'salt'和'cost'。

文档中如下所述:

cost表示应该使用的算法成本。可以在crypt()页面上找到这些值的示例。

当我进入crypt()页面时,它给出的文档是:

Blowfish哈希,其盐如下:"$2a$"、"$2x$"或"$2y$",一个两位数的成本参数"$"和来自字母表"./0-9A-Za-z"的22位数字。在盐之外使用这个范围的字符将导致crypt()返回一个零长度字符串。两位数的成本参数是基于基于Blowfish的哈希算法器的迭代次数的以2为底的对数,并且必须在04-31范围内,超出此范围的值将导致crypt()失败。PHP 5.3.7之前的版本仅支持"$2a$"作为盐前缀: PHP 5.3.7引入了新的前缀来修复Blowfish实现中的安全漏洞。请参阅»此文件以获取有关安全修复的完整详细信息,但是总结一下,仅针对PHP 5.3.7及更高版本的开发人员应首选"$2y$"。

我似乎无法理解这个。它说PHP 5.3.7及更高版本应该使用$2y$,但我要使用哪个cost值来得到它,而且它是最好的选择吗?他们提供的示例使用了一个7的值,但根据上述内容,它可以达到31,使用4和31有什么区别呢?


1
除非你能找到选择其他值的理由(例如当默认值明显不足时),否则为什么不选择默认值并继续处理下一个问题呢?根据我的经验,自PHP 5.3以来,PHP的默认值已经得到了很大的改善。这只是一个想法,~Ray - Ray Paseur
@RayPaseur,说得没错。但这仍然没有说明为什么要指定不同的成本值以及如何指定。PHP 默认值可能是安全的,但最少可能会出于性能原因。因此,根据生产环境和安全政策,可能需要更强的设置。这只是我的想法。=o) - cryptic ツ
还可以查看Openwall的Portable PHP密码哈希框架(PHPass)。它针对用户密码的多种常见攻击进行了加固。并且它根据所选哈希算法估算成本(但我不确定该选项是否公开)。 - jww
2个回答

18

password_hash()函数只是crypt()函数的一个包装器,它可以使正确使用它更容易。它负责生成一个安全的随机盐,并提供良好的默认值。

使用此函数最简单的方法是:

$hash = password_hash($password, PASSWORD_DEFAULT);

这意味着该函数将使用BCrypt(算法2y)来哈希密码,生成随机盐,并使用默认成本(目前为10)。这些都是很好的默认值,特别是我不建议自己生成盐,那里很容易出错。

如果您想更改成本参数,可以按照以下方式操作:

$hash = password_hash($password, PASSWORD_BCRYPT, ["cost" => 11]);

增加1个成本参数会使得计算哈希值所需时间翻倍。成本参数是迭代次数的以2为底的对数,也就是说:

$iterations = 2 ^ $cost;

编辑:

我看漏了你想要生成自己的类。对于 PHP 版本 5.3.7 及更高版本,有一个兼容包,由制作password_hash()函数的同一位作者开发。你可以直接使用此代码,或查看经过精心制作的实现方式。对于 PHP 版本低于 5.3.7 的情况,不支持带有2ycrypt,即 Unicode 感知 BCrypt 算法。您可以使用2a代替,它是早期 PHP 版本的最佳替代品。我在这里提供了一个带有许多注释的示例,也许您也想看一下。

附言:在password_hash()中,“盐”和“成本因素”表达正确,但是 crypt() 函数将“盐”用于所有crypt参数,这有点误导人。


1
感谢您提供深入的解释和链接。 - cryptic ツ

1

免责声明:此处使用的是 PHP 5.3.10 版本,但与您的描述似乎并没有太大区别。

成本适用于计算成本。当您增加成本值时,哈希密码所需的时间会更长。

function blowfish_salt($cost)
{
    $chars = './ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
    $salt = sprintf('$2y$%02d$', $cost);
    for ($i = 0; $i < 22; ++$i)
        $salt .= $chars[rand(0,63)];

    return $salt;
}

$password = 'My perfect password';
$cost = $argv[1];
$salt = blowfish_salt($cost);
$hash = crypt($password, $salt);

当我在我的(旧)机器上运行此程序时

php mycrypt.php 10

它会立即返回(约0.2秒),而使用其他方法则不会。

php mycrypt.php 16

需要大约5.2秒钟。


除了使暴力破解数据更耗时之外,增加它的好处是什么?何时应该增加它?合理的值是多少?谢谢 =o) - cryptic ツ
1
@cryptic 这就是主要原因。对于用户来说,如果他必须等待更长时间才能完成注册或登录,那么这只会让他感到烦恼。但对于攻击者来说,他能否每秒测试50个密码还是每5秒测试1个密码将产生巨大的差异。虽然默认值为7,但我认为15甚至10可能过高作为成本因素。 - Olaf Dietsche
@OlafDietsche 这个(评论)正是我在寻找的问题/答案,我认为这些信息应该更容易被发现,因为我一直在搜索cost值在增加安全性和/或不便方面的作用。干杯。 - Martin

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接