我在使用PHP做一些非常基本的会话安全类型的事情时遇到了困难:
- 当从一个未认证的上下文切换到一个已认证的上下文时,应该生成一个新的会话ID
- 当从已验证的上下文切换到未验证的上下文时,应该生成一个新的会话ID
我想做的不仅是在切换上下文时重新生成会话ID,而且在切换这些上下文时立即将一些东西放入会话(例如FLASH)。这三页应该能够澄清我的期望:
<?php
/* page1.php */
session_start();
# Just putting something in the session which I expect to
# not show up later
$_SESSION['INFO1'] = 'INFO1';
?>
<html>
<a href="page2.php">Page 2</a>
<?php print_r($_SESSION) ?>
</html>
所以当显示这个页面时,我希望看到INFO1
出现。我也希望当我回到这里时,不会看到INFO2
出现。如果我还没有会话ID,我希望得到一个(我有)。
<?php
# page2.php
session_destroy();
session_regenerate_id(TRUE);
$_SESSION['INFO2'] = 'From page 2';
session_write_close();
header('Location: page3.php');
exit;
?>
这将最类似于注销功能-我们通过将TRUE
传递给session_regenerate_id
来使现有会话无效。此外,我在(大概)新会话中放入了一些东西-可能像FLASH -说"您已经成功注销。
#page3.php
<html>
<body>
<?php session_start(); ?>
<?php print_r($_SESSION); ?>
</body>
</html>
在这一页,我希望发生两件事:
-
page2.php
的重定向应该给我发送一个新的会话ID cookie(它没有) - 我希望
print_r
打印来自INFO2
的信息,而不是来自INFO1
的。它没有INFO1
的信息,但不包括INFO2
的信息。
我有非常非常不一致的结果与session_regenerate_id
和重定向。这似乎是这样一个拼凑手动发送Set-Cookie
头-但即使我没有,session_regenerate_id(TRUE)
应该使旧的会话ID无效-所以即使浏览器没有因为某种原因获得新的会话ID,它也不会在会话中看到任何信息,因为旧会话已经无效。
还有其他人有过这类问题的经验吗?有什么好的方法来解决这些问题吗?
根据session_regenerate_id
的文档,似乎总是保留会话的内容。你给它传递一个TRUE
参数,但这只会删除磁盘上的实际会话文件;其中存储的值保存在$_SESSION
中,然后写入新会话。
所以也许可以手动清除:
$_SESSION = array();
不知道为什么你没有看到新的cookie,虽然。你在哪里检查,看到了什么?
edit:问题,正如OP在下面的评论中所揭示的那样,似乎是page2从未调用session_start
来加载第一个会话。生成以下内容:
<?php
session_start(); # Load the old session
session_destroy(); # Nuke it
session_unset(); # Delete its contents
session_start(); # Create a new session
session_regenerate_id(TRUE); # Ensure it has a new id
$_SESSION['FLASH'] = "You've been logged out";
session_write_close(); # Convince it to write
header('Location: index.php');
?>
我不知道这是否是最小的。至于可以删除多少内容,留给读者自行判断。