【问题标题】:PHP storing password with blowfish & salt & pepperPHP用河豚和盐和胡椒存储密码
【发布时间】:2013-02-22 02:22:03
【问题描述】:

我想用 PHP 将安全的用户密码存储在 MySQL 数据库中。

我怎样才能让它变得更好?

我的班级:

private static $algo = '$2a';
private static $cost = '$10';
private static $pepper = 'eMI8MHpEByw/M4c9o7sN3d';

public static function generateSalt($length) {
    $randomBinaryString = mcrypt_create_iv($length, MCRYPT_DEV_URANDOM);
    $randomEncodedString = str_replace('+', '.', base64_encode($randomBinaryString));
    return substr($randomEncodedString, 0, $length);
}

public static function generateHash($password) {
    if (!defined('CRYPT_BLOWFISH'))
        die('The CRYPT_BLOWFISH algorithm is required (PHP 5.3).');
    $password = hash_hmac('sha256', $password, self::$pepper, false);
    return crypt($password, self::$algo . self::$cost . '$' . self::generateSalt(22));
}

public static function checkPassword($hash, $password) {
    $salt = substr($hash, 0, 29);
    $password = hash_hmac('sha256', $password, self::$pepper, false);
    $new_hash = crypt($password, $salt);
    return ($hash == $new_hash);
}

【问题讨论】:

  • 虽然这在技术上是有答案的,但您的问题是相当武断和开放式的,应该改写以解决特定问题。
  • 对不起,这是我的第一个“问题”,下次我会做得更好!
  • 没问题;我给出了一个广泛的答案,并提供了一些关于散列和一般安全性的提示。
  • 看看answer中新的PHP函数password_hash()password_verify()的使用。
  • 这不应该在 Code Review SE 中吗?

标签: php hash salt blowfish crypt


【解决方案1】:

要么使用this 答案的建议(对于 PHP >= 5.5),要么使用以下类。感谢martinstoeckli 指出password_hash 函数。我阅读了代码,在password_hash 中我能看到的唯一不同之处是错误检查和来自操作系统的DEV_URANDOM 使用以生成更随机的盐。

class PassHash {
    public static function rand_str($length) {
        $chars = "0123456789./qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM";
        //only allowed chars in the blowfish salt.
        $size = strlen($chars);
        $str = "";
        for ($i = 0; $i < $length; $i++)
            $str .= $chars[rand(0, $size - 1)]; // hello zend and C.
        return $str;
    }
    public static function hash($input) {
        return crypt($input, "$2y$13$" . self::rand_str(22));
        // 2y is an exploit fix, and an improvement over 2a. Only available in 5.4.0+
    }
    public static function hash_weak($input) {
        return crypt($input, "$2a$13$" . self::rand_str(22)); }
        // legacy support, Add exception handling and fall back to <= 5.3.0
    public static function compare($input, $hash) {
        return (crypt($input, $hash) === $hash);
    }
}

这是我一直使用的。一个建议也是PHPass。它已经过试验和测试。


这个脚本唯一的缺点是我从rand() 生成随机数,而不是来自操作系统的源,但这很容易改变。

此外,没有真正的理由在 bcrypt 之上使用 SHA256 散列。 SHA256 很弱,可以用相对较少的努力破解3

此外,散列密码是必不可少的做法,但为了真正的安全,运行所有输入至少通过John the Ripperwordlist1通用密码并通知用户使用不同的密码。由于密码非常弱,单词列表的使用比任何暴力破解都有效得多。


最后一点,不要强迫您的用户使用符号、大写字母和数字,而是要强迫他们使用长密码2

在暴力破解密码方面,长度就是一切(无意幽默)。除非编辑配置,否则几乎所有预设破解程序都将设置为不超过 12 个字符。如果您看到某个网站的密码具有“最大长度”,请确保永远不要在那里重复使用密码,因为它们没有任何安全性4


1.饼干的任意选择;选择你认为最有效的方法
2.http://xkcd.com/936/
3. 相对而言(它的速度要快几个数量级,并且通过默默无闻在技术上是安全的)
4. 我什至见过银行这样做。他们的密码有最大长度让我换了银行。

【讨论】:

  • 非常感谢您的好提示,我会考虑这个。
  • @FillipPeyton bcrypt 哈希与它们一起存储盐。只需将输入传递给::Compare(),它在我使用它的五个站点(example here)中运行良好 - 分别要求盐、胡椒、哈希和选项是我没有做过的事情......曾经.
  • @FillipPeyton 哈希和盐在同一个字符串中。格式为$&lt;cipher&gt;$&lt;cost&gt;$&lt;salt&gt;&lt;hash&gt;。存储并比较;它就像PassHash::Compare($password_input, $hash_from_database); //true if correct else false 一样简单。你想太多了。
猜你喜欢
  • 2021-10-02
  • 2013-02-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-08-31
  • 1970-01-01
  • 2016-02-29
相关资源
最近更新 更多