跳转到内容

PHP 编程/会话

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

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

使用会话

[编辑 | 编辑源代码]

在每个将成为当前会话一部分的 PHP 脚本的顶部,必须有函数 session_start()。它必须在第一个输出(echo 或其他)之前,否则将导致错误“标头已发送”。

 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 超全局数组中,并从一个页面传递到另一个页面。但是,尝试通过赋值存储对象的状态时会出现问题。对象状态可以通过使用 serialize() 函数存储在会话中。serialize() 将把对象数据写入一个数组,然后可以将其存储在 $_SESSION 超全局变量中。unserialize() 可用于在尝试访问当前会话一部分的页面中的对象之前还原对象的狀態。如果对象要在会话期间跨多个页面访问使用,则必须在调用 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。


华夏公益教科书