跳转到内容

PHP 编程/会话

来自维基教科书,开放的书籍,为开放的世界
(从 PHP 编程/会话 重定向)

会话 允许 PHP 脚本在 Web 服务器上存储数据,这些数据可以在以后使用,即使是在对不同 PHP 页面进行请求之间也是如此。每个会话都有一个不同的标识符,它以 Cookie 或 $_GET 变量的形式发送到客户端的浏览器。会话在用户关闭浏览器时结束,或者在 Web 服务器删除会话信息时结束,或者在程序员显式地销毁会话时结束。在 PHP 中,它通常被称为 PHPSESSID。会话非常有用,可以保护用户无法读取或写入的数据,尤其是当 PHP 开发人员不想在 Cookie 中提供信息时,因为 Cookie 很容易被读取。会话可以通过 $_SESSION 超级全局变量来控制。存储在此数组中的数据在整个会话期间都是持久的。它是一个简单的数组。会话比 Cookie 更容易使用,这为 PHP 开发人员提供了很大帮助。大多数情况下,会话用于用户登录、购物车和其他需要保持浏览流畅的补充。PHP 脚本可以轻松地控制发送的会话 Cookie,并控制整个会话数据。会话始终存储在一个唯一的文件名中,要么在临时文件夹中,要么在特定文件夹中,如果脚本指示这样做的话。

使用会话

[编辑 | 编辑源代码]

在每个将作为当前会话一部分的 PHP 脚本的开头,必须有函数 session_start()。它必须在第一个输出(echo 或其他)之前,否则会导致错误“Headers already sent out”。

 session_start();

此函数将执行以下操作

  1. 它将检查 _COOKIE_GET 数据,如果给定的话
  2. 如果会话文件不存在于 session.save_path 位置,它将
    1. 生成一个新的唯一标识符,并且
    2. 根据该标识符创建一个新文件,并且
    3. 向客户端浏览器发送一个 Cookie
  3. 如果存在,PHP 脚本将尝试将文件的数据存储到 _SESSION 变量中,以便进一步使用

现在,您可以通过两种不同的方式简单地设置变量,默认方法

 $_SESSION['example'] = "Test";

或者过时的方法

 $example="Test";
 session_register($example);

以上两个语句都将注册会话变量 $_SESSION['example'] 为“Test”。过时的方法不应该使用,它只列出来是因为您仍然可以在由不知道新方法的程序员编写的脚本中看到它。默认方法是首选。

会话配置选项

[编辑 | 编辑源代码]

PHP 会话很容易控制,并且可以通过一些小因素使其更安全或更不安全。以下是一些可以使用 php_ini() 函数轻松更改的运行时选项

名称 默认值 可更改
session.save_path "/tmp" PHP_INI_ALL
session.name "PHPSESSID" PHP_INI_ALL
session.save_handler "files" PHP_INI_ALL
session.auto_start "0" PHP_INI_ALL
session.gc_probability "1" PHP_INI_ALL
session.gc_divisor "100" PHP_INI_ALL
session.gc_maxlifetime "1440" PHP_INI_ALL
session.serialize_handler "php" PHP_INI_ALL
session.cookie_lifetime "0" PHP_INI_ALL
session.cookie_path "/" PHP_INI_ALL
session.cookie_domain "" PHP_INI_ALL
session.cookie_secure "" PHP_INI_ALL
session.use_cookies "1" PHP_INI_ALL
session.use_only_cookies "0" PHP_INI_ALL
session.referer_check "" PHP_INI_ALL
session.entropy_file "" PHP_INI_ALL
session.entropy_length "0" PHP_INI_ALL
session.cache_limiter "nocache" PHP_INI_ALL
session.cache_expire "180" PHP_INI_ALL
session.use_trans_sid "0" PHP_INI_SYSTEM/PHP_INI_PERDIR
session.bug_compat_42 "1" PHP_INI_ALL
session.bug_compat_warn "1" PHP_INI_ALL
session.hash_function "0" PHP_INI_ALL
session.hash_bits_per_character "4" PHP_INI_ALL
url_rewriter.tags "a=href,area=href,frame=src,input=src,form=fakeentry" PHP_INI_ALL

一个简单的例子是这段代码

 //Setting The Session Saving path to "sessions", '''must be protected from reading'''
 session_save_path("sessions"); // This function is an alternative to ini_set("session.save_path","sessions");
 //Session Cookie's Lifetime ( not effective, but use! )
 ini_set("session.cookie_lifetime",time()+60*60*24*500);
 //Change the Session Name from PHPSESSID to SessionID
 session_name("SessionID");
 //Start The session
 session_start();
 //Set a session cookie ( Required for some browsers, as settings that had been done before are not very effective 
 setcookie(session_name(), session_id(), time()+3600*24*365, "/");

这个例子只是将 Cookie 设置为下一年。

结束会话

[编辑 | 编辑源代码]

当用户点击“注销”或“退出”时,通常需要销毁所有登录数据,这样就没有人可以再访问它了。会话文件将被删除,同时也会通过以下方式取消设置 Cookie

 session_destroy();

使用其他类型会话数据

[编辑 | 编辑源代码]

简单数据,如整数、字符串和数组,可以轻松地存储在 $_SESSION 超级全局数组中,并且可以在页面之间传递。但是,当尝试通过赋值存储对象的 state 时,会出现问题。可以通过使用 serialize() 函数将对象的 state 存储在会话中。serialize() 将把对象的 data 写入一个数组中,然后可以存储在 $_SESSION 超级全局变量中。unserialize() 可用于在尝试在属于当前会话的页面中访问对象之前恢复对象的 state。如果要在会话期间跨多个页面访问使用对象,则必须在调用 unserialize() 之前定义对象定义。在序列化和反序列化对象时,可能会出现其他问题。

避免会话固定

[编辑 | 编辑源代码]

会话固定描述了一种攻击向量,其中恶意第三方设置(即固定)用户的会话标识符(SID),从而能够访问该用户的会话。在会话的基本实现中,如上所述,这是一个非常真实的漏洞,每个使用会话进行任何敏感操作的 PHP 程序都应该采取措施来解决它。以下按适用范围的广度排序,是防止会话固定的措施

  1. 不要使用 GET 或 POST 变量来存储会话 ID(在大多数 PHP 配置中,使用 Cookie 来存储 SID,因此程序员不需要执行任何操作来实现这一点);
  2. 在每个用户请求上重新生成 SID(在会话的开头使用 session_regenerate_id());
  3. 使用会话超时:对于每个用户请求,存储当前时间戳,并在下一次请求时检查是否已超过超时时间间隔;
  4. 提供注销功能;
  5. 检查每个请求的“浏览器指纹”。这是一个存储在 $_SESSION 变量中的哈希,包含用户代理头、客户端 IP 地址、盐值和/或其他信息的组合。有关此详细信息的更多讨论,请参见下文;一些人认为它不过是一种“通过模糊来实现安全”。[待办事项]
  6. 检查来源:这并不适用于所有系统,但如果您知道您网站的用户必须来自某个已知域,您可以丢弃与来自其他地方的用户关联的会话。它依赖于用户代理提供来源头,这一点不应该假设。
此示例代码解决了上述所有问题,除了来源检查。
$timeout = 3 * 60; // 3 minutes
$fingerprint = md5('SECRET-SALT'.$_SERVER['HTTP_USER_AGENT']);
session_start();
if ( (isset($_SESSION['last_active']) && (time() > ($_SESSION['last_active']+$timeout)))
     || (isset($_SESSION['fingerprint']) && $_SESSION['fingerprint']!=$fingerprint)
     || isset($_GET['logout']) ) {
    do_logout();
}
session_regenerate_id(); 
$_SESSION['last_active'] = time();
$_SESSION['fingerprint'] = $fingerprint;
do_logout() 函数销毁会话数据并取消设置会话 Cookie。


华夏公益教科书