【问题标题】:PHP session regeneration securityPHP会话再生安全
【发布时间】:2012-12-29 01:50:01
【问题描述】:

我在使用 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 使现有会话无效。另外,我在(大概)new 会话中放了一些东西 - 这可能就像一个 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 ,它不会在会话中看到任何信息,因为旧会话已失效。

还有其他人遇到过这类问题吗?有没有解决这些问题的好方法?

【问题讨论】:

    标签: php security session


    【解决方案1】:

    基于session_regenerate_iddocumentation,听起来会话的内容总是被保留。您正在向它传递一个 TRUE 参数,但这只会删除磁盘上的实际会话文件;其中存储的值保存在$_SESSION 中,然后写入新会话。

    所以也许手动清除它:

    $_SESSION = array();
    

    不过,不确定为什么您没有看到新的 cookie。你在哪里检查的,你看到了什么?

    编辑:正如 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');
    ?>
    

    我不知道这是否是最小的。弄清楚其中有多少可以删除,留给读者作为练习。

    【讨论】:

    • 呃——对——给page2加一个session_destroy会清空session的内容,但是新的内容还是没有加进去,也没有发送新的session ID。我通过在 webkit 工具中查看网站的当前 cookie 来检查是否发送了新的会话 ID。因为我不敢相信它没有发送新的 cookie,所以我还检查了 MITM 代理 - 它绝对没有发送新的 cookie。'
    • session_destroy also 只影响磁盘上的文件。它不会删除$_SESSION。通过创建一个新会话,您可以让 PHP 在某个地方存储从第一个会话遗留下来的所有会话数据。尝试在第 2 页的每一行之后转储 $_SESSION,您应该会看到这种情况。
    • 嗯。对于 cookie 问题,如果您放弃 session_write_close 调用会发生什么?如果您删除 header+exit 并只提供一个页面会发生什么?
    • 谢谢,@Eevee - 我认为在我们两个之间,我们终于解决了:php
    • PHP 手册session_unset 提到“注意不要用unset($_SESSION) 取消设置整个$_SESSION”,而是使用:“$_SESSION = array();”(在 PHP 4.0.6 之后使用时)。跨度>
    猜你喜欢
    • 2012-07-22
    • 1970-01-01
    • 1970-01-01
    • 2011-11-06
    • 2020-04-16
    • 2011-02-11
    • 2012-09-24
    相关资源
    最近更新 更多