首页 文章

使用PHP 5.5的password_hash和password_verify函数

提问于
浏览
32

假设我想为用户存储密码,这是使用PHP 5.5的 password_hash() 函数(或PHP 5.3.7的这个版本:https://github.com/ircmaxell/password_compat)的正确方法吗?

$options = array("cost" => 10, "salt" => uniqid());
$hash = password_hash($password, PASSWORD_BCRYPT, $options);

然后我会这样做:

mysql_query("INSERT INTO users(username,password, salt) VALUES($username, $hash, " . $options['salt']);

要插入数据库 .

然后验证:

$row = mysql_fetch_assoc(mysql_query("SELECT salt FROM users WHERE id=$userid"));
$salt = $row["salt"];
$hash = password_hash($password, PASSWORD_BCRYPT, array("cost" => 10, "salt" => $salt));

if (password_verify($password, $hash) {
    // Verified
}

4 回答

  • 6

    暂时忽略数据库语句的问题,我将回答有关 password_hash 的问题 .

    简而言之,不,那不是你怎么做的 . 您不希望单独存储salt,您应该同时存储hash和salt,然后使用它们来验证密码 . password_hash 返回包含两者的字符串 .

    password_hash 函数返回一个包含散列和salt的字符串 . 所以:

    $hashAndSalt = password_hash($password, PASSWORD_BCRYPT);
    // Insert $hashAndSalt into database against user
    

    然后验证:

    // Fetch hash+salt from database, place in $hashAndSalt variable
    // and then to verify $password:
    if (password_verify($password, $hashAndSalt)) {
       // Verified
    }
    

    另外,正如评论所示,如果您对安全性感兴趣,可能需要查看 mysqli (在PHP5.5中不推荐 ext/mysql ),以及关于SQL注入的这篇文章:http://php.net/manual/en/security.database.sql-injection.php

  • 10

    建议不要使用自己的盐,从PHP 7开始,its use is deprecated . 要了解原因,read the author's thoughts

    有一件事对我来说非常清楚:盐的选择是危险的 . 我还没有看到盐选项的单一用法,甚至还不错 . 每个用法的范围从坏(传递mt_rand()输出)到危险(静态字符串)到疯狂(将密码作为自己的盐传递) . 我得出的结论是,我认为我们不应该允许用户指定盐 .

  • 4

    请注意这来自php.net

    警告从PHP 7.0.0开始,不推荐使用salt选项 . 现在优选简单地使用默认生成的盐 .

    结论?忘记盐的选择 .

    这足够了 password_hash('password', PASSWORD_DEFAULT) *(或_BCRYPT)

  • 59

    你不应该输入自己的盐,留盐空,功能会产生良好的随机盐 .

    插入数据库(或文件或任何您使用的)整个函数返回的字符串 . 它包含:算法ID,成本,盐(22个字符)和哈希密码 .

    整个字符串都需要使用password_verify() . 盐是随机的,不会伤到落入坏人手中(使用哈希密码) . 这可以防止(或非常困难)使用ready set生成的密码和散列列表 - 彩虹表 .

    您应该考虑添加成本参数 . 默认(如果省略) is 10 - 如果更高则函数计算哈希更长 . 将成本增加1,生成哈希所需的时间翻倍(从而延长了破解密码所需的时间)

    $hash = password_hash($password, PASSWORD_BCRYPT, array("cost" => 10));
    

    您应该根据服务器上的速度检查设置此参数 . 建议该功能执行100毫秒(有些人更喜欢使其达到250毫秒) . 通常成本= 10或11是一个不错的选择(2015年) .

    为了提高安全性,您可能希望将密码添加为长(50-60个字符是不错的选择)秘密字符串 . 在使用password_hash()或password_verify()之前 .

    $secret_string = 'asCaahC72D2bywdu@#$@#$234';
    $password  = trim($_POST['user_password']) . $secret_string;
    // here use password_* function
    

    警告对于algo参数使用PASSWORD_BCRYPT,将导致密码参数被截断为最大长度为72个字符 .

    如果$ password将超过72个字符并且您更改或添加73或90个字符,则哈希不会更改 . 可选,坚持$ secret_string应该在最后(在用户的密码之后而不是之前) .

相关问题