当你关注于防止源码的暴露时,你的会话数据只同样存在着风险。在默认情况下,SESSION保存在/tmp目录下。这样做在很多情形下是很方便的,其中之一是所有用户都有对/tmp的写入权限,这样Apache同样也有权限进行写入。虽然其他用户不能直接从shell环境读取这些会话文件,但他们可以写一个简单的脚本来进行读取:

01 <?php
02  
03 header('Content-Type: text/plain');
04 session_start();
05  
06 $path = ini_get('session.save_path');
07 $handle = dir($path);
08  
09 while ($filename = $handle->read())
10 {
11   if (substr($filename, 0, 5) == 'sess_')
12   {
13     $data = file_get_contents("$path/$filename");
14  
15     if (!empty($data))
16     {
17       session_decode($data);
18       $session = $_SESSION;
19       $_SESSION = array();
20       echo "Session [" . substr($filename, 5) . "]\n";
21       print_r($session);
22       echo "\n--\n\n";
23     }
24   }
25 }
26  
27 ?>

这个脚本在session.save_path所定义的会话文件保存目录中搜索以sess_为前缀的文件。找到文件后,即对它的内容进行解析并用print_r()函数显示它的内容。这样其它开发者就容易地取得了你的用户的会话数据。

解决这个问题的最好方法是把你的会话数据存入用用户名和密码保护的数据库中。由于数据库的访问是受控的,这样就多了一层额外的保护。通过应用前节中提及的技巧,数据库可以为你的敏感数据提供一个安全的存放地,同时你应该保持警惕,你的数据库安全性正变得越来越重要。

为在数据库中保存会话数据,首先需要建立一个数据表:

1 CREATE TABLE sessions
2 (
3   id varchar(32) NOT NULL,
4   access int(10) unsigned,
5   data text,
6   PRIMARY KEY (id)
7 );

如果你使用的是MySQL,则表结构描述如下:

1 mysql> DESCRIBE sessions;
2 +--------+------------------+------+-----+---------+-------+
3 | Field  | Type             | Null | Key | Default | Extra |
4 +--------+------------------+------+-----+---------+-------+
5 | id     | varchar(32)      |      | PRI |         |       |
6 | access | int(10) unsigned | YES  |     | NULL    |       |
7 | data   | text             | YES  |     | NULL    |       |
8 +--------+------------------+------+-----+---------+-------+

如要使会话数据能保存在此表中,你需要使用session_set_save_handler( )函数来编辑PHP的内建会话机制:

01 <?php
02  
03 session_set_save_handler('_open',
04                          '_close',
05                          '_read',
06                          '_write',
07                          '_destroy',
08                          '_clean');
09  
10 ?>

以上的六个参数每一个都代表着需要你编写的函数的名称,他们对下面的任务进行处理:

  • 打开会话存储
  • 关闭会话存储
  • 读取会话数据
  • 写入会话数据
  • 消灭会话数据
  • 清除旧会话数据

我有意使用了有意义的名称,这样你可以一下看出它们的目的。命名是任意的,但你可能希望用下划线开头(如此处所示)或其它的命名约定来防止名称冲突。下面是这些函数(使用MySQL)的示例:

01 <?php
02  
03 function _open()
04 {
05   global $_sess_db;
06  
07   $db_user = $_SERVER['DB_USER'];
08   $db_pass = $_SERVER['DB_PASS'];
09   $db_host = 'localhost';
10  
11   if ($_sess_db = mysql_connect($db_host, $db_user, $db_pass))
12   {
13     return mysql_select_db('sessions', $_sess_db);
14   }
15  
16   return FALSE;
17 }
18  
19 function _close()
20 {
21   global $_sess_db;
22  
23   return mysql_close($_sess_db);
24 }
25  
26 function _read($id)
27 {
28   global $_sess_db;
29  
30   $id = mysql_real_escape_string($id);
31  
32   $sql = "SELECT data
33           FROM   sessions
34           WHERE  id = '$id'";
35  
36   if ($result = mysql_query($sql, $_sess_db))
37   {
38     if (mysql_num_rows($result))
39     {
40       $record = mysql_fetch_assoc($result);
41  
42       return $record['data'];
43     }
44   }
45  
46   return '';
47 }
48  
49 function _write($id, $data)
50 {
51   global $_sess_db;
52  
53   $access = time();
54  
55   $id = mysql_real_escape_string($id);
56   $access = mysql_real_escape_string($access);
57   $data = mysql_real_escape_string($data);
58  
59   $sql = "REPLACE
60           INTO    sessions
61           VALUES  ('$id', '$access', '$data')";
62  
63   return mysql_query($sql, $_sess_db);
64 }
65  
66 function _destroy($id)
67 {
68   global $_sess_db;
69  
70   $id = mysql_real_escape_string($id);
71  
72   $sql = "DELETE
73           FROM   sessions
74           WHERE id = '$id'";
75  
76   return mysql_query($sql, $_sess_db);
77 }
78  
79 function _clean($max)
80 {
81   global $_sess_db;
82  
83   $old = time() - $max;
84   $old = mysql_real_escape_string($old);
85  
86   $sql = "DELETE
87           FROM   sessions
88           WHERE  access < '$old'";
89  
90   return mysql_query($sql, $_sess_db);
91 }
92  
93 ?>

你必须要在session_start( )之前调用session_set_save_handler( )函数,但你可以在任何地方对这些函数本身进行定义。

这个流程的漂亮之处在于你无须对代码进行编辑或变化使用会话的方式。$_SESSION依然存在,行为依旧,还是由PHP来产生与传递会识标识,对有关会话的配置变更同样还会生效。所有你需要做的只是调用这一个函数(同时建立由它指定的所有函数),PHP就会照顾余下的事情。

PHP安全编程:更优的会话数据安全 更好地防范session暴露(转)的更多相关文章

  1. 编程思想转换&体验Lambda的更优写法和Lambda标准格式

    编程思想转换做什么,而不是怎么做 我们真的希望创建一个匿名内部类对象吗?不,我们只是为了做这件事情而不得不创建一个对象. 我们真正希望做的事情是:将run方法体内的代码传递给Thread类知晓. 传递 ...

  2. PHP日志扩展 SeasLog-1.6.8, 性能更优

    SeasLog-1.6.8 发布了,性能更优. 改进日志: 1.6.8: 优化内存使用和性能,修复已知Bug. - Fixed issue #97 PHP5.* Cached Block. - Fix ...

  3. IntelliJ IDEA 2019.2最新解读:性能更好,体验更优,细节处理更完美!

    idea 2019.2 准备 idea 2019.2正式版是在2019年7月24号发布的,本篇文章,我将根据官方博客以及自己的理解来进行说明,总体就是:性能更好,体验更优,细节处理更完美! 支持jdk ...

  4. 体验Lambda的更优写法和Lambda标准格式

    体验Lambda的更优写法 借助Java8的全新语法,上述Runnable接口的匿名内部类写法可以通过更简单的Lambda表达式达到等效: public class Lambda02 { public ...

  5. 取代 Mybatis Generator,这款代码生成神器配置更简单,开发效率更高!

    作为一名 Java 后端开发,日常工作中免不了要生成数据库表对应的持久化对象 PO,操作数据库的接口 DAO,以及 CRUD 的 XML,也就是 mapper. Mybatis Generator 是 ...

  6. JavaWeb(二)会话管理之细说cookie与session

    前言 前面花了几篇博客介绍了Servlet,讲的非常的详细.这一篇给大家介绍一下cookie和session. 一.会话概述 1.1.什么是会话? 会话可简单理解为:用户开一个浏览器,点击多个超链接, ...

  7. 会话技术、Cookie技术与Session技术

    一.会话技术  1. 存储客户端状态 会话技术是帮助服务器记住客户端状态(区分客户端)的.  2. 会话技术 从打开一个浏览器访问某个站点,到关闭这个浏览器的整个过程,称为一次会话.会话技术就是记录这 ...

  8. MT【272】更大的视野,更好的思路.

    已知$f(x)=\sum\limits_{k=1}^{2017}\dfrac{\cos kx}{\cos^k x},$则$f(\dfrac{\pi}{2018})=$_____ 分析:设$g(x)=\ ...

  9. Java第三阶段学习(十三、会话技术、Cookie技术与Session技术)

    一.会话技术  1. 存储客户端状态 会话技术是帮助服务器记住客户端状态(区分客户端)的.  2. 会话技术 从打开一个浏览器访问某个站点,到关闭这个浏览器的整个过程,称为一次会话.会话技术就是记录这 ...

随机推荐

  1. VLC命令参数(转载)

    转载自: http://blog.csdn.net/bytxl/article/details/6613449 http://www.cnblogs.com/MikeZhang/archive/201 ...

  2. Title of live Writer

    Test From Windows Live Writer **markdown bold**

  3. 测试gcc的优化选项

    一.测试准备及原理 测试代码: static void wait(volatile unsigned long dly) { ; dly--); } int main(void) { unsigned ...

  4. Object-C非正式协议与正式协议的区别

    Object-C非正式协议与正式协议的区别 这两个概念困扰我很久了,一直都很像搞清楚到非正式协议和正式协议有什么区别和联系,下面结合网上的资料和自己的看法谈谈这个问题. 一.非正式协议 显然这个名词是 ...

  5. Solr4.8.0源码分析(25)之SolrCloud的Split流程

    Solr4.8.0源码分析(25)之SolrCloud的Split流程(一) 题记:昨天有位网友问我SolrCloud的split的机制是如何的,这个还真不知道,所以今天抽空去看了Split的原理,大 ...

  6. [POJ 2774] Long Long Message 【后缀数组】

    题目链接:POJ - 2774 题目分析 题目要求求出两个字符串的最长公共子串,使用后缀数组求解会十分容易. 将两个字符串用特殊字符隔开再连接到一起,求出后缀数组. 可以看出,最长公共子串就是两个字符 ...

  7. [BZOJ 1084] [SCOI2005] 最大子矩阵 【DP】

    题目链接:BZOJ - 1084 题目分析 我看的是神犇BLADEVIL的题解. 1)对于 m = 1 的情况, 首先可能不取 Map[i][1],先 f[i][k] = f[i - 1][k];   ...

  8. ibatis动态语句加and 和不加and

    <select id="queryGoodsGroupCodeName" parameterClass="String" resultClass=&quo ...

  9. ARM单片机的头文件如何用结构体定义地址

    下面我们以ARM Cortex-M0内核单片机LPC1114的头文件lpc11xx.h文件进行说明. 1.先说两句 lpc11xx.h文件是lpc11xx系列单片机包含的头文件.这个文件的作用和51单 ...

  10. TControl的显示函数(5个非虚函数,4个虚函数)和三个例子的执行过程(包括SetParent的例子)

    // 9个显示函数 procedure SetBounds(ALeft, ATop, AWidth, AHeight: Integer); virtual; // 虚函数,important 根据父控 ...