5

我一直在研究我的网站 (PHP) 的安全性,并且有大量信息需要获取。我试图实现我在OWASP上研究过的安全性,但我有点紧张的一件事是,当用户注销时如何处理 SESSIONS。

目前我正在使用的是:

session_destroy();

但是,我读到我应该更改 XRSF 令牌并启动另一个 SESSION,以便它强制用户重新提交登录凭据,进而明确结束用户 SESSION。

session_destroy()了吗?

编辑

我已经下载了 michael-the-messenger,我相信它是由 Michael Brooks (Rook) 创建的,它应该非常安全,并且我看到了一些我可能想要使用的代码。这是可以安全地替换session_destroy()我正在使用的东西吗?

代码

if($_SESSION['user']->isAuth())
{
    /* if they have clicked log out */
    /* this will kill the session */
    if($_POST['LogMeOut'] == 'true')
    {
        //When the user logs out the xsrf token changes.
        $tmp_xsrf = $_SESSION['user']->getXsrfToken();
        $_SESSION['user']->logout();
        $loginMessage = str_replace($tmp_xsrf, $_SESSION['user']->getXsrfToken(), $loginMessage);
        print layout('Authorization Required', $loginMessage);
    }
    else
    {
        header("Location: inbox.php");
        //user is allowed access. 
    }
}
else
{
    // code goes on ....

登出

public function logout()
{
    $_SESSION['user'] = new auth();
}

显然$_SESSION['user'] = new auth();重新实例化了将私有变量设置$auth为 false 的对象。

4

2 回答 2

2

but one thing I'm a little nervous about, among other things, is how to handle SESSIONS when the user logs out.

According to manual:

In order to kill the session altogether, like to log the user out, the session id must also be unset. If a cookie is used to propagate the session id (default behavior), then the session cookie must be deleted. setcookie() may be used for that.

So, in order to safely destroy a session, we'd also erase it on the client-machine.

session_destroy() along with setcookie(session_name(), null, time() - 86400) will do that.

Apart from that,

What you are doing wrong and why:

Session storage merely uses data serialization internally. By storing an object in the $_SESSION superglobal you just do serialize/unserialize that object on demand without even knowing it.

1) By storing an object in $_SESSION you do introduce global state. $_SESSION is a superglobal array, thus can be accessed from anywhere.

2) Even by storing an object that keeps an information about logged user, you do waste system memory. The length of object representation is always greater than a length of the strings.

But why on earth should you even care about wrapping session functionality? Well,

  • It makes a code easy to read, maintain and test
  • It adheres Single-Responsibility Principle
  • It avoids global state (if properly used), you'll access session not as $_SESSION['foo'], but $session->read['foo']
  • You can easily change its behaivor (say, if you decide to use DB as session storage) without even affecting another parts of your application.
  • Code reuse-ability. You can use this class for another applications (or parts of it)

If you wrap all session-related functionality into a signle class, then it will turn into attractive:

$session = new SessionStorage();

$session->write( array('foo' => 'bar') );

if ( $session->isValid() === TRUE ) {

    echo $session->read('foo'); // bar

} else {

    // Session hijack. Handle here
}

// To totally destroy a session:
$session->destroy();


// if some part of your application requires a session, then just inject an instance of `SessionStorage`
// like this:
$user = new Profile($session);


// Take this implementation as example:

final class SessionStorage
{
    public function __construct()
    {
        // Don't start again if session is started:
        if ( session_id() != '' ) {
            session_start();
        }

        // Keep initial values
        $_SESSION['HTTP_USER_AGENT'] = $_SERVER['HTTP_USER_AGENT'];
        $_SESSION['REMOTE_ADDR'] = $_SERVER['REMOTE_ADDR'];
    }

    /**
     * You can prevent majority of hijacks using this method
     * 
     * @return boolean TRUE if session is valid
     */
    public function isValid()
    {
        return $_SESSION['HTTP_USER_AGENT'] === $_SERVER['HTTP_USER_AGENT'] && $_SESSION['REMOTE_ADDR'] === $_SERVER['REMOTE_ADDR'] ;
    }


    public function __destruct()
    {
        session_write_close();
    }

    /**
     * Fixed session_destroy()
     * 
     * @return boolean
     */
    public function destroy()
    {
        // Erase the session name on client side
        setcookie(session_name(), null, time() - 86400);

        // Erase on the server
        return session_destroy();
    }


    public function write(array $data)
    {
        foreach($data as $key => $value) {
            $_SESSION[$key] = $value;
        }
    }


    public function exists()
    {
        foreach(func_get_args() as $arg){

            if ( ! array_key_exists($arg, $_SESSION) ){
                return false;
            }
        }

        return true;
    }

    public function read($key)
    {
        if ( $this->exists($key) ){

            return $_SESSION[$key];

        } else {

            throw new RuntimeException('Cannot access non-existing var ' .$key);
        }
    }

}
于 2013-04-29T09:37:18.723 回答
-2

也许 session_unset() 是你正在寻找的。

于 2013-04-29T05:57:41.010 回答