【问题标题】:PHP Advanced Secure Session ClassPHP 高级安全会话类
【发布时间】:2012-06-29 16:35:44
【问题描述】:

在实习期间,我正在学习一个非常好的教程,为购物车制作高级 PHP 安全会话,这将为用户提供个人级别的定价(无论如何,这就是目标。)

这是教程: http://tutorial-resource.com/2011/10/a-secure-session-management-class-in-php/

首先,为了测试此会话,我创建了一个基于 Quickbooks 客户 ID 检查现有客户的原始登录。真正的处理使用注册、登录名和密码。然后我做了一个登录检查器,在 mysql 数据库中找到用户,找到后,逐页检索需要与用户保持一致的用户数据列。 (我保证在我完成这项工作后,我会进一步防止 SQL 注入。)我添加了一些额外的字段来存储在 SessionData 中。

<?php
    include "class.session.php";

    if(empty($_POST['customer_id']))
    {
        $this->HandleError("Customer ID is empty!");
        return false;
    }

    $customer_id = trim($_POST['customer_id']);
    $dbuser = "CENSORED";
    $dbpass = "CENSORED";
    $host = "localhost";
    $dbname = "CENSORED";

// database connection 
mysql_connect("localhost", $dbuser, $dbpass) or die(mysql_error());
mysql_select_db($dbname) or die("Unable to select database");

//This query grabs all the puchases going back up to three months
//This debug line displays the query
$query = "SELECT * FROM customers";
echo $query."<br>";

$found = 0;
$result = mysql_query($query);
while($row=mysql_fetch_array($result))
{
    //Grab the database pieces the customer will need throughout the page.
    echo "Checking customer number ".$row['customer_id']."<br>";
    if ($row['customer_id'] == $customer_id)
    {
        $found = 1;
        break;
    }

}

//-create while loop and loop through result set
if ($found == 0)
{
    echo 'Wrong customer number';
}

while($row=mysql_fetch_array($result))
{
    //Grab the database pieces the customer will need throughout the page.
    $customer_id = $row['customer_id'];
    $first_name = $row['first_name'];
    $last_name = $row['last_name'];
    $first_name = $row['price_level'];
}

//Give the user a session.
$sessions = new sessionsClass;
$sessions->_sessionStart();

$sessionInfo = $sessions->sessionCheck();

if( $sessionInfo = false )
{
      # This session is invalid. Tell the user.
}
else
{
      # Update the name.
      $sessionInfo->sessionData['customer_id'] = $customer_id;
      $sessionInfo->sessionData['company_name'] = $company_name;
      $sessionInfo->sessionData['first_name'] = $first_name;
      $sessionInfo->sessionData['last_name'] = $last_name;
      $sessionInfo->sessionData['price_level'] = $price_level;
      $sessionInfo->setSessionData();
      # Session is valid, can use the data.
      echo "Your name is ".$sessionInfo->sessionData['first_name']." ".$sessionInfo->sessionData['last_name']."<br>";
}

?>

成功登录后,我在 error_log 中看到一个错误,上面写着 “调用未定义的方法 stdClass::setSessionData()” 当函数明显存在时,直接从教程中取出: $sessionInfo->setSessionData();

为什么登录不能将 setSessionData 识别为未定义的方法而不是函数?
我不完全理解的一个线索是,它将 setSessionData 称为“未定义的方法 stdClass”,而不是“未定义的函数”。功能和教程很相似,只是连接到我的db:

public function setSessionData()
{
    $dbuser = "CENSORED";
    $dbpass = "CENSORED";
    $host = "localhost";
    $dbname = "CENSORED";

    // database connection 
    mysql_connect("localhost", $dbuser, $dbpass) or die(mysql_error());
    mysql_select_db($dbname) or die("Unable to select database");
    //Encrypt the data.
      $serialiseData = serialize( $this->sessionData );
    //Update the session data.
      mysql_query( "UPDATE sessions SET sessionData = '{$serialiseData}' WHERE sessionHash = '{$this->sessionHash}'" );

}

我的最后一个问题是,每个单独的页面需要什么才能安全地区分普通用户和登录用户,无论是哪个页面?是这样的吗?

if (sessionCheck == false)
{show ordinary stuff}
else if (sessionCheck == return true)
{show personalized stuff}

编辑本教程毕竟似乎有一些问题。例如,在教程接近尾声时。

# Session is valid, can use the data.
      echo "Your name is " . $sessionInfo->sessionData['fullname'];

      # Update the name.
      $sessionInfo->sessionData['fullname'] = "My New name";

      $sessionInfo->setSessionData();
}

这是错误的,因为 sessionInfo 是一个布尔值,旨在为 false 返回 true。相反,我将其替换为

$sessions->sessionData['customer_id'] = $customer_id;
$sessions->sessionData['company_name'] = $company_name;
$sessions->sessionData['first_name'] = $first_name;
$sessions->sessionData['last_name'] = $last_name;
$sessions->sessionData['price_level'] = $price_level;
$sessions->setSessionData();

但这仍然没有奏效。此外,本教程让人们创建了一个完整的 MySQL 数据库,但在课堂或教程中的任何地方都没有发生任何一次 INSERT。对现有会话进行 UPDATE 查询的功能是存在的,但没有用于创建新会话的功能。我可以添加什么来让数据库成功创建会话?

【问题讨论】:

  • 这个“安全”会话类在setSessionData 中有一个SQL injection vulnerability,因为会话ID 使用时没有经过适当的转义,可能源自cookie。

标签: php mysql security session login


【解决方案1】:

如果在反序列化期间找不到类,则序列化对象将转换为stdClass。我的猜测是,当您从数据库中读取会话信息并尝试将其放回 sessionClass 对象时,您还没有包含定义该类的文件。确保在反序列化之前 定义了类。

由于stdClass 没有名为setSessionData 的方法,您会收到“调用未定义方法”错误。方法是通常用来指代类中的函数的术语,而函数只是一个独立的函数定义。

要在每个页面上区分登录用户和普通用户,您通常需要启动会话并检查向您表明用户已通过身份验证的应用程序特定值。这可以像在会话中设置loggedIn 标志一样简单,或者存储更复杂的类型并检查其值。但基本上你需要在需要从登录用户中了解普通用户的每个页面上执行此操作。

希望对您有所帮助。

顺便说一句,如果您在代码开头调用$this-&gt;HandleError("Customer ID is empty!");,如果该块执行,您将收到一条错误消息,指出未定义$this。由于没有在类中调用该代码,因此没有 $this 的实例,因此您必须找出处理该错误的正确方法。

【讨论】:

  • 哇,我从来不知道序列化。由于类本身正在执行序列化和反序列化,因此类“包含自身”可以吗?登录肯定包括类文件。至于 HandleError,该代码是旧的。而且我现在已经用原始的回声代替了它。
  • 哎呀。我绝对不能让这个类包含它自己的文件。记忆变得疯狂。
  • 该类的另一个问题是在教程中的任何地方都没有发生任何类型的 mysql 插入。我不知道该类是否需要执行插入,或者该插入应该发生在登录脚本中。
猜你喜欢
  • 2017-10-15
  • 2012-07-22
  • 1970-01-01
  • 1970-01-01
  • 2011-11-06
  • 2020-04-16
  • 2011-02-11
相关资源
最近更新 更多