PHP会话再生安全性


PHP session regeneration security

我在使用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');
?>

我不知道这是否是最小的。至于可以删除多少内容,留给读者自行判断。