【发布时间】:2015-07-28 18:28:52
【问题描述】:
php.net 说:
PHP 中的会话支持包括一种跨平台保存某些数据的方法 后续访问。
访问您网站的访问者被分配了一个唯一的 ID,即所谓的 会话 ID。这要么存储在用户端的 cookie 中,要么是 在 URL 中传播。
我正在尝试查看第二个选项,即 php 通过查询字符串传递会话 ID。我这样做只是为了教育目的。我知道不建议这样做。
重现我的实验:
我在 /var/www/html/script.php 中存储了以下脚本:
<?php
session_start();
if (isset($_SESSION["accesses"])) ++$_SESSION["accesses"];
else $_SESSION["accesses"] = 1;
echo "This page has been accessed ", $_SESSION["accesses"], " times";
?>
用php.ini中的默认php设置,即:
session.use_cookies = 1
session.use_only_cookies = 1
session.use_trans_sid = 0
一切正常。也就是说,当我在浏览器中访问 localhost/script.php 并刷新页面几次时,计数器会按预期工作。
当我在浏览器中禁用 cookie 时,当我多次刷新页面时计数器不再起作用(它一直保持为 1)。然后我在网上读到,默认情况下,通过查询字符串维护 php 会话是关闭的。然后我去修改php.ini如下:
session.use_cookies = 0
session.use_only_cookies = 0
session.use_trans_sid = 1
用 apache2 重新加载后
service apache2 reload
脚本中的计数器无论如何都不起作用。我在 php.ini 中尝试了更多设置组合,但没有成功。
我使用 PHP 5.5.9 和 Apache 2.4.7。
问题:
我的理解是,当在 php.ini 中禁用 cookie 并启用通过查询字符串传递会话 id 时,在第一次 GET 之后,php 应该看到查询字符串中没有会话 id。然后 php 将为用户初始化一个会话 id 并发送一个响应,该响应会将客户端重定向到与查询字符串中的会话 id 相同的 URL。这一切都是在不编写任何代码的情况下发生的——它是由 php 模块来维护会话的。
这至少是我所期望的。这有多少是真的?我是否对 PHP 自动执行的操作做了很多假设?但是如果我这样做了,那么“这要么存储在用户端的 cookie 中,要么在 URL 中传播”是什么。关于 php.net 关于? 如果 _SESSION 在 cookie 被禁用时不起作用,不应该简单地说吗?
编辑:
下面要回答的其他 cmets:
谜团解开了。通过查询字符串维护会话的工作原理如下面加星标的答案所示。为了查看它的实际效果,我将 /var/www/html/script.php 中的脚本修改为:
<?php
session_start();
if (isset($_SESSION["accesses"])) ++$_SESSION["accesses"];
else $_SESSION["accesses"] = 1;
echo "This page has been accessed ", $_SESSION["accesses"], " times";
echo '<br><a href="script.php">revisit</a>';
?>
你可以看到简单的刷新页面被PHP视为多次 尝试初始化一个新会话。只有当您单击“重新访问”链接时,会话 ID 才会实际嵌入(由 PHP 自动)在链接中,并且计数器开始工作(从那时起,它会通过再次访问链接或刷新来增加)。
关于 php.ini 中的设置的更多信息 (注意:我在 Firefox 39.0 中进行了以下所有实验。在其他浏览器中行为可能会有所不同。):
选项 1: 如果您希望 PHP 使用 cookie 来维护会话(如果它们在客户端浏览器中启用)并使用查询字符串(如果 cookie 被禁用),请确保您的 php.ini 具有以下设置:
session.use_cookies = 1
session.use_only_cookies = 0
session.use_trans_sid = 1
第一个默认启用(至少在我的 PHP 版本中,见上文)。其余两个是从默认值修改的。您需要修改两者。
这是如何工作的很有趣,因为当您执行第一个 GET 请求时,您不会在查询字符串中传递会话 id 并且未设置 cookie,因此 PHP 不知道 是否应该重写链接(请参阅下面带星标的答案)或设置 cookie(可能会失败)。
它的作用是尝试两者:您可以看到,在第一次访问时,下面示例中的“revisit”链接被 php 重写为包含会话 ID,但也是来自服务器的第一个响应尝试设置一个饼干。
只有在第二次请求之后,PHP 才知道 cookie 是否被成功植入。如果是,则不再重写链接。如果没有,它会不断重写链接以在查询字符串中包含会话 ID。
选项 2: 如果您希望 PHP 使用 cookie 来维护会话(如果它们在客户端浏览器中启用),但在禁用 cookie 时不使用查询字符串,请坚持使用默认设置,即:
session.use_cookies = 1
session.use_only_cookies = 1
session.use_trans_sid = 0
选项 3: 如果您希望 PHP 专门使用查询字符串来维护会话(不推荐),即使启用了 cookie,请使用:
session.use_cookies = 0
session.use_only_cookies = 0
session.use_trans_sid = 1
请注意,这些与默认的 PHP 设置完全相反。这是有充分理由的。
【问题讨论】:
-
在
querystring中使用session id可以导致session hijacking。 -
@DarkBee 这个问题承认这一点:“我这样做只是为了教育目的。我知道不建议这样做。”
-
如果你输入: session_regenerate_id(); 你可以让黑客更难劫持会话:就在会话开始代码下方。
标签: php apache session cookies