首页 > 解决方案 > PHP $_SESSION maxlifetime 无法正常工作

问题描述

对于我网站上的所有页面,我在顶部都有这个会话检查:

<?php
// Initialize the session
if(!isset($_SESSION))
{ 
    session_start();
}
 
// Check if the user is logged in, if not then redirect him to login page
if(!isset($_SESSION["loggedin"]) || $_SESSION["loggedin"] !== true){
  header("location: login.php");
  exit;
}
?>

我用它来检查用户是否已登录。如果用户没有登录,他将被重定向到登录页面。

在 login.php 页面的最顶部,我有这个:

<?php

// server should keep session data for AT LEAST 8 hours
ini_set('session.gc_maxlifetime', 28800);

// each client should remember their session id for EXACTLY 8 hour
session_set_cookie_params(28800);

// Initialize the session
session_start();
 
// Check if the user is already logged in, if yes then redirect him to welcome page
if(isset($_SESSION["loggedin"]) && $_SESSION["loggedin"] === true){
    header("location: index.php");
    exit;
}

基本上这应该使会话持续 8 小时,是吗?

当用户成功登录时,我得到了 SESSION:$_SESSION["loggedin"] = true;

我在这里做错了什么?当我将 SESSION 设置为持续 28800 秒 = 8 小时时,为什么我的用户在一段时间处于非活动状态后会不断注销/重定向到登录页面?

标签: php

解决方案


当客户端请求中不存在会话 cookie 时,cookie 最初设置一次。这意味着:这些设置最初只应用一次,而不是每次点击session_start().

当您启动会话时,cookie 时间开始到期,而不是您实际登录时。

因此,如果您提前访问该站点并开始 8 小时的会话,但您在 7.5 小时后登录,您的“登录”将在 30 分钟后过期(8 小时 - 7.5 小时 = 0.5 小时)。

从技术上讲,您的问题在这里:

<?php
// Initialize the session
if(!isset($_SESSION))
{ 
    session_start();
}

会话开始时没有特定的到期时间。但是您想在会话开始时显式指定过期时间:

<?php
// Put this on top of ALL pages that RELY on session
if (session_status() === PHP_SESSION_NONE) {
    ini_set('session.gc_maxlifetime', 28800);
    session_set_cookie_params(28800);
    if (!session_start()) {
        throw new \Exception('Failed to start a new session');
    }
}

当有人成功登录时,您会喜欢:

<?php
if (login_successful()) {
    // Beware of race conditions in flakey wifi or with concurrent requests
    session_regenerate_id();
    $_SESSION['loggedin'] = true;
    $_SESSION['someToken'] = bin2hex(random_bytes(32));
}

稍后设置过期时间无效,因为如果没有更改值(或会话 ID),cookie 不会“刷新”。

您的代码还有两个问题:

  1. 没有session_regenerate_id(),你很容易受到会话固定https://owasp.org/www-community/attacks/Session_fixation

  2. 您根本没有实施身份验证。每个人都可以通过简单地创建一个本地 cookie 来“登录”到您的站点loggedin=true。不检查密码或用户名。


推荐阅读