当你关注于防止源码的暴露时,你的会话数据只同样存在着风险。在默认情况下,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. ios开发之UIImageView

    废话少说,直接进入正题!!! 1.创建一个UIImageView: 创建一个UIImageView对象的几种方法: UIImageView *imageView1 = [[UIImageView al ...

  2. 关掉PUTTY后,进程仍可以运行。

    如果你正在运行一个进程,而且你觉得在退出帐户时该进程还不会结束,那么可以使用nohup命令.该命令可以在你退出帐户之后继续运行相应的进程.no hup就是不挂起的意思( no hang up).该命令 ...

  3. javascript DOM艺术

    一.DOM基础1.节点(node)层次Document--最顶层的节点,所有的其他节点都是附属于它的.DocumentType--DTD引用(使用<!DOCTYPE>语法)的对象表现形式, ...

  4. 第一个程序点亮一个LED灯

    #include <reg52.h> // 引用52包文件 可以理解为命名空间 sbit P1_0 = P1^0;   // 定义P1管脚0 void main()             ...

  5. python 装饰器、生成器、迭代器

    # 装饰器'''由高阶函数(把一个函数名当作实参传递给另一个函数,返回值中包含函数名)和嵌套函数(函数中嵌套函数)组成功能:在不更改原函数的代码和调用方式的前提下添加新的功能装饰器本身就是一个函数.使 ...

  6. JS Math.sin() 与 Math.cos() 用法

    Math.sin(x)      x 的正玄值.返回值在 -1.0 到 1.0 之间: Math.cos(x)    x 的余弦值.返回的是 -1.0 到 1.0 之间的数: 这两个函数中的X 都是指 ...

  7. IOS“多继承”

    转自念茜的博客: 当单继承不够用,很难为问题域建模时,我们通常都会直接想到多继承.多继承是从多余一个直接基类派生类的能力,可以更加直接地为应用程序建模.但是Objective-C不支持多继承,由于消息 ...

  8. MiniProfiler.3.0.10 用于MVC4.0中不能显示SQL语句

    MiniProfiler.3.0.10 用于MVC4.0中可以显示执行时间,但是不能显示SQL语句,怎么解决?

  9. 【Java】ArrayList和LinkedList的区别

    一般大家都知道ArrayList和LinkedList的大致区别:      1.ArrayList是实现了基于动态数组的数据结构,LinkedList基于链表的数据结构.      2.对于随机访问 ...

  10. 稍加详细的ATR信息,将完善历史字节部分+

    http://blog.csdn.net/jennyvenus/article/details/2900697 //Reset 3B FB 13 00 00 81 31 FE 45 65 46 53 ...