2

好的,我编写了自己的 SALT 版本,我称之为咸味,哈哈,不要取笑我。无论如何,我的脚本的注册部分如下所示是 100% 正确工作的。

    //generate SALTY my own version of SALT and I likes me salt.. lol
    function rand_string( $length ) {
        $chars = "ABCDEFGHIJKLMNOPQRSTUWXYZabcdefghijklmnopqrstuwxyz1234567890";
        $size = strlen( $chars );
        for( $i = 0; $i < $length; $i++ ) {
            $str .= $chars[ rand( 0, $size - 1 ) ];
        }
        return $str;
    } 
    $salty = rand_string( 256 );

    //generate my extra salty pw 
    $password = crypt('password');
    $hash = $password . $salty;
    $newpass = $hash;

    //insert the data in the database
    include ('../../scripts/dbconnect.php');

    //Update db record with my salty pw ;)
                                           // TESTED WITH AND WITHOUT SALTY 
                                          //HENCE $password and $newpass
    mysql_query("UPDATE `Register` SET `Password` = '$password' WHERE `emailinput` = '$email'");
    mysql_close($connect);

但是我的 LOGIN 脚本失败了。我将其设置为测试并回显是否登录。它总是返回失败。我进入数据库并将加密的咸密码更改为“测试”,我得到了成功。所以我的问题出在我假设的这个 LOGIN 脚本中。现在我不确定如何在其中实现我的 $Salty。但也请注意,即使没有 SALTY(仅使用 crypt 存储我的通行证) - 我仍然无法成功登录。如果你建议我使用河豚 - 请注意我的虚拟主机不支持它,我不知道如何安装它。

这是我的登录脚本:

if (isset($_POST['formsubmitted'])) 
{
include ('../../scripts/dbconnect.php');

$username = mysql_real_escape_string($_POST['username']);
$password = crypt(mysql_real_escape_string($_POST['password']));

$qry = "SELECT ID FROM Register WHERE emailinput='$username' AND Password='$password'"; 
$result = mysql_query($qry);

if(mysql_num_rows($result) > 0) 
{
    echo 'SUCCESS';
    //START SESSION
}
else
{
    echo 'FAILED';
    //YOU ARE NOT LOGGED IN     
}
}
  1. 那么这个登录有什么问题呢?为什么仅使用 crypt/storing only crypt 不起作用?

  2. 我怎样才能让它同时存储 crypt 和随机生成的 SALTY :) ?

泰前进

4

3 回答 3

2

每次运行此代码时,您都会生成一个不同的盐值。所以当密码第一次被存储时,你的盐将是(组成一些例子)abc。你加密你的密码(假设它是123,附加盐,最后是123abc,你存储在数据库中。

当您下次尝试登录时,您会生成一个新的随机盐(例如456)。你加密密码,附加盐,现在你得到了123456. 还有你的问题。现在你有两个完全不同的字符串,所以你的登录失败了。

您需要将盐与加密文本分开存储,以便稍后再次使用盐。这意味着您的登录脚本首先必须检索与尝试登录的任何用户关联的盐,重新加密/盐他们输入的密码,并查看字符串是否匹配。

从更大的角度来看,您还错误地使用了盐渍。在通过 crypt 运行密码之前,必须将盐添加到密码中。盐可以增加暴力破解密码的难度。123是一个简单的密码,但123big_long_ugly_salt_value不是。

你所做的只是一些无用的随机数生成,只会增加你的 CPU 和存储开销,但对提高安全性没有任何作用。

于 2012-06-30T02:19:14.070 回答
1

因此,在存储中,您要加密“密码”,然后附加 $salty(这是一个 rand_string)

但是,在稍后的密码比较中,您将加密 $_POST['password'],而不是附加相同的随机字符串。所以他们不会是一样的。

不是在每个密码存储过程中随机生成盐,而是最终将盐存储在某个地方,或者从以后可以确保再次找到的东西创建盐,以便在再次登录时进行比较。

如果您希望每个用户使用不同的盐,那么您可以使用用户 ID 或其他一些不会更改为您的盐的信息,关于如何让这个现在工作的一些想法。或者,如果这无关紧要,您可以使用自己的其他随机字符串来使用。

正如马克 B 在他的回答中所说,你应该在加密之前添加盐。在确实不保护密码之后添加它。

使用 crypt 函数时,您可以在函数调用中添加盐:

地穴($密码,$盐);

而且我不会真正弄乱密码的 mysql_real_escape_string ,因为您正在加密它。由于您正在加密可能的顽皮字符串,因此不必担心注入。

于 2012-06-30T01:58:26.423 回答
0

我将对您的代码进行以下调整:

function rand_string( $length ) {
    // added period and slash to the alphabet
    $chars = "ABCDEFGHIJKLMNOPQRSTUWXYZabcdefghijklmnopqrstuwxyz1234567890./";
    $size = strlen( $chars );
    for( $i = 0; $i < $length; $i++ ) {
        $str .= $chars[ rand( 0, $size - 1 ) ];
    }
    return $str;
}

// we need 22 random characters
$salty = rand_string(22);
// apply blowfish with cost := 13
$newpass = crypt($password, sprintf('$2y$%02d$%s', 13, $salty));

这使用 Blowfish 对您的密码进行哈希处理;在强度 13 时完成大约需要 0.5 秒,因此根据您的情况,您可能希望减少它;成本可以更改为较新的密码。

salt 与密码 btw 一起存储,因此无需为此设置另一列。

要验证数据库中的密码,您必须首先从相应Register行加载密码字段。

if (crypt($_POST['password'], $password_from_db) === $password_from_db) {
    // success
} else {
    // password didn't match
}

顺便说一句,比较函数经常变成一个恒定时间算法来防止定时攻击。


您的salty()函数可以替换为以下等价物以产生 22 char long salts:

substr(strtr(base64_encode(openssl_pseudo_random_bytes(18)), '+', '.'), 0, 22);

另见:https ://wiki.php.net/rfc/password_hash

于 2012-06-30T03:10:48.290 回答