优雅地使用CodeIgniter 3之Session类库(1)(转)

相信无数人在使用CI2的Session类库时,遇到各种的坑,各种抱怨,各种不解。在CI中国论坛能搜到大量关于Session类库的提问,说明要想用 好session类库还是得下一番功夫。本文将先从CI2入手,讲述CI下Session类库的设计理念和在CI3下的Session类库做了哪些重大改 进。首先在这里简单说明一下Session和cookie的区别。

Session和cookie的区别

1.在某些语境中,cookie是session的一种实现方式,Ci的类库设计似乎就这么认为的。设想用户登录后使用Session保存数据的一种情 景。用户输入密码和口令发送到服务器后,php就会在服务器端生成一个php sessionid和一个具体的数据包放到一个文件中,并存放到指定的文件夹下(如果session.save_handler=files),然后会把 sessionId作为一个cookie放到响应中返回给客户端(前提是用户浏览器开启了cookie,否则会加入到url地址的查询字符串中)。用户再 次访问服务器上的其他页面时,会把这个phpsessionid的cookie携带上作为请求的一部分发送给服务器,服务器就能根据session id到保存session的文件夹下找到特定的文件,读取其中的数据。


2.而cookie,在服务器端和客户端都是可以设置的。在客户端设置(通过js)时,主要作用是用户在自己的浏览器页面跳转时能传递数据。服务端不会太 多理睬客户端设置的cookie,客户端发过来什么,它就原封不动地返回什么。同时,服务器也会发出让客户端设置cookie的指令,下次请求时客户端也 会无脑地把cookie发送到服务器。


在CI2.0版本的Session类库中,默认使用了cookie来保存session,便带给我们各种不解。下面谈下CI2.0的session工作原理。

基本原理

使用Session库时,会有一个元数据。我们可以把这个元数据理解为在浏览器和服务器之间的一个令牌,有了这个令牌,服务器的城门才会对客户端的请求敞 开。客户端好比是一个信使,要去服务器的王宫里报告信息,服务器的门卫就会检查这个令牌,这个令牌包含的基本信息是:ip地址、user agent、上次活动时间、Session id,其中Session id是重要的,Session id不对,直接拒绝。但是门卫也可能根据上级指示,需要根据他的外表判断是否是来自特定地区(IP地址的限制)、看下他的服饰是否符合某些特征(user agent限制),是否令牌是否已经过期(上次活动时间),如果都满足才能让特定的西域人进入王宫。

1 Array
2 (
3     [session_id] => 4a5a5dca22728fb0a84364eeb405b601
4     [ip_address] => 127.0.0.1
5     [user_agent] => Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_7;
6     [last_activity] => 1303142623
7 )

门卫得到的上级指示来自于配置文件,它们放在config.php中:

1 $config['sess_match_ip']  = FALSE;
2 $config['sess_match_useragent'] = TRUE;
3 $config['sess_time_to_update'] = 300;

门卫会拿令牌里的信息(http请求携带的cookie)和真实的信息(http请求头的信息)比对,判断你是否是合法的,不合法的话,就会认为你来路不 明,拒绝你携带来的任何数据信息。如果你在使用CI自带的Session库时,总是出现读不到数据的情况,你就要看下你是否要求门卫检查的过于严格。特别 是当设置sess_match_useragent设为TRUE时,会遇到各种的坑:

1. 你用flash组件上传文件,只有登录的用户才能上传文件,结果你每次判断用户是否登录都会出错,因为flash发送的http请求有可能更改了user agent;

2. 使用ie切换不同的模式,比如兼容模式,也会造成user agent不同;

3. user agent的长度最长是120个字符,手动设置User agent是需要截取字符到最大120个。

4. 另外,如果出现“Cannot modify header information - headers already sent by”错误,基本可以断定是你文件的编码格式有误,请去掉bom头。

安全问题

CI使用cookie来传递数据本来就不够安全,而且如果数据量巨大时也会有性能问题。但是CI还是友好地加入以下几个安全验证机制:

1. 加密令牌

1 $config['encryption_key'] = 'mahuaz_';
2 $config['sess_encrypt_cookie'] =  TRUE;

设置后,客户端检查cookie时就可以看到加密后的序列化数据。


2. 自动更新机制

CI 默认每五分钟更新一次令牌,更新发生在客户端的一次请求中。客户端每发送一次请求,会把cookie的信息发送到服务器,服务器根据发来的cookie判 断是否到了应该更换令牌的时间了,如果是,就会重新换一个新的令牌返回给客户端。这就相当于门卫给你换了令牌,下次要使用新令牌进门。此时即使有坏人伪造 了一个令牌也不起作用了,因为旧令牌已经作废。这样就相当于加了一条安全机制。可以使用:

1 $config['sess_time_to_update'] = 300;

来设置多长时间来换一次令牌。这个时间不要设置的太短,更新频繁也会影响性能。这里不要和sess_expiration混淆:

1 $config['sess_expiration']  = 7200;

这个配置是用来指示整个cookie的过期时间的,相当于令牌完全失效,再怎么更换都不起作用。

在CI中文论坛上,每每有遇到各种session问题,总有人推荐使用hex封装的Session库 ,或者使用stblog的作者Saturn的Session库 https://github.com/cnsaturn/codeigniter-my-session前者使用PHP原生Session,不需要额外配置;后者需要安装 memcached 服务以及 memcache/memcached 扩展。hex封装的这个Session库特性有限,它有如下特点:

1. 简化了CI自带Session的安全机制,没有做每五分钟更新session_id的设置;

2.没有加密Session;

3.永远不会过期,虽然它会读取$config['sess_expiration'] = 7200;判断Session是否过期,但是如果发现过期的话,并不是直接返回空数据,而是重新产生一个新的Session id,把旧数据转到新数据中。除非你超过了最大gc回收时间:7200s。

4.config.php中的以下配置节都没任何用处:

1 $config['sess_cookie_name']  = 'ci_session';
2 //$config['sess_expiration']  = 7200; 该配置节有用
3 $config['sess_expire_on_close'] = FALSE;
4 $config['sess_encrypt_cookie'] = FALSE;
5 $config['sess_use_database'] = FALSE;
6 $config['sess_table_name']  = 'ci_sessions';
7 $config['sess_match_ip']  = FALSE;
8 $config['sess_match_useragent'] = TRUE;
9 $config['sess_time_to_update'] = 300;

所以,使用这个库也只能解决大部分问题,真正的解决方案也只能等到CI3来处理,事实上CI3也如愿地解决了上面提到的很多问题。下一节我们讲讲如何使用CI3的session。

http://www.ifixedbug.com/posts/how-to-use-codeigniter3-session-1

posted @ 2015-08-06 17:17  北斗极星  阅读(727)  评论(0编辑  收藏  举报