17

我一直在使用 PHPcrypt()作为在我的数据库中存储和验证密码的一种方式。我将散列用于其他事情,但crypt()用于密码。文档不是那么好,似乎有很多争论。我正在使用河豚和两种盐来加密密码并将其存储在数据库中。在我存储盐和加密密码之前(如加盐哈希)但意识到它是多余的,因为盐是加密密码字符串的一部分。

我对彩虹表攻击的工作方式有点困惑crypt(),无论如何从安全的角度来看这看起来是正确的。我使用第二个盐附加到密码以增加短密码的熵,可能有点过头了,但为什么不呢?

function crypt_password($password) {
if ($password) {
    //find the longest valid salt allowed by server
    $max_salt = CRYPT_SALT_LENGTH;

    //blowfish hashing with a salt as follows: "$2a$", a two digit cost parameter, "$", and 22 base 64
    $blowfish = '$2a$10$';

    //get the longest salt, could set to 22 crypt ignores extra data
    $salt = get_salt ( $max_salt );

    //get a second salt to strengthen password
    $salt2 = get_salt ( 30 ); //set to whatever


    //append salt2 data to the password, and crypt using salt, results in a 60 char output
    $crypt_pass = crypt ( $password . $salt2, $blowfish . $salt );

    //insert crypt pass along with salt2 into database.
    $sql = "insert into database....";

    return true;
    }
}  


function get_salt($length) {
$options = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789./';

$salt = '';

for($i = 0; $i <= $length; $i ++) {
    $options = str_shuffle ( $options );
    $salt .= $options [rand ( 0, 63 )];
}
return $salt;
}

function verify_password($input_password)
{
if($input_password)
{
    //get stored crypt pass,and salt2 from the database
    $stored_password = 'somethingfromdatabase';
    $stored_salt2 = 'somethingelsefromdatabase';

    //compare the crypt of input+stored_salt2 to the stored crypt password
    if (crypt($input_password . $stored_salt2, $stored_password) == $stored_password) {
        //authenticated
        return true;
    }
    else return false;
}
else return false;
}
4

5 回答 5

15

你真的应该看看 PHPASS:http ://www.openwall.com/phpass/这是一个使用 crypt() 的密码散列框架,用于 Wordpress 和 phpBB 等项目。

这个网站上还有一篇关于使用 crypt() 进行密码散列、加盐和拉伸的优秀文章:http ://www.openwall.com/articles/PHP-Users-Passwords

更新: 目前有一个 PHPASS 库的替代方案。在 PHP 的下一个版本中,有一些特殊的函数用于散列和验证密码(使用 bcrypt):http ://www.php.net/manual/en/ref.password.php 。有一个兼容性库可以为 PHP 5.3.7+ 实现这些功能:https ://github.com/ircmaxell/password_compat

于 2010-09-29T12:45:57.023 回答
11

Your use of crypt() is fine. crypt($input, $stored) == $stored is the way it is designed to be used.

Your get_salt() function is not great, since it is using the often-poor rand() function. You should consider using a stronger random function, like openssl_random_pseudo_bytes(), instead.

于 2010-09-30T07:00:09.040 回答
3

彩虹表的想法是攻击者可以在家中制作一个包含所有可能密码及其哈希值的表。

例如

PASSWORD HASH
iloveSO  gjroewjgo
password knbnogjwm
secret   gjroehghe
jbieber  rewgroewj

等等

使用此表,攻击者可以快速将任何散列转换为密码。Rainbow 表使用了一些技巧,因此不必存储所有哈希值,但它仍会预先计算所有哈希值。

通过使用盐,即使将其与密码一起存储,也会使这变得更加困难。攻击者现在不必对字典中的每个单词进行哈希处理,而是必须使用每个 salt对每个单词进行哈希处理。使用足够长的盐,这提供了足够的组合,使得计算所有这些散列变得不可行。

所以盐并不意味着是一个额外的密码,只有应用程序知道,它意味着改变散列函数,使其不标准。

于 2010-09-29T11:15:23.100 回答
2

这是对 crypt() 的误用,因为您使用的是已弃用的原语。Blowfish 已经很老了,twofish 是替代品,甚至那也很旧,因为threefish 几乎完成了。您应该使用 sha2 系列的成员,sha256 或 sha512 都是不错的选择。crypt() 可以与 sha256 或 sha512 一起使用,您应该分别使用 CRYPT_SHA256 CRYPT_SHA512 参数。

此外,您的盐的熵/大小比非常小,您只使用字母数字集,这是一个笑话,因为字母数字彩虹表是最常见的。您应该使用 base256 的完整字节,我建议使用 256 字节长的盐。请记住,根据定义,所有哈希函数都是二进制安全的,因此您不必担心空字节等。

于 2010-09-29T18:26:01.220 回答
0

Use SHA-512 (if available) with a salt which includes time() and openssl_random_pseudo_bytes(). Crypt is consolidated / efficient because it returns the salt inserted with the hashed string.

于 2012-06-12T17:42:38.820 回答