首页 > 解决方案 > 为什么在 Symfony 中使用相同的盐和密码调用 encodePassword()(或 hashPasswor())会产生不同的哈希?

问题描述

UserPassword 编码器中,

public function encodePassword(UserInterface $user, string $plainPassword)
{
    $encoder = $this->encoderFactory->getEncoder($user);
    return $encoder->encodePassword($plainPassword, $user->getSalt());
}

编码器从用户实体获取盐。

getSalt()我为in User 实体设置了一个静态变量:

public function getSalt()
{
    return 'my-static-salt';
}

但是当我编码时:

$password  = $encoder->encodePassword($user, "my-password");
$password2 = $encoder->encodePassword($user, "my-password");

$password并且$password2彼此不同,就好像该encodePassword()方法使用随机盐一样。

我错过了什么?

标签: phpsymfonypassword-hash

解决方案


Symfony > 5.4 的注意事项

从 Symfony 6 开始,这些类和方法被更恰当地命名EncodeHash. 并从 Security Core 包移至 Password Hasher 包:

例如, Symfony\Component\Security\Core\Encoder\EncoderFactory变成 Symfony\Component\PasswordHasher\Hasher\PasswordHasherFactory,等等。

但答案的实质是一样的。


EncoderFactory默认情况下,它会给你一个实例(NativePasswordEncoder除非你安装了 libsodium 库,在这种情况下它会给你一个SodiumPasswordEncoder)。

如果你看看 NativePasswordEncoder::encodePassword()你会看到这个

public function encodePassword($raw, $salt)
{
    if (\strlen($raw) > self::MAX_PASSWORD_LENGTH) {
        throw new BadCredentialsException('Invalid password.');
    }

    // Ignore $salt, the auto-generated one is always the best

    $encoded = password_hash($raw, $this->algo, $this->options);

    if (72 < \strlen($raw) && 0 === strpos($encoded, '$2')) {
        // BCrypt encodes only the first 72 chars
        throw new BadCredentialsException('Invalid password.');
    }

    return $encoded;
}

注意这条评论:

// 忽略 $salt,自动生成的总是最好的

如果您不将盐字符串传递给password_hash(),它会在您每次调用它时生成自己的随机生成的盐,并将盐存储在操作的结果中(以及使用的散列算法)。

(同样,SodiumPasswordEncoder你会看到$salt 根本没有使用它,尽管不存在类似的评论)。

进一步阅读:


推荐阅读