【问题标题】:PHP Session: How to Edit Other user's Session / Editting Session filePHP Session:如何编辑其他用户的 Session / 编辑 Session 文件
【发布时间】:2019-03-28 22:39:31
【问题描述】:

编辑 - 2:请参阅 Sam 的案例解决方案。旧方法以及问题本身我仍然会留在这里,但是基于 Sam 的解决方案构建了一个新的解决方案,并且它可以在我保留的项目的 github 的存储库中获得

编辑 - 1:查看方法 destroy(id) 以了解解决方法

目前,我的系统在某些情况下需要使用新值更新其他用户会话。当前案例现在需要在执行某个操作时更改某些用户的会话文件中的单个值。 在我的项目中,我创建了一个实现 SessionHandlerInterface 的类 SessionHandlerCustom,并且我已经实现了一个为每个用户创建一个带有 Id 的自定义会话的逻辑。我可以访问自定义目录中的文件,但奇怪的是我不能对这些会话文件使用 file_put_contents 或 file_get_contents。我尝试使用 Session 函数,通过使用 SessionHandlerCustom 中提供的 read() 函数,我能够使用它的 SessionId 从用户会话中获取所有内容。

SessionFileGetValueByHashCode 的工作方法是从 Session 中获取内容的方法,并且使用一些 Key(通常是我想要在文件中的字段名称),它将获得确切的字符串那把钥匙和它的价值。 第二种方法根本不起作用,它实际上会更改 Session 中的值,但实际上并没有。我曾尝试直接操作文件但没有成功,并尝试使用 SessionHandlerCustom->write() 方法但没有效果。

谁能帮我解释一下改变/操纵其他用户会话的正确方法是什么?

系统示例:记录了一个普通用户,同时管理员使用管理功能并更改该用户的某些值。如果该值不是每次都从数据库中获取的值,则当前登录用户的会话变量需要更改其值。

如果你好奇,系统是开源的,你可以在这里访问它: https://github.com/msiqueira-dev/InfraTools

\*
This should be in the class that implements SessionHandlerInterface. This will actually delete the users session and force it to reload the whole session when it makes another request. The $SavePath variable is variable create and stored with the directory folder of the Session.
*/
public function destroy($id)
    {
        $file = $this->SavePath . "/sess_" . $id;
        if (file_exists($file)) 
            unlink($file);
        return true;
    }

SessionFileGetValueByHashCode

//The &$Value will be filled with the whole $Key and its values presented in the Session File. For example: SomeValue|s:0:"";
public function SessionFileGetValueByHashCode(&$Value, $Application, $SessionId, $Key)
{
        $Value = NULL;
        if(isset($Application) && !empty($Application) && isset($SessionId) && !empty($SessionId) && isset($Key) && !empty($Key))
        {
            $file = SESSION_PATH . $Application . "/sess_" . $SessionId;
            if(file_exists(($file)))
            {
                $str = $this->InstanceSessionHandlerCustom->read($SessionId);
                $start = strpos($str, $Key);
                $end=$start;
                while($str[$end] != '"')
                {
                    $Value .= $str[$end];
                    $end++;
                }
                $Value .= '"';
                $end++;
                while($str[$end] != '"')
                {
                    $Value .= $str[$end];
                    $end++;
                }
                $Value .= '"';
                if($Value != NULL)
                    return Config::RET_OK;
            }
        }
        return Config::RET_ERROR;
    }

SessionFileUpdateValueByHashCode

public function SessionFileUpdateValueByHashCode($Application, $SessionId, $OldValue, $NewValue)
    {
        if(isset($Application) && !empty($Application) && isset($SessionId) && !empty($SessionId) 
                               && isset($OldValue) && !empty($OldValue) && isset($NewValue) && !empty($NewValue))
        {
            $file = SESSION_PATH . $Application . "/sess_" . $SessionId;
            if(file_exists(($file)))
            {
                $str = $this->InstanceSessionHandlerCustom->read($SessionId);
                $str = str_replace($OldValue, $NewValue, $str, $count);
                if($count > 0)
                {
                    echo $str . "<br>";
                    if($this->InstanceSessionHandlerCustom->write($SessionId, $str))
                        return Config::RET_OK;
                }
            }
        }
        return Config::RET_ERROR;
    }

【问题讨论】:

    标签: php session


    【解决方案1】:

    可以修改其他用户会话(见下文),尽管我个人建议不要这样做。正如我想象的那样,它可以打开一个充满会话劫持和其他漏洞的世界。

    使用您的示例用例

    记录了一个普通用户,同时管理员使用管理员功能并更改该用户的某些值。如果该值不是每次都从数据库中获取的值,则当前登录用户的会话变量需要更改其值。

    您最好更新数据库中的值,然后在处理下一页之前检查它是否已更改。 如果您不想在每个页面加载之前检查多个用户字段,那么当您在管理面板中更新用户时,您可以构建值的哈希并将其添加到名为 session_hash 的新列中。然后在页面加载时比较这个字段

    但如果您仍想修改其他用户的会话,您可以将当前的session_id 设置为目标。

    // End my current session and save its id
    session_start();
    $my_session_id = session_id();
    session_write_close();
    
    // Modify our target session 
    session_id($target_id);
    session_start();
    $_SESSION['is_logged_in'] = false;
    session_write_close();
    
    // Start our old session again
    session_id($my_session_id);
    session_start();
    
    

    编辑

    示例:https://www.samdjames.uk/session_example/index.php

    示例源:https://gist.github.com/SamJUK/c220e3742487567c6262238edf85695e

    【讨论】:

    • 那么,如果你设置了一个 session_id,并且有一个有效的现有用户 id,我可以设置一个 session_start 并且当前会话将是 id 的用户而不是调用脚本的用户吗?那正确吗 ?很有趣,我错过了!谢谢
    • 正确,但不要忘记之后重置您的会话 ID。否则,您将在以后的脚本中继续使用其他用户的会话。我在上面的答案中添加了一个带有源的 poc 示例
    【解决方案2】:

    谁能帮我解释一下正确的方法 更改/操作其他用户的会话?

    正确的做法是:你没有

    会话旨在处理当前会话的数据,因此得名。如果您干扰其他人的会话,例如在您的示例中,管理员用户更改了用户的数据,然后立即更新,那么您几乎肯定会更好地使用不同的方法。

    例如,您:

    1. 可以使用 websocket 通知用户客户端有关更改
    2. 可以使用令牌来验证用户会话中的数据是否仍然有效
    3. 可以使用一些持久层(例如数据库)来传达更改

    当然还有更多的选择,我建议您重新考虑您的架构并想出不同的方法,而不是更改不同用户的会话。

    【讨论】:

    • 感谢您的评论,目前只有 2 个案例,并且都涉及管理员使用,这会改变用户会话。我可能确实会尝试使用令牌让受影响的用户创建一个新会话,我看到的唯一问题是用户必须再次登录。如果我继续走昨天的路,我可能会尝试使用 exec 或删除并重新创建文件。感谢您提供的所有选项。
    • 只是为了好奇。你知道为什么不能直接编辑 Session 文件吗?文件是否完全锁定?
    猜你喜欢
    • 2016-02-20
    • 2019-10-21
    • 1970-01-01
    • 2015-12-05
    • 2013-05-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-07-20
    相关资源
    最近更新 更多