【问题标题】:Does Symfony derive the salt from the hash or isn't the hash salted at all?Symfony 是从散列中派生盐还是散列根本不加盐?
【发布时间】:2014-09-10 08:19:53
【问题描述】:

我正在使用 Symfony2 实现密码重置功能。我对用于验证重置请求的确认代码进行散列和加盐处理有疑问。

$user 变量包含Acme\SecurityBundle\Model\User 的一个实例。这个类的算法是bcrypt,代价是15。

Acme\SecurityBundle\Model\User

namespace Acme\SecurityBundle\Model;

use Acme\SecurityBundle\Model\om\BaseUser;
use Symfony\Component\Security\Core\Util\SecureRandom;

class User extends BaseUser
{
    public function getSalt()
    {
        $random = new SecureRandom();
        return base64_encode($random->nextBytes(128 / 8));
    }
}



散列和验证发生在控制器内部,如下所示。


散列:

// Generate confirmation code
$tokenGenerator = new UriSafeTokenGenerator();
$resetConfirmationCodePlain = substr($tokenGenerator->generateToken(), 0, 20);
// Hash confirmation code
$factory = $this->get('security.encoder_factory');
$encoder = $factory->getEncoder($user);
$resetConfirmationCode = $encoder->encodePassword($resetConfirmationCodePlain, $user->getSalt());


验证:

// Validate confirmation code
$factory = $this->get('security.encoder_factory');
$encoder = $factory->getEncoder($user);
$isValid = $encoder->isPasswordValid(
    $user->getResetConfirmationCode(), $confirmationCode, null
);


如您所见,在散列时添加了盐,但在验证时未添加。尽管如此,确认码验证成功。

有人可以解释一下吗? Symfony 是从哈希中派生盐还是根本不加盐?

附注我以同样的方式更新用户的密码。

【问题讨论】:

标签: php symfony hash


【解决方案1】:

看看哈希值本身...

$2y$10$nOUIs5kJ7naTuTFkBy1veuK0kSxUFXfuaOKdOKf9xYT0KKIGSJwFa
 |  |  |                     |
 |  |  |                     hash-value = K0kSxUFXfuaOKdOKf9xYT0KKIGSJwFa
 |  |  |
 |  |  salt = nOUIs5kJ7naTuTFkBy1veu (22 characters)
 |  |
 |  cost-factor = 10 = 2^10 iterations
 |
 hash-algorithm = 2y = BCrypt

...您可以看到盐包含在存储的哈希值中。验证函数可以从这个存储的哈希中读取使用的盐和其他参数,这就是为什么你不必将此参数传递给函数。

根据 Symfony 的源代码,BCryptPasswordEncoder 内部使用了 PHP 函数 password_hash()。如果省略“salt”参数,此函数将生成安全盐,因此我建议省略此参数。如果您传递一个 salt 参数,该函数将确保 salt 具有有效的格式。

【讨论】:

  • getSalt方法返回一个base64编码的字符串,长度为24。hash 22个字符中的盐怎么算? = 字符是否被剥离?
  • 谢谢。我现在明白了。我会从 getSalt 返回 null 让 PHP 处理这个问题。
【解决方案2】:

你已经成功了一半。使用 BCrypt 生成的最终哈希包括密文、成本和使用的盐。 PHP password_hash 函数是通用的,允许您传入盐(某些算法需要这样做),但如果未在编码上提供,BCrypt 将生成一个,并且在解码时它可能会被忽略(因为你可以得到它从哈希中),所以传入null就可以了。

因此,您不仅在解码时不需要传入盐,在编码时也可能不应该传入盐,因为 BCrypt 会以加密安全的方式处理这一点。

查看questionpassword_hash() 的 PHP 文档

【讨论】:

  • User Provider 需要定义 getSalt 方法。根据该页面底部的注释,值 $password.'{'.$salt.'}'; 被创建,然后如果 getSalt 返回某些内容,则使用 bcrypt 散列,否则它只是使用 bcrypt 编码。
  • 而且我没有存储我的盐,那么 AP 中的哈希如何成功验证?获取值getSalt 返回是否完全被忽略?
  • 我怀疑 Symfony 文档页面不准确,至少对于 BCrypt 而言。如果您查看 BCrypt PasswordEncoder 的源代码github.com/symfony/symfony/blob/master/src/Symfony/Component/…,那么当它们传递给password_hash 时,明文密码和盐仍然是分开的。因此,正如我们所讨论的那样,盐仍然可以从哈希中检索,虽然您没有单独保存盐,但当您保存整个哈希时,您是在间接地保存它。
  • github.com/symfony/symfony/blob/master/src/Symfony/Component/… 有一个 mergePasswordAndSalt 函数,其行为与该文档中的一样,并被其他编码器使用,例如 MessageDigest 。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-02-27
  • 1970-01-01
  • 2011-09-27
  • 2015-02-17
  • 1970-01-01
  • 1970-01-01
  • 2015-08-20
相关资源
最近更新 更多