PHP,MySQL - 我自己的SALT版本(我称之为咸) - 登录问题

时间:2012-06-30 01:54:51

标签: php mysql phpmyadmin

好的我写了我自己的SALT版本我称之为咸lol不要取笑我..无论如何我的脚本的注册部分如下工作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脚本失败了。如果它的登录与否,我将它设置为TEST并回显。它总是返回FAILED。我进入DB并将加密的咸pw改为“TEST”,我获得了成功。所以我的问题是在我假设的LOGIN脚本中的某个地方。现在我不知道如何实现我的$ Salty。但也请注意,即使没有SALTY(只使用crypt存储我的通行证) - 我仍然无法成功登录。如果你要建议我使用河豚 - 注意我的webhost没有支持它,我不知道如何安装它。

这是我的登录脚本:

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 /只存储crypt?

  2. 如何使其存储隐藏和随机生成的SALTY :)?

  3. Ty advance

3 个答案:

答案 0 :(得分:2)

每次运行此代码时,您将生成一个不同的salt值。因此,当首次存储密码时,您的盐将会(构成一些示例内容)abc。你隐藏了你的密码(比如说它是123,附上盐,最后是123abc,你存储在数据库中。

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

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

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

您所做的只是一些无用的随机数生成,只会增加您的CPU和存储开销,但不会增加安全性。

答案 1 :(得分:1)

所以在存储中你要加密'密码'然后追加$ salty(这是一个rand_string)

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

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

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

正如马克B在他的回答中所说,你应该在加密之前加盐。在真正没有保护密码之后追加它。

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

crypt($ password,$ salt);

我不会真的搞乱mysql_real_escape_string的密码,因为你正在加密它。由于你正在加密可能的顽皮字符串,因此没有任何关于注射的担忧。

答案 2 :(得分: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秒完成,所以根据你的情况,你可能想减少它;可以为更新的密码更改费用。

盐与密码btw一起存储,因此不需要另外一列。

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

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

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


您的salty()函数可以替换为以下等效函数以生成22个char长盐:

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

另请参阅:https://wiki.php.net/rfc/password_hash