用户
 找回密码
 入住 CI 中国社区
搜索
查看: 9552|回复: 9
收起左侧

CodeIgniter配置之SESSION

[复制链接]
发表于 2013-12-10 12:33:07 | 显示全部楼层 |阅读模式
刚使用Codeigniter时也被其中的SESSION迷惑过,后来就再也没用过CI自带的SESSION,想必还是有必要整理一下SESSION。为弄清CI中的SESSION,先来说一下PHP中SESSION是如何工作的。由于HTTP协议本身是无状态的,所以当保留某个用户的访问状态信息时,需要客户端有一个唯一标识传给服务端,这个唯一标识就是SESSION ID,存放在客户端的COOKIE中,然后服务端根据该标识读取存放的用户状态信息,达到保存会话状态的目的。PHP中启动一个会话需要执行下面语句:
PHP复制代码
 
session_start();
 
复制代码

1、客户端每次请求时会有一些信息存放中HTTP头中发送给服务端,以用户第一次访问为例:
Request Headers
Accept:text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Accept-Encoding:gzip,deflate,sdch
Accept-Language:zh-CN,zh;q=0.8
Cache-Control:max-age=0
Connection:keep-alive
Host:s.local
User-Agent:Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/31.0.1650.63 Safari/537.36

2、服务端接到请求处理后并返回给客户端,并在HTTP Response中加上添加COOKIE的请求,告诉浏览器需要设置一个COOKIE,COOKIE名为PHPSESSID,值为r887k5n4scg32d4ba34huuhmq7,如:
Response Headers
Cache-Control:no-store, no-cache, must-revalidate, post-check=0, pre-check=0
Connection:Keep-Alive
Content-Length:0
Content-Type:text/html
Date:Sun, 08 Dec 2013 12:56:56 GMT
Expires:Thu, 19 Nov 1981 08:52:00 GMT
Keep-Alive:timeout=5, max=100
Pragma:no-cache
Server:Apache/2.2.11 (Win32) PHP/5.4.7
Set-Cookie:PHPSESSID=r887k5n4scg32d4ba34huuhmq7; path=/
X-Powered-By:PHP/5.4.7

3、当客户端再次访问该网站的页面时,浏览器会将该COOKIE发送给服务端,服务端根据COOKIE的值去读取服务器上存放SESSION的文件,拿到到会话信息,如:
Request Headers
Accept:text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Accept-Encoding:gzip,deflate,sdch
Accept-Language:zh-CN,zh;q=0.8
Cache-Control:max-age=0
Connection:keep-alive
Cookie:PHPSESSID=r887k5n4scg32d4ba34huuhmq7
Host:s.local
User-Agent:Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/31.0.1650.63

所以在会话有效期内,获取到了SESSION ID即获取到了用户的授权,这是比较危险的。客户端可以模拟请求并将COOKIE的内容发送给服务端,服务端根据SESSION ID取到会话内容,从而获得用户权限,以本地的一个管理系统为例,通过chrome登录后查看到客户端COOKIE如下图:


假如如果通过某种手段获取到了SESSION ID, 可以模拟发送一个相同的COOKIE过去即可实现登录。FireFox中可添加COOKIE,打开Firebug后Cookies中新建cookie,确定之后刷新页面即可登录到管理系统,如下图:

通常情况下可通过js获取到cookie,所以需要注意转义,防止数据展示时被执行了。接下来看看CI中的SESSION。在配置文件中有几个跟Session配置相关的参数,影响到Session的使用,它们是:
PHP复制代码
 
//session保存在cookie中的名称
$config['sess_cookie_name'] = 'ci_session';
//session的有效时间
$config['sess_expiration']  = 7200;
//是否关闭浏览器session失效
$config['sess_expire_on_close'] = FALSE;
//SESSION是否加密存放在COOKIE中
$config['sess_encrypt_cookie']  = FALSE;
//是否保存在数据库中
$config['sess_use_database']    = FALSE;
//存在数据库中,则数据库表名
$config['sess_table_name']  = 'ci_sessions';
//是否匹配IP
$config['sess_match_ip']    = FALSE;
//是否匹配UserAgent
$config['sess_match_useragent'] = TRUE;
//更新时间时间
$config['sess_time_to_update']  = 300;
 
复制代码

CI自带的SESSION没有服务端文件存储,所有的信息都存放在客户端COOKIE中,当调用$this->load->library('session');时会启动一个会话,即设置一个COOKIE,COOKIE的内容如下:
Array
(
        [session_id] => f05138a9513e4928cb0a57672cfe3b53
        [ip_address] => 127.0.0.1
        [user_agent] => Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/31.0.1650.63 Safari/537.36
        [last_activity] => 1386569398
        [user_data] =>
)
当客户端请求时会将这些信息在HTTP头中传输给服务端,服务端从HTTP头中读取到SESSION信息。同样的可以实现会话,但该方式有很多的不确定因素,根据源码说几点吧:
1、 如果日志文件中出现:The session cookie data did not match what was expected. This could be a possible hacking attempt.说明两个问题:a.sess_encrypt_cookie为false,SESSION在COOKIE中未加密存放 b.读取到COOKIE后,校验失败。涉及到加解密、参数处理的情况,容易出现匹配不通过的情况,若不通过则清空SESSION。
2、如果sess_match_ip为true,当客户端IP变化时,SESSION将校验不通过,从而清空SESSION。
3、sess_match_useragent默认为true,当客户端UserAgent变化时,校验不通过,清空SESION。简单的例子,通过IE浏览器访问,若切换到不同的IE模式,Agent不同,所以校验不通过,清空SESSION。
可以看到,当出现上面任何一种情况时,SESSION都会清空,出现登录不成功或者跳转到登录页面的情况。如果说不加密、不校验IP、UserAgent呢?因为COOKIE是存放在客户端,需要伴随HTTP请求发给服务端,一来过多的COOKIE会影响速度,对一些图片等资源来说完全时浪费带宽;二来COOKIE只能存储4K的数据,加密处理后能存放的更小。
种种的不确定因素将产生各种奇怪的问题,避免过多的纠结,果断改用其他方式吧。
发表于 2014-1-15 16:09:45 | 显示全部楼层
请问换用什么方式比较好呢?之前关于session的问题也蛋疼了很久~
 楼主| 发表于 2014-1-16 09:29:27 | 显示全部楼层
不把你打哭 发表于 2014-1-15 16:09
请问换用什么方式比较好呢?之前关于session的问题也蛋疼了很久~

PHP原生的方式就挺好,可以重写下session类,现在项目中有用到原生的session和redis的方式。
发表于 2014-7-28 20:40:19 | 显示全部楼层
session也可以存放在数据库啊
发表于 2014-7-28 20:41:18 | 显示全部楼层
Bobby 发表于 2014-1-16 09:29
PHP原生的方式就挺好,可以重写下session类,现在项目中有用到原生的session和redis的方式。
...

能否给个示例代码?
发表于 2014-9-2 10:47:05 | 显示全部楼层
一直感觉session有问题
发表于 2014-9-20 11:51:46 | 显示全部楼层
可以使用那种方式嘛 1:客户端设置cookie的值 就比如说登录的时候 ,
1:判断登录成功之后 我设置一个 键auth_code 为用户的登录信息进行加密(此加密按照你自己的存储方式进行加密 , 此方式很难破解) ,
2:判断的时候获取cookie auth_code 值 然后解密判断即可
发表于 2014-12-4 13:40:40 | 显示全部楼层
keep learning....
发表于 2014-12-12 15:00:18 | 显示全部楼层
努力吧~~SESSION是大问题
发表于 2015-12-5 22:31:27 | 显示全部楼层
还在学习中

本版积分规则