PHP:$_SESSION - 在 $_SESSION 变量中存储临时使用的数据的优缺点是啥
Posted
技术标签:
【中文标题】PHP:$_SESSION - 在 $_SESSION 变量中存储临时使用的数据的优缺点是啥【英文标题】:PHP: $_SESSION - What are the pros and cons of storing temporarily used data in the $_SESSION variablePHP:$_SESSION - 在 $_SESSION 变量中存储临时使用的数据的优缺点是什么 【发布时间】:2010-09-09 19:42:00 【问题描述】:我最近开始经常做的一件事是在任务开始时检索一些数据并将其存储在 $_SESSION['myDataForTheTask'] 中。
现在这样做似乎很方便,但我对使用这种方法的性能、安全风险或类似情况一无所知。这是由更专业的程序员经常做的事情,还是更像是业余的事情?
例如:
if (!isset($_SESSION['dataentry']))
$query_taskinfo = "SELECT participationcode, modulearray, wavenum FROM mng_wave WHERE wave_id=" . mysql_real_escape_string($_GET['wave_id']);
$result_taskinfo = $db->query($query_taskinfo);
$row_taskinfo = $result_taskinfo->fetch_row();
$dataentry = array("pcode" => $row_taskinfo[0], "modules" => $row_taskinfo[1], "data_id" => 0, "wavenum" => $row_taskinfo[2], "prequest" => FALSE, "highlight" => array());
$_SESSION['dataentry'] = $dataentry;
【问题讨论】:
您的 SQL 查询容易受到 SQL 注入攻击。例如,有人可以输入 '?wave_id=wave_id' 并且查询会选择所有行。 (DELETE、INSERT 和 UPDATE 查询更糟。)在这种情况下,您应该编写代码以确保它是一个数字,而最简单的方法是 intval() 【参考方案1】:$_SESSION 项目存储在会话中,默认情况下保存在磁盘上。无需像您那样创建自己的数组并将其填充到“dataentry”数组条目中。您可以只使用 $_SESSION['pcode']、$_SESSION['modules'] 等。
就像我说的,会话存储在磁盘上,指向会话的指针存储在 cookie 中。用户因此不能轻易获得会话数据。
【讨论】:
只需使用多维数组 $_SESSION['mystuff']['mydata'] = 'blah'; @conmulligan:当然,但是除了你放在那里的东西之外,会话中不会有任何内容。您可能会将 $_SESSION 与 $_SERVER 混淆。【参考方案2】:我经常使用这种方法,我认为它没有任何问题。与 cookie 不同,数据不存储在客户端,这通常是一个大错误。
尽管如此,请注意始终清理用户输入,尤其是当您将用户输入放入 $_SESSION 变量,然后在 SQL 查询中使用该变量时。
【讨论】:
【参考方案3】:在决定将临时数据存储在何处时,您需要考虑几个因素。会话存储非常适合特定于单个用户的数据。如果您发现默认的基于文件的会话存储处理程序效率低下,您可以实现其他东西,可能使用数据库或 memcache 类型的后端。请参阅session_set_save_handler 了解更多信息。
我发现在用户会话中存储公共数据是一种不好的做法。有更好的地方可以存储多个用户经常访问的数据,并且通过将这些数据存储在会话中,您将为需要这些数据的每个用户复制数据。在您的示例中,您可能会为此波形数据(基于 wave_id)设置不同类型的存储引擎,该引擎不专门与用户会话相关联。这样,您只需将数据拉下一次,然后将其存储在多个用户无需再次拉出即可访问数据的地方。
【讨论】:
【参考方案4】:IMO,在会话中存储东西是完全可以接受的。这是使数据持久化的好方法。在许多情况下,它也比将所有内容存储在 cookie 中更安全。以下是一些问题:
有人可能会劫持会话,因此如果您打算使用它来跟踪用户授权,请小心。阅读this 了解更多信息。 保存数据可能是一种非常懒惰的方式。不要只是把所有东西都扔到会话中,这样你以后就不必再查询了。 如果您要在会话中存储对象,则需要在下一次请求启动会话之前包含它们的类文件,或者您需要配置自动加载器。【讨论】:
【参考方案5】:如果您在自己的服务器上运行,或者在没有人可以窥探服务器上文件/内存的环境中运行,则会话数据是安全的。它们存储在服务器上,只是发送给客户端的标识 cookie。问题是,当然,其他人是否可以抢走 cookie 并冒充其他人。使用 HTTPS 并确保不将会话 ID 放在 URL 中应该可以使您的用户免受大多数这些问题的影响。 (如果您不小心,XSS 可能仍会被用于抓取 cookie,请参阅 Jeef Atwoods post on this。)
至于在会话变量中存储什么,如果您想在另一个页面(例如购物篮)上再次引用它,请将您的数据放在那里,但如果它只是用于生成的临时数据,请不要放在那里此页面的结果,例如当前查看的帖子的标签列表。会话用于每个用户的持久数据。
【讨论】:
【参考方案6】:这是相当常见的事情,而且会话通常比连续的数据库命中要快。它们也相当安全,因为 php 开发人员一直在努力防止会话劫持。
唯一的问题是您需要记住在发生变化时重建会话条目。而且,如果拥有会话的用户以外的用户更改了任何会导致需要刷新此密钥的内容,则没有简单的方法来通知系统刷新此会话密钥。可能没什么大不了的,但您应该注意一些事情。
【讨论】:
【参考方案7】:我一直使用会话变量来为用户存储信息。我没有看到任何性能问题。会话数据是基于 cookie(或 PHPSESSID,如果您关闭了 cookie)。我不认为它比任何其他基于 cookie 的身份验证更具安全风险,并且可能比将实际数据存储在用户 cookie 中更安全。
只是让您知道,您的 SQL 语句确实存在安全问题:
SELECT participationcode, modulearray, wavenum FROM mng_wave WHERE wave_id=".$_GET['wave_id'];
您应该从不,我从不重复,获取用户提供的数据并使用它来运行 SQL 语句,而无需先对其进行清理。我会将它用引号括起来并添加函数mysql_real_escape_string()
。这将保护您免受大多数攻击。所以你的行看起来像:
$query_taskinfo = "SELECT participationcode, modulearray, wavenum FROM mng_wave WHERE wave_id='".mysql_real_escape_string($_GET['wave_id'])."'";
【讨论】:
【参考方案8】:Zend Framework 有一个有用的会话数据管理库,它有助于过期和安全(用于验证码之类的东西)。他们还对会话进行了有用的解释。见http://framework.zend.com/manual/en/zend.session.html
【讨论】:
【参考方案9】:会话变量确实是让这些变量在访问者在网站上的整个时间内可用的唯一方法之一(并且可能是最有效的),用户没有真正的方法来编辑它们(除了在您的代码或 PHP 解释器中利用),因此它们相当安全。
这是一种存储用户可以更改的设置的好方法,因为您可以在会话开始时从数据库中读取一次设置,并且该设置可用于整个会话,您只需要进行进一步的数据库调用如果更改了设置,当然,正如您在代码中显示的那样,找出设置是否已经存在或是否需要从数据库中提取它们是微不足道的。
我想不出任何其他安全存储临时变量的方法(因为 cookie 很容易被修改,而且在大多数情况下这是不可取的),所以 $_SESSION 将是可行的方法
【讨论】:
“它们相当安全”只有在它是专用服务器时才是正确的。在共享主机上,同一台机器上的其他用户可以访问 php-session 数据。 如果您选择将会话数据存储在默认位置以外的其他位置,则不会。或者当您使用不同的会话存储机制时,例如 DB 或(您自己的私有)memcache。【参考方案10】:另一种改进输入验证的方法是强制转换 _GET['wave_id'] 变量:
$query_taskinfo = "SELECT participationcode, modulearray, wavenum FROM mng_wave WHERE wave_id=".(int)$_GET['wave_id']." LIMIT 1";
我假设 wave_id 是一个整数,并且只有一个答案。
会
【讨论】:
【参考方案11】:我发现会话非常有用,但有几点需要注意:
1) PHP 可能会将您的会话存储在 tmp 文件夹或其他目录中,您服务器上的其他用户可以访问这些目录。您可以通过转到 php.ini 文件来更改存储会话的目录。
2) 如果您正在建立一个需要非常严格的安全性的高价值系统,您可能希望在将数据发送到会话之前对其进行加密,然后对其进行解密以使用它。注意:这可能会产生过多的开销,具体取决于您的流量/服务器容量。
3) 我发现 session_destroy();不会立即删除会话,您仍然需要等待 PHP 垃圾收集器清理会话。您可以在 php.ini 文件中更改垃圾收集器的运行频率。但似乎还是不太可靠,更多信息http://www.captain.at/howto-php-sessions.php
【讨论】:
【参考方案12】:$_SESSION 机制正在使用 cookie。
如果是 Firefox(也许是新的 IE,我没有检查自己),这意味着 会话在打开的选项卡之间共享。默认情况下,这不是您所期望的。这意味着会话不再是“特定于单个窗口/用户的东西”。
例如,如果您打开了两个选项卡来访问您的站点,而不是使用第一个选项卡以 root 身份登录,您将获得另一个选项卡的 root 权限。
这真的很不方便,特别是如果您编写电子邮件客户端或其他东西(如电子商店)。在这种情况下,您将不得不手动管理会话或在 URL 中引入不断重新生成的密钥或执行其他操作。
【讨论】:
【参考方案13】:您可能想考虑一下这有多符合 REST 标准?
即请参阅“A Brief Introduction to REST”中的“无状态通信”段落...
“REST 要求状态是 变成资源状态,或保持在 客户端。换句话说,服务器 不应该保留某种 任何通信状态 它与之通信的客户超出了 单个请求。”
(或***上REST 的任何其他链接)
所以在你的情况下,'wave_id' 是一个合理的 GET 资源,但你真的想将它存储在 SESSION 中吗?确定memcached 是您缓存对象资源的解决方案吗?
【讨论】:
【参考方案14】:使用会话的其他一些缺点:
$_SESSION
数据将在 session.gc_maxlifetime 秒不活动后过期。
您必须记住为每个将使用会话数据的脚本调用 session_start()
。
通过在多台服务器上进行负载平衡来扩展网站可能是个问题,因为每次都需要将用户定向到同一台服务器。使用“Sticky Sessions”解决这个问题。
【讨论】:
【参考方案15】:$_SESSION 在安全性方面非常有用,因为它是一种在用户活跃在您的页面上时存储信息的服务器端方式,因此很难破解,除非您的实际 php 文件或服务器存在被利用的弱点。一个非常好的实现是存储一个变量来确认用户已登录,并且只有在确认用户已登录时才允许执行操作。
【讨论】:
以上是关于PHP:$_SESSION - 在 $_SESSION 变量中存储临时使用的数据的优缺点是啥的主要内容,如果未能解决你的问题,请参考以下文章
session 和 _session 之间的区别(facebook 集成)
linux下 php文件中session_id无法保持不变,每次刷新页面session_id也会出现新的数值 这个是怎么搞定的?