【问题标题】:Do I need base64 encode my salt (for hashing passwords)?我是否需要对我的盐进行 base64 编码(用于散列密码)?
【发布时间】:2013-01-16 21:07:32
【问题描述】:

请原谅我提出这个非常奇怪的问题。我了解 base64 编码用于传输数据的目的(即 MIME 的 Base64 编码),但我不知道是否需要对我的 salts 进行 base64 编码。

我写了一个实用类(确实是一个基础抽象类):

use Symfony\Component\Security\Core\Encoder\BasePasswordEncoder;

abstract class AbstractCryptPasswordEncoder extends BasePasswordEncoder
{
    /**
     * @return string
     */
    protected abstract function getSaltPrefix();

    /**
     * @return string
     */
    protected abstract function getSalt();

    /**
     * {@inheritdoc}
     */
    public function encodePassword($raw, $salt = null)
    {
        return crypt($raw, $this->getSaltPrefix().$this->getSalt());
    }

    /**
     * {@inheritdoc}
     */
    public function isPasswordValid($encoded, $raw, $salt = null)
    {
        return $encoded === crypt($raw, $encoded);
    }
}

真正的实现类是:

class Sha512CryptPasswordEncoder extends AbstractCryptPasswordEncoder
{
    /**
     * @var string
     */
    private $rounds;

    /**
     * @param null|int $rounds The number of hashing loops
     */
    public function __construct($rounds = null)
    {
        $this->rounds = $rounds;
    }

    /**
     * {@inheritdoc}
     */
    protected  function getSaltPrefix()
    {
        return sprintf('$6$%s', $this->rounds ? "rounds={$this->rounds}$" : '');
    }

    /**
     * {@inheritdoc}
     */
    protected function getSalt()
    {
        return base64_encode(openssl_random_pseudo_bytes(12));
    }
}

关键部分是盐生成,它将嵌入密码中:我是否需要base64_encode 出于任何原因(存储),假设它永远不会通过网络发送?

【问题讨论】:

标签: php passwords base64 salt crypt


【解决方案1】:

BASE64 用于将二进制数据编码为文本表示。它允许使用文本通道传输二进制数据。如果您想将散列密码存储在 DB 中,则不必对其进行编码 - 它已经是文本格式。

【讨论】:

    【解决方案2】:

    每个哈希算法都需要给定字母表中的盐,这意味着使用 base64_encode() 可能是正确的,但通常它要么不使用完整的字母表,要么返回不在此字母表中的字符。

    以 BCrypt 为例,这是一个很好的密码哈希算法(SHA-512 不合适,因为它太快了),它接受 base64 编码字符串的所有字符,除了 '+' 字符。另一方面,它接受'。不属于 base64 编码字符串的字符。

    PHP 5.5 将有函数password_hash()password_verify() 准备好,让BCrypt 的使用更容易,我真的可以推荐它们。还有一个 compatibility pack 可用于较旧的 PHP 版本,在第 121 行您可以看到确实使用了 base64_encode(),但之后所有无效的 '+' 字符都被替换为允许的 '.'字符:

    为 BCrypt 编码盐:

    $salt = str_replace('+', '.', base64_encode($buffer));
    

    【讨论】:

    • +1 以获得好的答案。关于兼容性包的部分并不完全清楚,因此为了其他人的利益,兼容性包是一个可下载的库,它为 PHP 5.3 或 5.4 的用户实现了 PHP5.5 password_xxx() 函数。这意味着任何当前支持的 PHP 版本的所有用户都可以使用新的官方 PHP 密码 API
    • @SDC - 感谢您的评论,我试图让它更清楚一点。
    • 优秀的答案,+1。虽然河豚盐要求对我来说非常清楚(base64 编码随机字节,'+' 替换)但仍然不清楚 sha512 盐要求:原始字节?一些字母?
    • @Gremo - 刚刚查看了 PHP 源代码,并没有发现关于 salt 的 SHA-512 aphabet 的任何限制。该代码使用strcspn() 查找盐的终止“$”,这意味着盐不应包含空字符,当然也不能包含“$”字符。所以你不能使用原始字节盐和没有 unicode 字符(它们通常包含一个空字节)。我不能肯定地说,我没问题(我不是 C 破解),所以也许最好使用与 BCrypt 等其他算法相同的字母表,只是为了安全起见。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-10-08
    • 1970-01-01
    • 2012-05-28
    • 2019-07-11
    • 2015-02-17
    相关资源
    最近更新 更多