【问题标题】:PHP: Hashing code not working any longer?PHP:散列代码不再工作?
【发布时间】:2011-10-03 14:39:45
【问题描述】:

我使用了一段时间的这个哈希函数(从互联网上得到它)。问题是它曾经可以立即工作,但现在它正在抱怨一个参数。以下是代码:

function generateHash($plainText, $salt = null)
{

    if ($salt === null)
    {
        $salt = substr(md5(uniqid(rand(), true)), 0, SALT_LENGTH);
    }
    else
    {
        $salt = substr($salt, 0, SALT_LENGTH);
    }
    return $salt . sha1($salt . $plainText);
}

所以我会在方法调用中使用这段代码:

validateUserInput($userid, $pass);

而 validateUserInput 是:

function validateUserInput($username, $password)
{
    //$username = mysql_real_escape_string($username);
    //$password = mysql_real_escape_string($password);

    if(!$username || !$password)
    {
        //$errors['credentials'] = 'Missing Credentials!';
        //$_SESSION['errors_array'] = $errors;
        //echo $errors['credentials'];
        header("LOCATION:XXXXXXX.php");
    }

    $local_salt = generateHash($password);
    //echo $local_salt;
    $groupid;

    if($username != null && $password !=null)
    {   
        connectToServer();
        $result = mysql_query("SELECT * FROM users WHERE hashkey = '{$local_salt}'");

        while($row_access = mysql_fetch_array($result))
        {
            $groupid = $row_access['groupid'];
        }
        if(!isset($result))
        {
            $errors['not_found_user'] = 'No Users Found with Provided Credentials!';
            //$_SESSION['errors_array'] = $errors;
            $userfound = 0;
            $_SESSION['user_available'] = $userfound;
        }elseif(isset($result)){
            $_SESSION['user_logged'] = array('username' => $username, 'password' => $password, 'salt' => $local_salt, 'groupid' => $groupid);
            $userfound = 1;
            //echo "stored";
            $_SESSION['user_available'] = $userfound;
        }       
    }
}

最后的错误是:

Warning: substr() expects parameter 3 to be long, string given in /home/XXXX.php on line 64

这是指向函数generateHash()

【问题讨论】:

    标签: php hash


    【解决方案1】:

    错误本身会告诉你一切。常量SALT_LENGTH 不是long。我怀疑它根本没有定义,所以 PHP 将裸字符串转换为字符串 ("SALT_LENGTH") 并将 that 传递给 substr(),这会报错。

    话虽这么说...这段代码错误的很危险:

    1. if(!isset($result)): 真的吗?这个条件将总是为假,因为$result总是被设置(除非你遇到mysql_query()的问题,但这并没有告诉你任何关于登录的有效性)。由于mysql_query() 永远不会返回null,因此不会拒绝任何登录。

    2. 这个查询:

      SELECT * FROM users WHERE hashkey = '{$local_salt}'
      

      无效。 $local_salt = generateHash($password);。在generateHash 函数中,如果没有给出盐,则会为您随机创建一个盐。因此,每次调用generateHash 都会生成一个新的哈希,这意味着它无法与数据库中的任何内容进行比较。

    基于上述两个(非常)严重的错误,我将永远丢弃这段代码。


    使用盐时检查有效哈希的正确方法如下:

    $_SESSION['user_logged'] = null;
    
    // fetch hashed pw from db, where username is the submitted username
    $result = mysqli_query("SELECT hash FROM users WHERE username = '{$username}'");
    
    if ($result->num_rows != 0) 
    {
         $row = $result->fetch_assoc();    
         $hash = $row['hash'];
    
         $salt = substr($hash, 0, SALT_LENGTH); // extract salt 
    
         if (generateHash($password, $salt) == $hash) 
         {
             // login successful. 
             $_SESSION['user_logged'] = $username; // don't store passwords here
         }
    }
    
    // if $_SESSION['user_logged'] is not set, the login failed
    if (!isset($_SESSION['user_logged'])) 
    {
        // you *don't* want to tell people which one (login or pw) is invalid
        echo 'Invalid login or password';
    }
    

    注意:SALT_LENGTH 最多为 32 非常重要,否则由于generateHash() 的实现方式,这将不起作用。

    【讨论】:

    • 感谢 cmets。谢谢,并将继续努力。尽管如此,您的评论与我的问题无关,这就是为什么一段一直有效的代码会停止工作!
    • @sys_debug 阅读第一段。我猜它以前可以工作,因为您在另一个文件中定义了SALT_LENGTH,现在由于某种原因而丢失了。无论如何,我要指出的是,即使它以前“工作”过,它也没有做正确的事情。
    • 谢谢,非常感谢您的帮助。现在改变它。确保避免上面概述的陷阱:)
    • 好的,在考虑您的实施之前,我做了以下事情:(请告知我是否可行)
    【解决方案2】:

    显然SALT_LENGTH 不是整数。找到它的定义并更正它。

    【讨论】:

    • 是的,我知道,但它曾经一直有效!我尝试通过使用 strlen(salt) 来定义它,但没有奏效,因为 salt 在进入函数时为空并在函数中生成。
    【解决方案3】:

    不要在每次编写应用程序时创建一个新的散列函数,而应该使用 php 提供给你的散列函数:crypt()(我建议使用任何河豚或 sha256+ 散列)。

    当从数据库中选择信息时,你应该通过用户名选择它,然后用php检查hash是否适合密码。

    【讨论】:

    • 我现在已经开始这样做了...进行到一半...正如您所说,我现在正在检查用户名,然后验证哈希密码
    • @sys_debug ,哦,看看PDO 和准备好的语句。首先,因为mysql_* 函数很古老,很快就会被弃用,其次 - 如果使用正确,准备好的语句几乎不可能在您的代码中进行 SQL 注入。这么说吧:在使用prepared statements时,您需要一种特殊的才能来创建sql漏洞。
    猜你喜欢
    • 2016-06-13
    • 1970-01-01
    • 2016-01-28
    • 2019-03-30
    • 1970-01-01
    • 2016-05-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多