【问题标题】:PHP $_SESSION AND $_COOKIE Strange behaviorPHP $_SESSION 和 $_COOKIE 奇怪的行为
【发布时间】:2020-06-30 11:21:57
【问题描述】:

我正在尝试将 COOKIES 安装到我的网站中。
我在 GitHub 上找到了一个脚本:https://github.com/jotaroita/secure-login-php7-remember-register-resetpw

我已经实现了脚本并且可以登录了。
我可以只使用 SESSION 登录,或者我可以同时使用 SESSION 登录并设置“记住我 -COOKIE”。

为了测试 COOKIE,我将 SESSION 设置为 1 分钟后过期。 $expireAfter = 1;

塞纳里奥:
我登录网站并勾选“记住我”。会话开始并设置了 cookie。一切正常!
## last action: 1 seconds ago skip the cookie check: session already set

我等待 60 秒并重新加载页面。会话销毁并且 Cookie 读取:
## last action: 108 seconds ago session destroy for inactivity cookie read cookie valid format cookie right selector cookie right token set a new token in DB and in cookie session set $_SESSION['user']
但是在我的其他页面(home.php)$_SESSION['user'] 是空的?! (我包括来自:check.php 的 SESSION 和 COOKIE 检查)if(isset($_SESSION['last_action'])){ 返回 true

如果我再等 60 秒并重新加载页面 if(isset($_SESSION['last_action'])){ 将返回 false。但现在$_SESSION['user'] 已设置。

如果我再等 60 秒并重新加载页面。 if(isset($_SESSION['last_action'])){ 返回真。但是现在$_SESSION['user'] 是空的。

home.php

<?php
//START SESSION
session_start();

//CONNECT TO DB, SET HEADER, SET TIMEZONE, CHECK FOR LOGIN-COOKIES
include("check.php");

//CHECK IF SESSION EXIST
if(!isset($_SESSION['user'])) {
    $isSesstion = false;
    header("Location: /index.php");
}
else{
    $isSesstion = true;
}
.....

check.php

<?php
define ("PEPPER",''); //random string for extra salt, use if you want.
define ("WEBSITE",'mydomain.com');  //your web site without http:// without final /
define ("SCRIPTFOLDER",'/login'); //direcory of the script start with a / if you installed the script in the root write just a / never finish with a /

$hosting="localhost"; //your host or localhost
$database="db"; //your database name
$database_user="user"; //your username for database
$database_password="pwd"; //your database password

require_once('pdo_db.php');
//generate random sequence or numbers and letter avoid problems with special chars

function aZ ($n=12) {
    $chars = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz';
    $bytes = random_ver($n);
    $result="";
    foreach (str_split($bytes) as $byte) $result .= $chars[ord($byte) % strlen($chars)];
    return $result;
}

//generate random and avoid compatibility problem with php version
function random_ver ($n=10) {
    $v=(int)phpversion()+0;
    if ($v<7) {
        //if php version < 7 use the old function for generate random bytes
        return openssl_random_pseudo_bytes($n);
    }else{
        //random_bytes is better but works only with php version > 7
        return random_bytes($n);
    }
}


// ********************************
// * SESSION TIME UPDATE          *
// ********************************

//Expire the session if user is inactive for 15 minutes or more.
//if u want to check how cookie works let the session id expire (wait X minutes without action, maybe set expireAfter to low value),
//close the browser then open again
$expireAfter = 1;

//Check to see if our "last action" session
//variable has been set.
if(isset($_SESSION['last_action'])){ echo 'IN';
    //Figure out how many seconds have passed
    //since the user was last active.
    $secondsInactive = time() - $_SESSION['last_action'];
    //Convert our minutes into seconds.
    $expireAfterSeconds = $expireAfter * 60;
    //Check to see if they have been inactive for too long.
    $debug.="last action: $secondsInactive seconds ago<br>";

    if($secondsInactive >= $expireAfterSeconds){
        //User has been inactive for too long.
        //Kill their session.
        session_unset();
        session_destroy();
        $debug.="session destroy for inactivity<br>";
    }  
}
//Assign the current timestamp as the user's
//latest activity
$_SESSION['last_action'] = time();

// *********************************
// * CHECK AUTO LOG-IN WITH COOKIE *
// *********************************


//if session is not set, but cookie exists
if (empty($_SESSION['user']) && !empty($_COOKIE['remember']) && $_GET["logout"]!=1) {

    $debug.="cookie read<br>";
    list($selector, $authenticator) = explode(':', urldecode($_COOKIE['remember']));

    //get from database the row with id and token related to selector code in the cookie
    $sql = $db->prepare("SELECT * FROM user_tokens
                         WHERE selector = ? limit 1");
    $sql->bindParam(1, $selector);
    $sql->execute();
    $row = $sql->fetch(PDO::FETCH_ASSOC);

    if (empty($authenticator) or empty($selector)) 
        $debug.="cookie invalid format<br>";

    //continue to check the authenticator only if the selector in the cookie is present in the database
    if (($sql->rowCount() > 0) && !empty($authenticator) && !empty($selector)) { 

        $debug.="cookie valid format<br>";

        // the token provided is like the token in the database
        // the functions password_verify and password_hash add secure salt and avoid timing attacks
        if (password_verify(base64_decode($authenticator), $row['hashedvalidator'])){

            //SET SESSION DATA
            $sql = $db->prepare("SELECT * FROM users WHERE id = ?");
            $sql->bindParam(1, $row['userid']);
            $sql->execute();
            $session_data = $sql->fetch(PDO::FETCH_ASSOC);

            //UNSET VARS
            unset($session_data['password']);

            $_SESSION['user'] = $session_data;

            //update database with a new token for the same selector and set the cookie again
            $authenticator = bin2hex(random_ver(33));
            $res=$db->prepare("UPDATE user_tokens SET hashedvalidator = ? , expires = FROM_UNIXTIME(".(time() + 864000*7).") , ip = ? WHERE selector = ?");
            $res->execute(array(password_hash($authenticator, PASSWORD_DEFAULT, ['cost' => 12]),$_SERVER['REMOTE_ADDR'],$selector));

            //set the cookie
            $setc = setcookie(
                'remember',
                $selector.':'.base64_encode($authenticator),
                time() + 864000*7, //the cookie will be valid for 7 days, or till log-out (if u want change it, modify the login.php file too)
                '/',
                WEBSITE,
                false, // TLS-only set to true if u have a website on https://
                false  // http-only
            );

            $debug.="cookie right selector<br>cookie right token<br>set a new token in DB and in cookie<br>session set ".$_SESSION['user']['usr_fname']."<br>";
        } else { 
            //selector exists but token doesnt match. that could be a secure problem, all selector/authenticator in database for that user will be deleted

            $res=$db->prepare("DELETE FROM user_tokens WHERE userid = ".$row["userid"]);
            $res->execute();
            $debug.="cookie right selector<br>cookie wrong token (all DB entry for that user are deleted)<br>";
        }
    } else {
        $debug.="selector not found in DB<br>";
    }
} else {
    $debug.="skip the cookie check: ";
    if (!empty($_SESSION['user'])) $debug.="session already set<br>";
    if (empty($_COOKIE['remember'])) $debug.="no cookie set<br>";
}
?>

那么,代码有什么问题?
为什么每次刷新网页时 $_SESSION 都会充满数据?
为什么每次刷新页面时if(isset($_SESSION['last_action'])){ 不返回 true?
为什么 $_SESSION 始终在调试消息 session set ".$_SESSION['user']['usr_fname']." 中携带数据......但它不会通过include(check.php");?

您需要更多代码吗?只是要求它!

【问题讨论】:

    标签: php session cookies


    【解决方案1】:

    我想我找到了问题所在。

    取消设置并销毁会话后。我不得不开始一个新的会话。
    奇怪的是,这种情况每秒钟才发生一次。但是添加session_start(); 解决了这个问题!

    if(isset($_SESSION['last_action'])){
      $secondsInactive = time() - $_SESSION['last_action'];
    
      $expireAfterSeconds = $expireAfter * 60;
    
      $debug.="last action: $secondsInactive seconds ago<br>";
      if($secondsInactive >= $expireAfterSeconds){
        //User has been inactive for too long.
        //Kill their session.
        session_unset();
        session_destroy();
        $debug.="session destroy for inactivity<br>";
      }  
    }
    
    ...
    session_start();
    $_SESSION['user'] = $session_data;
    ...
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-07-02
      • 1970-01-01
      • 2016-06-17
      相关资源
      最近更新 更多