Symfony 5 如何为 argon2 存储盐?

How Symfony 5 stores salt for argon2?

symfony 如何存储 argon2 的盐字符串? argon 中的盐在编码密码时是强制性的,但没有盐字符串存储在用户实体中。密码编码器中的函数支持盐作为参数,但为空且从未使用过

/vendor/symfony/security-core/Encoder/SodiumPasswordEncoder.php

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

    if (\function_exists('sodium_crypto_pwhash_str')) {
        return sodium_crypto_pwhash_str($raw, $this->opsLimit, $this->memLimit);
    }

    if (\extension_loaded('libsodium')) {
        return \Sodium\crypto_pwhash_str($raw, $this->opsLimit, $this->memLimit);
    }

    throw new LogicException('Libsodium is not available. You should either install the sodium extension, upgrade to PHP 7.2+ or use a different encoder.');
}

盐直接存储在哈希密码上,不需要使用单独的字段来存储盐。

未使用 $salt 参数,因为每次调用 sodium_crypto_pwhash_str 时都会生成一个随机盐,如 the docs:

中所述

Uses a CPU- and memory-hard hash algorithm along with a randomly-generated salt, and memory and CPU limits to generate an ASCII-encoded hash suitable for password storage.

return 值将包含散列密码、使用的算法、salt、内存成本、时间成本等。重新散列和验证用户提供的密码所需的一切,这就是存储在 UserInterface::$password

例如,呼叫:

sodium_crypto_pwhash_str('secret_string',
    SODIUM_CRYPTO_PWHASH_OPSLIMIT_INTERACTIVE,
    SODIUM_CRYPTO_PWHASH_MEMLIMIT_INTERACTIVE
);

会 return 是这样的吗:

$argon2i$v=19$m=32768,t=4,p=1$smna9HfWD+caJJakZiekyQ$qbflsyuP3txLRgsGIt1alcv7HmYjfiMPanYtDU0LtCA

different parts of the response之间用$字符隔开,分别为:

  1. argon2i: 使用的算法
  2. v=19: 版本
  3. m=32768,t=4,p=1:算法选项(内存成本、时间成本、要使用的线程)
  4. smna9HfWD+caJJakZiekyQ这是自动生成的salt。
  5. qbflsyuP3txLRgsGIt1alcv7HmYjfiMPanYtDU0LtCA。实际哈希值。

这是存储在 UserInterface::$password 上的内容,如您所见,它包含验证哈希所需的所有信息,包括盐。将盐存储在单独的字段中已被弃用,保留该字段只是为了向后兼容。

任何使用上述方法或推荐的 password_hash 的人都可以在没有专用盐场的情况下满足他们的所有需求。