【发布时间】:2015-10-14 17:33:42
【问题描述】:
我已经尝试解决这个问题好几个星期了。
我已经创建了一个类来保护 PHP 会话,它工作正常,除非有人试图执行注册(它的问题 #2)并且如果某些功能被禁用(这导致 #2 发生),其余的网站运行良好。
那么问题来了:
- session_regenerate_id - 已注释掉
从这里开始,一切正常,除了验证码创建机制(仅在注册页面上),对于登录页面它工作正常 - session_regenerate_id(true) - 未注释
在这里,注册工作正常,没有问题,没有验证码问题,但是在页面刷新几次后,会话就消失了,所以用户需要再登录 6 次刷新并且 $_SESSION 再次设置为 null
我知道问题可能出在哪里,但我不知道如何解决。
我有一个私有静态函数,它在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 方法'....
是的....有点....但问题是,由于我猜我缺乏知识,我在某个地方搞砸了脚本,逻辑出错了。
以下是链接(可能是为了简化理解):
Sessions.FreedomCore.php - 会话类
String.FreedomCore.php - 验证码生成(指向准确的行)
@987654323 @ - 帐户创建过程(仅适用于 session_regenerate_id)
pager.php - 验证码显示过程(在某些情况下始终有效)
pager.php - 执行登录案例(在任何情况下由于某种原因没有问题)
如果您对它的实际工作原理非常感兴趣(我的意思是它如何在 4 次刷新后取消对用户的授权)
Please head over here
用户名: test
密码: 123456
所以问题是: 如何修改我的课程,使用当前方法使用 session_regenerate_id(true) 保存会话数据,并防止在调用 session_regenerate_id 后刷新它。
这些链接直接指向脚本的问题区域。
非常感谢任何帮助。
非常感谢您的帮助!
【问题讨论】:
-
问题不是很清楚。看了你的问题,我有点困惑。
-
@JijoJohn 我用问题部分更新了主题