会话验证会破坏会话

时间:2015-09-13 19:10:51

标签: php security session session-variables

这是我的Session课程:

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变量似乎没有被设置,即使它没有被更改,并且会话随机销毁 - 即使在用户登录时也是如此。这是什么原因造成的? / p>

更新1:
这似乎只发生在我的localhost环境(WAMPServer 2.5),而不是我的共享主机帐户

更新2:
它似乎没有发生,因为Session::destroy()方法在某处意外调用,因为当我在方法中抛出异常时,错误发生而没有抛出异常

更新3:
忽略更新#1 - 它也发生在我的共享主机帐户

更新4
我试过andpei的答案,但问题仍然存在。这是新的Session类:

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);
}

,所以我删除了它,现在错误不再发生了。这个会话验证真的有必要吗?为什么或者为什么不?如果保持它是明智的,那么如何解决错误呢?

1 个答案:

答案 0 :(得分:2)

这是一个设计问题,因为您无意中创建了Session个对象的多个实例,这些实例的SESSION_VALIDATOR可能具有不同的值。

要避免此问题,您应该在OOP Singleton Pattern中使用。 = new Session方法不是按getInstance()创建实例,而是始终返回相同的实例对象。

您可以尝试使用此示例创建class Session with a Singleton

更新评论

如果您没有实例化Session对象,那么它可能会被Garbage Collector删除,因为没有对它的引用。因此,SESSION_VALIDATOR也会被删除。在这种情况下,您将销毁会话(_unset,_destroy,_start),从而注销用户。

您可以尝试上面的示例,这将通过使用单例模式来解决问题。

比整个对象存储为静态值。

更新至SESSION_VALIDATOR

的问题

这是一个设计问题,因为你在服务器端存储一个状态,它取决于客户端的会话状态,即垃圾收集器运行(服务器)或浏览器删除cookie或注销(客户端) )。

理论上,这意味着HTTP是无状态的,会话用于解决这个问题。实际上,这意味着您必须从会话中读取值并确定登录是否有效。

所以,你的验证必须是一个函数而不是SESSION_VALIDATOR 变量,它根据会话状态,它的值和你的用户数据库返回一个布尔值,即使用Singleton

会在会话中存储类似login = true的内容。使用您可以使用用户数据库验证的值。

另请参阅 OWASP PHP Security Cheat Sheet

类似的问题: