关于会话:PHP:$ _SESSION-将临时使用的数据存储在$ _SESSION变量中的优缺点是什么

关于会话:PHP:$ _SESSION-将临时使用的数据存储在$ _SESSION变量中的优缺点是什么

PHP: $_SESSION - What are the pros and cons of storing temporarily used data in the $_SESSION variable

最近我开始做得更多的一件事是在任务开始时检索一些数据并将其存储在$ _SESSION ['myDataForTheTask']中。

现在看来这样做非常方便,但是我对使用这种方法对性能,安全风险或类似方面一无所知。它是由具有更多专业知识的程序员定期完成的事情,还是更业余的事情?

例如:

1
2
3
4
5
6
7
8
9
10
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;
}

Well Session变量实际上是在访问者访问网站的整个时间中使这些变量可用的唯一方法(也许是最有效的方法),用户没有真正的方法来编辑它们(除了在您的代码或PHP解释器中进行漏洞利用),因此它们相当安全。

这是存储可由用户更改的设置的好方法,因为您可以在会话开始时从数据库中读取一次设置,并且该设置可用于整个会话,因此您只需要进行进一步的数据库调用如果更改了设置,当然,正如您在代码中所显示的那样,查找设置是否已经存在或是否需要从数据库中提取这些设置很简单。

我想不出其他任何方式来安全地存储临时变量(因为可以轻松地修改cookie,并且在大多数情况下这是不可取的),因此$ _SESSION将成为实现的方式


$ _ SESSION机制正在使用cookie。

对于Firefox(也许还有新的IE,我没有检查自己),这意味着会话在打开的选项卡之间共享。默认情况下,这不是您期望的。这意味着会话不再是"特定于单个窗口/用户的东西"。

例如,如果您打开了两个选项卡来访问您的站点,而不是使用第一个选项卡作为根用户登录,则您将在另一个选项卡中获得root特权。

这确实很不方便,尤其是在您编写电子邮件客户端或其他代码(例如e-shop)的情况下。在这种情况下,您将必须手动管理会话或在URL中引入不断重新生成的密钥或执行其他操作。


我一直使用会话变量来存储用户信息。我还没有发现任何性能问题。会话数据是根据cookie(如果您已关闭cookie,则为PHPSESSID)提取的。与其他任何基于cookie的身份验证相比,我认为它没有更多的安全风险,而且可能比在用户cookie中存储实际数据更安全。

不过,只是让您知道,您的SQL语句确实存在安全问题:

1
SELECT participationcode, modulearray, wavenum FROM mng_wave WHERE wave_id=".$_GET['wave_id'];

您永远都不要,我永远不要重复使用用户提供的数据,并将其用于运行SQL语句而无需先对其进行清理。我将其package在引号中并添加功能mysql_real_escape_string()。这样可以保护您免受大多数攻击。因此,您的行将如下所示:

1
$query_taskinfo ="SELECT participationcode, modulearray, wavenum FROM mng_wave WHERE wave_id='".mysql_real_escape_string($_GET['wave_id'])."'";

如果您在自己的服务器上运行,或者在没人能窥探服务器上文件/内存的环境中,则会话数据是安全的。它们存储在服务器上,只是一个标识cookie发送到客户端。问题是,其他人当然可以抢走cookie并假冒其他人。使用HTTPS并确保不将会话ID放在URL中,可以使您的用户免受大多数此类问题的影响。 (如果您不小心的话,XSS可能仍可用来抓取cookie,也请参见Jeef Atwoods的相关文章。)

关于存储在会话变量中的内容,如果要再次在另一个页面(例如购物篮)上引用它,则将数据放在此处,但如果它只是用于生成该变量的临时数据,则不要放在此处。此页面的结果,例如当前查看的帖子的标签列表。会话用于按用户的持久性数据。


在决定将临时数据存储在何处时,需要考虑一些因素。会话存储非常适合单个用户的数据。如果您发现默认的基于文件的会话存储处理程序效率低下,则可以实施其他操作,可能使用数据库或后端的内存缓存类型。有关更多信息,请参见session_set_save_handler。

我发现在用户的会话中存储通用数据是一种不好的做法。有更好的存储数据的位置,这些数据将被多个用户频繁访问,通过将这些数据存储在会话中,您将为需要此数据的每个用户复制数据。在您的示例中,您可能为此波浪数据(基于wave_id)设置了另一种类型的存储引擎,该存储引擎并不专门与用户的会话绑定。这样,您将一次拉取数据并将其存储在多个用户可以访问数据的位置,而无需再次拉取。


使用会话的其他一些缺点:

  • $_SESSION数据将在session.gc_maxlifetime闲置秒数后过期。
  • 您必须记住为每个将使用会话数据的脚本调用session_start()
  • 通过在多个服务器上进行负载平衡来扩展网站可能是一个问题,因为每次都需要将用户定向到同一服务器。通过" Sticky Sessions"解决此问题。

  • 另一种改善输入验证的方法是强制转换_GET ['wave_id']变量:

    1
    $query_taskinfo ="SELECT participationcode, modulearray, wavenum FROM mng_wave WHERE wave_id=".(int)$_GET['wave_id']." LIMIT 1";

    我假设wave_id是一个整数,并且只有一个答案。


    您可能要考虑这是REST风格的吗?

    即请参见" REST简介"中的"无状态通信"段落。

    "REST mandates that state be either
    turned into resource state, or kept on
    the client. In other words, a server
    should not have to retain some sort of
    communication state for any of the
    clients it communicates with beyond a
    single request."

    (或REST维基百科上的任何其他链接)

    因此,在您的情况下,'wave_id'是获取GET的明智资源,但是您是否真的要将其存储在SESSION中?当然,memcached是您缓存对象Resource的解决方案吗?


    我发现会话非常有用,但需要注意以下几点:

    1)PHP可能会将您的会话存储在tmp文件夹或服务器上其他用户可以访问的其他目录中。您可以通过转到php.ini文件来更改存储会话的目录。

    2)如果要建立一个需要非常严格的安全性的高价值系统,则可能需要在将数据发送到会话之前对其进行加密,然后解密以使用它。注意:这可能会产生过多的开销,具体取决于您的流量/服务器容量。

    3)我发现了session_destroy();不会立即删除会话,您仍然必须等待PHP垃圾收集器清理会话。您可以在php.ini文件中更改运行垃圾收集器的频率。但是它似乎仍然不是很可靠,更多信息http://www.captain.at/howto-php-sessions.php


    Zend Framework具有用于会话数据管理的有用库,该库有助于有效期和安全性(用于验证码)。他们对会议也有有用的解释。参见http://framework.zend.com/manual/en/zend.session.html


    IMO,将内容存储在会话中是完全可以接受的。这是使数据持久化的好方法。在许多情况下,它比将所有内容存储在Cookie中更安全。这里有一些问题:

    • 有人可能会劫持一个会话,因此,如果要使用它来跟踪用户授权,请当心。阅读此以获得更多信息。
    • 这可能是保存数据的一种非常懒惰的方式。不要将所有内容都扔在会话中,这样您以后就不必查询它了。
    • 如果要在会话中存储对象,则在下一个请求开始会话之前,将需要包含其类文件,或者需要配置自动加载器。

    $ _ SESSION项目存储在会话中,默认情况下,它保留在磁盘上。无需像您一样制作自己的阵列并将其填充到" dataentry"阵列条目中。您可以只使用$ _SESSION ['pcode'],$ _ SESSION ['modules']等。

    就像我说的那样,会话存储在磁盘上,而指向该会话的指针则存储在cookie中。因此,用户无法轻松获取会话数据。


    $ _ SESSION在安全性上非常有用,因为它是服务器端在用户活跃在您的页面上时存储信息的方式,因此除非您的实际php文件或服务器具有被利用的弱点,否则很难被黑客入侵。一个很好的实现是存储一个变量以确认用户已登录,并且仅在确认用户已登录后才允许执行操作。


    这是很常见的事情,并且会话通常比连续数据库命中要快。它们也相当安全,因为PHP开发人员为防止会话劫持而进行了艰苦的工作。

    唯一的问题是,当发生更改时,您需要记住要重建会话条目。而且,如果拥有会话的用户以外的其他用户进行了任何更改,都将导致需要刷新此密钥,则没有简单的方法来通知系统刷新此会话密钥。可能没什么大不了的,但是您应该注意一些事情。


    我相当使用这种方法,我认为它没有任何问题。与cookie不同,数据不是存储在客户端,这通常是一个大错误。

    尽管如此,但要小心,始终清理用户输入,尤其是如果要将用户输入放入$ _SESSION变量中,然后再在SQL查询中使用该变量。


    推荐阅读