1

我想用 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);
}
4

1 回答 1

3

要么使用这个答案的建议(对于 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(),而不是从操作系统的源生成随机数,但这很容易改变。

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

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


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

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


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

于 2013-02-21T14:00:39.143 回答