Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/security/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
PHP会话和会话重新生成id_Php_Security_Session - Fatal编程技术网

PHP会话和会话重新生成id

PHP会话和会话重新生成id,php,security,session,Php,Security,Session,我已经尝试解决这个问题好几个星期了。 我已经创建了一个保护PHP会话的类,它可以正常工作,除非有人试图执行注册(问题是#2),如果某些功能被禁用(导致#2发生),网站的其余部分也可以正常工作 问题就在这里: <?php Class Session { public static $DBConnection; private static $SessionCreated = false; public function __construct($Database

我已经尝试解决这个问题好几个星期了。
我已经创建了一个保护PHP会话的类,它可以正常工作,除非有人试图执行注册(问题是#2),如果某些功能被禁用(导致#2发生),网站的其余部分也可以正常工作

问题就在这里:

<?php

Class Session
{

    public static $DBConnection;
    private static $SessionCreated = false;

    public function __construct($Database)
    {
        session_set_save_handler(array($this, 'Open'), array($this, 'Close'), array($this, 'Read'), array($this, 'Write'), array($this, 'Destroy'), array($this, 'GarbageCollector'));
        register_shutdown_function('session_write_close');
        Session::$DBConnection = $Database::$Connection;
    }

    private static function GenerateSessionData()
    {
        $_SESSION['loggedin'] = '';
        $_SESSION['username'] = '';
        $_SESSION['remember_me'] = '';
        $_SESSION['preferredlanguage'] = '';
        $_SESSION['generated_captcha'] = '';
    }

    public static function UpdateSession($Data)
    {
        if(!isset($_SESSION['loggedin']))
            Session::GenerateSessionData();
        foreach($Data as $key=>$value)
            $_SESSION[$key] = $value;
    }

    public static function GenerateCSRFToken()
    {
        $InitialString = "abcdefghijklmnopqrstuvwxyz1234567890";
        $PartOne = substr(str_shuffle($InitialString),0,8);
        $PartTwo = substr(str_shuffle($InitialString),0,4);
        $PartThree = substr(str_shuffle($InitialString),0,4);
        $PartFour = substr(str_shuffle($InitialString),0,4);
        $PartFive = substr(str_shuffle($InitialString),0,12);
        $FinalCode = $PartOne.'-'.$PartTwo.'-'.$PartThree.'-'.$PartFour.'-'.$PartFive;
        $_SESSION['generated_csrf'] = $FinalCode;
        return $FinalCode;
    }

    public static function ValidateCSRFToken($Token)
    {
        if(isset($Token) && $Token == $_SESSION['generated_csrf'])
        {
            unset($_SESSION['generated_csrf']);
            return true;
        }
        else
            return false;
    }

    public static function UnsetKeys($Keys)
    {
        foreach($Keys as $Key)
            unset($_SESSION[$Key]);
    }

    public static function Start($SessionName, $Secure)
    {
        $HTTPOnly = true;
        $Session_Hash = 'sha512';

        if(in_array($Session_Hash, hash_algos()))
            ini_set('session.hash_function', $Session_Hash);
        ini_set('session.hash_bits_per_character', 6);
        ini_set('session.use_only_cookies', 1);

        $CookieParameters = session_get_cookie_params();

        session_set_cookie_params($CookieParameters["lifetime"], $CookieParameters["path"], $CookieParameters["domain"], $Secure, $HTTPOnly);
        session_name($SessionName);
        session_start();
        session_regenerate_id(true);
        if(!Session::$SessionCreated)
            if(!isset($_SESSION['loggedin']))
                Session::GenerateSessionData();
        Session::$SessionCreated = true;
    }

    static function Open()
    {
        if(is_null(Session::$DBConnection))
        {
            die("Unable to establish connection with database for Secure Session!");
            return false;
        }
        else
            return true;
    }

    static function Close()
    {
        Session::$DBConnection = null;
        return true;
    }

    static function Read($SessionID)
    {
        $Statement = Session::$DBConnection->prepare("SELECT data FROM sessions WHERE id = :sessionid LIMIT 1");
        $Statement->bindParam(':sessionid', $SessionID);
        $Statement->execute();
        $Result = $Statement->fetch(PDO::FETCH_ASSOC);
        $Key = Session::GetKey($SessionID);
        $Data = Session::Decrypt($Result['data'], $Key);
        return $Data;
    }

    static function Write($SessionID, $SessionData)
    {
        $Key = Session::GetKey($SessionID);
        $Data = Session::Encrypt($SessionData, $Key);

        $TimeNow = time();

        $Statement = Session::$DBConnection->prepare('REPLACE INTO sessions (id, set_time, data, session_key) VALUES (:sessionid, :creation_time, :session_data, :session_key)');
        $Statement->bindParam(':sessionid', $SessionID);
        $Statement->bindParam(':creation_time', $TimeNow);
        $Statement->bindParam(':session_data', $Data);
        $Statement->bindParam(':session_key', $Key);
        $Statement->execute();
        return true;
    }

    static function Destroy($SessionID)
    {
        $Statement = Session::$DBConnection->prepare('DELETE FROM sessions WHERE id = :sessionid');
        $Statement->bindParam(':sessionid', $SessionID);
        $Statement->execute();
        Session::$SessionCreated = false;
        return true;
    }

    private static function GarbageCollector($Max)
    {
        $Statement = Session::$DBConnection->prepare('DELETE FROM sessions WHERE set_time < :maxtime');
        $OldSessions = time()-$Max;
        $Statement->bindParam(':maxtime', $OldSessions);
        $Statement->execute();
        return true;
    }

    private static function GetKey($SessionID)
    {
        $Statement = Session::$DBConnection->prepare('SELECT session_key FROM sessions WHERE id = :sessionid LIMIT 1');
        $Statement->bindParam(':sessionid', $SessionID);
        $Statement->execute();
        $Result = $Statement->fetch(PDO::FETCH_ASSOC);
        if($Result['session_key'] != '')
            return $Result['session_key'];
        else
            return hash('sha512', uniqid(mt_rand(1, mt_getrandmax()), true));
    }

    private static function Encrypt($SessionData, $SessionKey)
    {
        $Salt = "06wirrdzHDvc*t*nJn9VWIfET+|co*pm~CbtT5P*S2IPD-VmEfd+CX2wrvZ";
        $SessionKey = substr(hash('sha256', $Salt.$SessionKey.$Salt), 0, 32);
        $Get_IV_Size = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_ECB);
        $IV = mcrypt_create_iv($Get_IV_Size, MCRYPT_RAND);
        $Encrypted = base64_encode(mcrypt_encrypt(MCRYPT_RIJNDAEL_256, $SessionKey, $SessionData, MCRYPT_MODE_ECB, $IV));
        return $Encrypted;
    }

    private static function Decrypt($SessionData, $SessionKey)
    {
        $Salt = "06wirrdzHDvc*t*nJn9VWIfET+|co*pm~CbtT5P*S2IPD-VmEfd+CX2wrvZ";
        $SessionKey = substr(hash('sha256', $Salt.$SessionKey.$Salt), 0, 32);
        $Get_IV_Size = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_ECB);
        $IV = mcrypt_create_iv($Get_IV_Size, MCRYPT_RAND);
        $Decrypted = mcrypt_decrypt(MCRYPT_RIJNDAEL_256, $SessionKey, base64_decode($SessionData), MCRYPT_MODE_ECB, $IV);
        return $Decrypted;
    }
}

?>
  • 会话\u重新生成\u id-已注释掉
    从这里开始,一切正常,除了captcha创建机制(仅在注册页面上),对于登录页面,一切正常
  • 会话\u重新生成\u id(true)-未注释
    在这里,注册工作正常,没有问题,没有验证码问题,但在页面刷新几次后,会话就消失了,所以用户需要再登录6次刷新,$\u会话再次设置为空
  • 我知道问题可能在哪里,但我不知道如何解决它

    我有一个私有静态函数,在调用session_start()之后直接调用它

    private static function GenerateSessionData()
    {
        $_SESSION['loggedin'] = '';
        $_SESSION['username'] = '';
        $_SESSION['remember_me'] = '';
        $_SESSION['preferredlanguage'] = '';
        $_SESSION['generated_captcha'] = '';
    }
    
    这样做是为了预先定义会话要使用的变量(我90%确信这就是会话之后变为空白的原因)。
    我不确定的是为什么

    这是完整的课程:

    <?php
    
    Class Session
    {
    
        public static $DBConnection;
        private static $SessionCreated = false;
    
        public function __construct($Database)
        {
            session_set_save_handler(array($this, 'Open'), array($this, 'Close'), array($this, 'Read'), array($this, 'Write'), array($this, 'Destroy'), array($this, 'GarbageCollector'));
            register_shutdown_function('session_write_close');
            Session::$DBConnection = $Database::$Connection;
        }
    
        private static function GenerateSessionData()
        {
            $_SESSION['loggedin'] = '';
            $_SESSION['username'] = '';
            $_SESSION['remember_me'] = '';
            $_SESSION['preferredlanguage'] = '';
            $_SESSION['generated_captcha'] = '';
        }
    
        public static function UpdateSession($Data)
        {
            if(!isset($_SESSION['loggedin']))
                Session::GenerateSessionData();
            foreach($Data as $key=>$value)
                $_SESSION[$key] = $value;
        }
    
        public static function GenerateCSRFToken()
        {
            $InitialString = "abcdefghijklmnopqrstuvwxyz1234567890";
            $PartOne = substr(str_shuffle($InitialString),0,8);
            $PartTwo = substr(str_shuffle($InitialString),0,4);
            $PartThree = substr(str_shuffle($InitialString),0,4);
            $PartFour = substr(str_shuffle($InitialString),0,4);
            $PartFive = substr(str_shuffle($InitialString),0,12);
            $FinalCode = $PartOne.'-'.$PartTwo.'-'.$PartThree.'-'.$PartFour.'-'.$PartFive;
            $_SESSION['generated_csrf'] = $FinalCode;
            return $FinalCode;
        }
    
        public static function ValidateCSRFToken($Token)
        {
            if(isset($Token) && $Token == $_SESSION['generated_csrf'])
            {
                unset($_SESSION['generated_csrf']);
                return true;
            }
            else
                return false;
        }
    
        public static function UnsetKeys($Keys)
        {
            foreach($Keys as $Key)
                unset($_SESSION[$Key]);
        }
    
        public static function Start($SessionName, $Secure)
        {
            $HTTPOnly = true;
            $Session_Hash = 'sha512';
    
            if(in_array($Session_Hash, hash_algos()))
                ini_set('session.hash_function', $Session_Hash);
            ini_set('session.hash_bits_per_character', 6);
            ini_set('session.use_only_cookies', 1);
    
            $CookieParameters = session_get_cookie_params();
    
            session_set_cookie_params($CookieParameters["lifetime"], $CookieParameters["path"], $CookieParameters["domain"], $Secure, $HTTPOnly);
            session_name($SessionName);
            session_start();
            session_regenerate_id(true);
            if(!Session::$SessionCreated)
                if(!isset($_SESSION['loggedin']))
                    Session::GenerateSessionData();
            Session::$SessionCreated = true;
        }
    
        static function Open()
        {
            if(is_null(Session::$DBConnection))
            {
                die("Unable to establish connection with database for Secure Session!");
                return false;
            }
            else
                return true;
        }
    
        static function Close()
        {
            Session::$DBConnection = null;
            return true;
        }
    
        static function Read($SessionID)
        {
            $Statement = Session::$DBConnection->prepare("SELECT data FROM sessions WHERE id = :sessionid LIMIT 1");
            $Statement->bindParam(':sessionid', $SessionID);
            $Statement->execute();
            $Result = $Statement->fetch(PDO::FETCH_ASSOC);
            $Key = Session::GetKey($SessionID);
            $Data = Session::Decrypt($Result['data'], $Key);
            return $Data;
        }
    
        static function Write($SessionID, $SessionData)
        {
            $Key = Session::GetKey($SessionID);
            $Data = Session::Encrypt($SessionData, $Key);
    
            $TimeNow = time();
    
            $Statement = Session::$DBConnection->prepare('REPLACE INTO sessions (id, set_time, data, session_key) VALUES (:sessionid, :creation_time, :session_data, :session_key)');
            $Statement->bindParam(':sessionid', $SessionID);
            $Statement->bindParam(':creation_time', $TimeNow);
            $Statement->bindParam(':session_data', $Data);
            $Statement->bindParam(':session_key', $Key);
            $Statement->execute();
            return true;
        }
    
        static function Destroy($SessionID)
        {
            $Statement = Session::$DBConnection->prepare('DELETE FROM sessions WHERE id = :sessionid');
            $Statement->bindParam(':sessionid', $SessionID);
            $Statement->execute();
            Session::$SessionCreated = false;
            return true;
        }
    
        private static function GarbageCollector($Max)
        {
            $Statement = Session::$DBConnection->prepare('DELETE FROM sessions WHERE set_time < :maxtime');
            $OldSessions = time()-$Max;
            $Statement->bindParam(':maxtime', $OldSessions);
            $Statement->execute();
            return true;
        }
    
        private static function GetKey($SessionID)
        {
            $Statement = Session::$DBConnection->prepare('SELECT session_key FROM sessions WHERE id = :sessionid LIMIT 1');
            $Statement->bindParam(':sessionid', $SessionID);
            $Statement->execute();
            $Result = $Statement->fetch(PDO::FETCH_ASSOC);
            if($Result['session_key'] != '')
                return $Result['session_key'];
            else
                return hash('sha512', uniqid(mt_rand(1, mt_getrandmax()), true));
        }
    
        private static function Encrypt($SessionData, $SessionKey)
        {
            $Salt = "06wirrdzHDvc*t*nJn9VWIfET+|co*pm~CbtT5P*S2IPD-VmEfd+CX2wrvZ";
            $SessionKey = substr(hash('sha256', $Salt.$SessionKey.$Salt), 0, 32);
            $Get_IV_Size = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_ECB);
            $IV = mcrypt_create_iv($Get_IV_Size, MCRYPT_RAND);
            $Encrypted = base64_encode(mcrypt_encrypt(MCRYPT_RIJNDAEL_256, $SessionKey, $SessionData, MCRYPT_MODE_ECB, $IV));
            return $Encrypted;
        }
    
        private static function Decrypt($SessionData, $SessionKey)
        {
            $Salt = "06wirrdzHDvc*t*nJn9VWIfET+|co*pm~CbtT5P*S2IPD-VmEfd+CX2wrvZ";
            $SessionKey = substr(hash('sha256', $Salt.$SessionKey.$Salt), 0, 32);
            $Get_IV_Size = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_ECB);
            $IV = mcrypt_create_iv($Get_IV_Size, MCRYPT_RAND);
            $Decrypted = mcrypt_decrypt(MCRYPT_RIJNDAEL_256, $SessionKey, base64_decode($SessionData), MCRYPT_MODE_ECB, $IV);
            return $Decrypted;
        }
    }
    
    ?>
    
    
    
    我不能排除私有静态函数(第一个提到的),因为我不能设置变量

    您可能会说:‘但是有一个UpdateSession方法’…
    是 啊有点。。。。但问题是,由于我的知识不足,我把脚本搞砸了,逻辑出了问题

    以下是链接(可能简化理解):
    -会话类
    -验证码生成(指向精确的行)
    -帐户创建过程(仅适用于会话\u重新生成\u id)
    -验证码显示过程(在某些情况下始终有效)
    -执行登录案例(由于某种原因,在任何情况下都不会出现问题)

    如果您喜欢super,请对它的实际工作方式感兴趣(我指的是它在4次刷新后如何取消用户权限)

    用户名:测试
    密码:123456

    所以问题是: 如何修改我的类,如何使用当前方法使用session_regenerate_id(true)保存会话数据,以及如何防止在调用session_regenerate_id后刷新会话数据

    这些链接直接指向脚本的问题区域。
    非常感谢您的帮助


    非常感谢您的帮助

    您正在经历我称之为的Cookie竞争状况

    当您使用
    session\u regenate\u id(true)
    PHP为每个请求创建一个新会话id(包含旧会话的数据),并从数据库中删除旧会话

    现在,您的网站包含许多需要加载的元素,例如
    /pager.php
    /data/menu.json
    。每次为浏览器分配一个新的会话id。通常不会有问题,但现代浏览器会并行处理请求:

  • 使用
    session\u id=a请求
    pager.php
  • data/menu.json
    是通过
    session\u id=a
  • pager.php
    删除
    sessions\u id=a
    并将
    session\u id=b
    返回到我的浏览器
  • data/menu.json
    在数据库中找不到
    session\u id=a
    ,假设我是新访问者,并给我
    session\u id=c
  • 现在,它取决于浏览器以何种顺序接收和解析哪个请求

    案例A
    数据/菜单。首先解析json
    :浏览器存储
    会话id=c
    。然后解析
    pager.php
    的响应,浏览器用b覆盖会话id。对于任何下一个请求,它将使用
    session\u id=b

    案例B
    pager.php
    首先被解析,然后是
    data/menu.json
    。浏览器现在存储
    session\u id=c
    ,您将注销

    这就解释了为什么它有时有效(例如,4或6次刷新),有时无效

    结论:不要使用
    session_regenate_id()没有很好的理由


    请提出一个新问题,为什么captcha创建机制在注册页面上不起作用,而是在登录页面上起作用


    关于加密的一些注意事项

  • 不要在ECB模式下使用AES。这会削弱加密
  • 您将加密密钥存储在数据旁边。你的加密系统刚刚坏了

  • 这个问题不是很清楚。读了你的问题后,我有点困惑。@JijoJohn我已经用问题部分更新了主题