会话验证破坏会话
Session validation destroys session
这是我的 Session
class:
class Session {
const SESSION_VALIDATOR = 'validSession';
/**
* Starts the session
*/
public static function init() {
session_start();
if (self::get(self::SESSION_VALIDATOR) !== true) {
session_unset();
session_destroy();
session_start();
self::set(self::SESSION_VALIDATOR, true);
}
session_regenerate_id(false);
}
/**
* Sets a value in the session
*
* @param string|int $key
* @param mixed $value
*/
public static function set($key, $value) {
$_SESSION[$key] = $value;
}
/**
* Gets a value from the session
*
* @param string|int $key
* @return mixed
*/
public static function get($key) {
if (isset($_SESSION[$key]))
return $_SESSION[$key];
else
return false;
}
/**
* Destroys the session
*/
public static function destroy() {
unset($_SESSION);
session_destroy();
}
}
在随机时间,会话中的 SESSION_VALIDATOR
变量似乎没有被设置,即使它没有改变,并且会话随机销毁 - 即使用户已登录。这是什么原因造成的?
更新一:
这似乎只发生在我的本地主机环境 (WAMPServer 2.5
),而不是我的共享主机帐户
更新二:
它似乎没有发生,因为 Session::destroy()
方法在某个地方被意外调用,因为当我在方法内部抛出异常时,错误发生而没有抛出异常
更新 3:
忽略更新 #1 - 它也发生在我的共享主机帐户上
更新 4
试了andpei的回答,问题依旧。这是新的 Session
class:
class Session {
const SESSION_STARTED = true;
const SESSION_NOT_STARTED = false;
const SESSION_VALIDATOR = 'validSession';
private $sessionState = self::SESSION_NOT_STARTED;
private static $instance;
private function __construct() {
}
public static function getInstance() {
if (!isset(self::$instance)) {
self::$instance = new self;
}
self::$instance->startSession();
return self::$instance;
}
public function startSession() {
if ($this->sessionState == self::SESSION_NOT_STARTED) {
$this->sessionState = session_start();
}
if (self::get(self::SESSION_VALIDATOR) !== true) {
$this->destroy();
session_start();
self::set(self::SESSION_VALIDATOR, true);
}
session_regenerate_id(false);
return $this->sessionState;
}
public function set($name, $value) {
$_SESSION[$name] = $value;
}
public function get($name) {
if (isset($_SESSION[$name])) {
return $_SESSION[$name];
}
}
public function __isset($name) {
return isset($_SESSION[$name]);
}
public function __unset($name) {
unset($_SESSION[$name]);
}
public function destroy() {
if ($this->sessionState == self::SESSION_STARTED) {
$this->sessionState = !session_destroy();
unset($_SESSION);
return !$this->sessionState;
}
return false;
}
}
这让我认为错误出在 SESSION_VALIDATOR
部分:
if (self::get(self::SESSION_VALIDATOR) !== true) {
$this->destroy();
session_start();
self::set(self::SESSION_VALIDATOR, true);
}
,所以我删除了它,现在错误不再出现了。这个会话验证真的有必要吗?为什么或者为什么不?而如果保留它是明智的,那么如何解决错误?
这是一个设计问题,因为您无意中创建了 Session
对象的多个实例,然后这些实例都可能对 SESSION_VALIDATOR
.
具有不同的值
为了避免这个问题你应该在 OOP 中使用 Singleton Pattern。 getInstance()
方法不是通过 = new Session
创建实例,而是 return 始终是相同的实例对象。
您可以尝试此示例来创建一个 class Session with a Singleton。
评论更新
如果您不实例化 Session
对象,那么它可能会被 Garbage Collector 删除,因为没有对它的引用。结果 SESSION_VALIDATOR
也被删除了。在这种情况下,您会销毁会话 (_unset,_destroy,_start),这会导致用户注销。
你可以尝试上面的例子,使用单例模式可以解决问题。
比整个对象存储为静态值。
关于SESSION_VALIDATOR
的问题更新
这是一个设计问题,因为您在服务器端存储的状态取决于客户端的会话状态,即垃圾收集器运行(服务器)或浏览器删除 cookie 或注销(客户端) .
理论上这意味着HTTP是无状态的,使用session来克服这个问题。实际上,这意味着您必须从会话中读取一个值并决定登录是否有效。
所以,你的验证必须是一个函数而不是 SESSION_VALIDATOR
变量,return 是一个布尔值,取决于会话状态,它的值和你的用户数据库,即单例。
但是不要在您的会话中存储类似 login=true 的内容。使用您可以通过用户数据库验证的值。
也看看 OWASP PHP Security Cheat Sheet
类似问题:
- PHP Session Security
- PHP Session Fixation / Hijacking
这是我的 Session
class:
class Session {
const SESSION_VALIDATOR = 'validSession';
/**
* Starts the session
*/
public static function init() {
session_start();
if (self::get(self::SESSION_VALIDATOR) !== true) {
session_unset();
session_destroy();
session_start();
self::set(self::SESSION_VALIDATOR, true);
}
session_regenerate_id(false);
}
/**
* Sets a value in the session
*
* @param string|int $key
* @param mixed $value
*/
public static function set($key, $value) {
$_SESSION[$key] = $value;
}
/**
* Gets a value from the session
*
* @param string|int $key
* @return mixed
*/
public static function get($key) {
if (isset($_SESSION[$key]))
return $_SESSION[$key];
else
return false;
}
/**
* Destroys the session
*/
public static function destroy() {
unset($_SESSION);
session_destroy();
}
}
在随机时间,会话中的 SESSION_VALIDATOR
变量似乎没有被设置,即使它没有改变,并且会话随机销毁 - 即使用户已登录。这是什么原因造成的?
更新一:
这似乎只发生在我的本地主机环境 (WAMPServer 2.5
),而不是我的共享主机帐户
更新二:
它似乎没有发生,因为 Session::destroy()
方法在某个地方被意外调用,因为当我在方法内部抛出异常时,错误发生而没有抛出异常
更新 3:
忽略更新 #1 - 它也发生在我的共享主机帐户上
更新 4
试了andpei的回答,问题依旧。这是新的 Session
class:
class Session {
const SESSION_STARTED = true;
const SESSION_NOT_STARTED = false;
const SESSION_VALIDATOR = 'validSession';
private $sessionState = self::SESSION_NOT_STARTED;
private static $instance;
private function __construct() {
}
public static function getInstance() {
if (!isset(self::$instance)) {
self::$instance = new self;
}
self::$instance->startSession();
return self::$instance;
}
public function startSession() {
if ($this->sessionState == self::SESSION_NOT_STARTED) {
$this->sessionState = session_start();
}
if (self::get(self::SESSION_VALIDATOR) !== true) {
$this->destroy();
session_start();
self::set(self::SESSION_VALIDATOR, true);
}
session_regenerate_id(false);
return $this->sessionState;
}
public function set($name, $value) {
$_SESSION[$name] = $value;
}
public function get($name) {
if (isset($_SESSION[$name])) {
return $_SESSION[$name];
}
}
public function __isset($name) {
return isset($_SESSION[$name]);
}
public function __unset($name) {
unset($_SESSION[$name]);
}
public function destroy() {
if ($this->sessionState == self::SESSION_STARTED) {
$this->sessionState = !session_destroy();
unset($_SESSION);
return !$this->sessionState;
}
return false;
}
}
这让我认为错误出在 SESSION_VALIDATOR
部分:
if (self::get(self::SESSION_VALIDATOR) !== true) {
$this->destroy();
session_start();
self::set(self::SESSION_VALIDATOR, true);
}
,所以我删除了它,现在错误不再出现了。这个会话验证真的有必要吗?为什么或者为什么不?而如果保留它是明智的,那么如何解决错误?
这是一个设计问题,因为您无意中创建了 Session
对象的多个实例,然后这些实例都可能对 SESSION_VALIDATOR
.
为了避免这个问题你应该在 OOP 中使用 Singleton Pattern。 getInstance()
方法不是通过 = new Session
创建实例,而是 return 始终是相同的实例对象。
您可以尝试此示例来创建一个 class Session with a Singleton。
评论更新
如果您不实例化 Session
对象,那么它可能会被 Garbage Collector 删除,因为没有对它的引用。结果 SESSION_VALIDATOR
也被删除了。在这种情况下,您会销毁会话 (_unset,_destroy,_start),这会导致用户注销。
你可以尝试上面的例子,使用单例模式可以解决问题。
比整个对象存储为静态值。
关于SESSION_VALIDATOR
这是一个设计问题,因为您在服务器端存储的状态取决于客户端的会话状态,即垃圾收集器运行(服务器)或浏览器删除 cookie 或注销(客户端) .
理论上这意味着HTTP是无状态的,使用session来克服这个问题。实际上,这意味着您必须从会话中读取一个值并决定登录是否有效。
所以,你的验证必须是一个函数而不是 SESSION_VALIDATOR
变量,return 是一个布尔值,取决于会话状态,它的值和你的用户数据库,即单例。
但是不要在您的会话中存储类似 login=true 的内容。使用您可以通过用户数据库验证的值。
也看看 OWASP PHP Security Cheat Sheet
类似问题:
- PHP Session Security
- PHP Session Fixation / Hijacking