如何正确结束用户会话? [英] How to properly end a users session?
问题描述
我一直在研究网站(PHP)的安全性,需要吸收大量信息。我已经尝试实现在 OWASP 上研究过的安全性,但是我要做的一件事是除了其他方面,我还有些担心的是用户注销时如何处理会话。
I've been working on the security of my site (PHP) and there's a ton of information to ingest. I've tried to implement security I've researched on OWASP, but one thing I'm a little nervous about, among other things, is how to handle SESSIONS when the user logs out.
当前我正在使用的是:
session_destroy();
但是,我读到我应该更改XRSF令牌并启动另一个SESSION,以便强制执行用户重新提交登录凭据,从而明确结束用户会话。
But, I've read that I should change the XRSF token and start another SESSION so it forces the user to resubmit login credentials in-turn explicitly ending the users SESSION.
session_destroy()
是否足够?
编辑
我已经下载了 michael-the-messenger ,我相信它是由Michael Brooks(Rook)创建的,应该非常安全,我看到了我可能想使用的一些代码。这可以安全地替换我正在使用的 session_destroy()
吗?
I've downloaded michael-the-messenger, which I believe was created by Michael Brooks (Rook) which should be VERY secure, and I saw some code that I might want to use. Is this something that could safely replace the session_destroy()
I'm using?
代码
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'] =新auth();
重新实例化将私有变量 $ auth
设置为false的对象。
Obviously $_SESSION['user'] = new auth();
reinstantiates the object which sets a private variable $auth
to false.
推荐答案
但我有点担心的一件事是,当用户注销时
如何处理会话。 / p>
but one thing I'm a little nervous about, among other things, is how to handle SESSIONS when the user logs out.
根据手册 :
为了完全终止会话,就像注销用户一样,还必须取消设置
会话ID。如果使用cookie传播
会话ID(默认行为),则必须删除
会话cookie。 setcookie()可能用于此目的。
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()
和 setcookie(session_name(),null ,time()-86400)
会做到这一点。
除此之外,
会话存储仅在内部使用数据序列化。通过将对象
存储在$ _ SESSION
超全局对象中,您只需按需对
序列化/反序列化该对象,而无需了解它。
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)通过将对象存储在 $ _ SESSION
中,您确实引入了全局状态。 $ _ SESSION
是一个超全局数组,因此可以从任何地方访问。
1) By storing an object in $_SESSION
you do introduce global state. $_SESSION
is a superglobal array, thus can be accessed from anywhere.
2)即使通过存储一个对象保留有关已登录用户的信息,则会浪费系统内存。对象表示的长度总是大于字符串的长度。
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,
- 它使代码易于阅读,维护和测试
- 它遵循单一责任原则
- 它避免了全局状态(如果使用得当的话) ),则您访问会话的方式不是
$ _ SESSION ['foo']
,而是$ session-> read ['foo']
- 您可以轻松更改其行为(例如,如果您决定使用数据库作为会话存储),甚至不影响应用程序的其他部分。
- 代码重用能力。您可以将该类用于其他应用程序(或部分应用程序)
- 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)
如果将所有与会话相关的功能包装到signle类中,然后它将变成具有吸引力的
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);
}
}
}
这篇关于如何正确结束用户会话?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!