诺亚方舟

沉淀

深入了解cookie与session

两年前整理了一篇关于cookie与session的文章,SESSION,如何让你的网站盘活起来!? ,然后大概近一年很少碰到这块知识,忘了7788,近期处理一个项目的时候重温了这块知识,基础知识就不再重复叙述,这里做深入一层的了解cookie与session。 一、cookie的组成 cookie存在于浏览器(客户端),这是个常识,那么在写一个cookie的时候需要哪些组成,下面介绍一下。 cookie 从上面的截图可以看出,浏览器中cookie的信息包括6个内容,Name和Value代表cookie的key与值,不多介绍。Domain指向的是cookie有效的域名,与Path两个字段组成cookie的有效范围。 Path可以指定与cookie关联的WEB页,严格控制cookie在一个域名下的有效区域,值可以是一个目录,或者是一个路径。如果http://www.a.com/devhead/index.html 建立了一个cookie,那么在http://www.a.com/devhead/目录里的所有页面,以及该目录下面任何子目录里的页面都可以访问这个cookie。这就是说,在http://www.a.com/devhead/stories/articles 里的任何页面都可以访问http://www.a.com/devhead/index.html建立的cookie。但是,如果http://www.a.com/zdnn/ 需要访问http://www.a.com/devhead/index.html设置的cookes,该怎么办?这时,我们要把cookies的path属性设置成“/”。在指定路径的时候,凡是来自同一域名,URL里有相同路径的所有WEB页面都可以共享cookies。现在看另一个例子:如果想让 http://www.a.com/devhead/filters/ 和http://www.a.com/devhead/stories/共享cookies,就要把path设成“/devhead”。 Expires,有效期,不介绍了。另外介绍的一个字段是Secure,这个属性的值或者是“secure”,或者为空。缺省情况下,该属性为空,也就是使用不安全的HTTP连接传递数据。如果一个 cookie 标记为secure,那么,它与WEB服务器之间就通过HTTPS或者其它安全协议传递数据。不过,设置了secure属性不代表其他人不能看到你机器本地保存的cookie。换句话说,把cookie设置为secure,只保证cookie与WEB服务器之间的数据传输过程加密,而保存在本地的 cookie文件并不加密。如果想让本地cookie也加密,得自己加密数据。 二、服务端(php)SESSION机制 众所周知,http是无状态的协议,那通讯状态就需要第三方来协助维护,cookie与session应运而生。cookie是保存在客户端的数据,session是保存在服务端的数据,那服务端靠什么在请求中找到上一次会话的保存状态?php处理session有多种方式,一种是files,一种是user,也可以是memcache(查看php.ini的session.save_handler值),本文只介绍常用的files方式。 PHP读取SESSION流程: 1、session_start() a、session_start ()是session机制的开始,它有一定概率开启垃圾回收 , 因为session是存放在文件中,PHP自身的垃圾回收是无效的,SESSION的回收是要删文件的,这个概率是根据php . ini的配置决定的,但是有的系统是 session . gc_probability = 0 ,这也就是说概率是0,而是通过cron脚本来实现垃圾回收。

1
2
3
4
5
6
session . gc_probability = 1
session . gc_divisor = 1000
session . gc_maxlifetime = 1440 // 过期时间 默认24分钟
//概率是 session.gc_probability/session.gc_divisor 结果 1/1000,
//不建议设置过小,因为session的垃圾回收,是需要检查每个文件是否过期的。
session . save_path = // 好像不同的系统默认不一样,有一种设置是 "N;/path"//这是随机分级存储,这个样的话,垃圾回收将不起作用,需要自己写脚本 ,默认状态下会保存到/tmp下,session文件以"sess_"开头,以session_id()结尾。例如:sess_0e8re7kiv9o0kvckhtqemeuk00。

b、session会判断当前请求中是否有 $_COOKIE [ session_name ()]; session_name ()返回保存session_id的COOKIE键值,这个值可以从php . ini找到,也可以利用session_name()设置一个cookie name。

1
session . name = PHPSESSID // 默认值PHPSESSID

c、 如果不存在会生成一个session_id , 然后把生成的session_id作为COOKIE的值传递到客户端 . 相当于执行了下面COOKIE 操作,注意的是,这一步执行了setcookie()操作,COOKIE是在header头中发送的,这之前是不能有输出的,PHP有另外一个函数 session_regenerate_id () 如果使用这个函数,这之前也是不能有输出的。

1
2
3
4
5
6
setcookie ( session_name () ,
session_id () ,
session . cookie_lifetime , // 默认0
session . cookie_path , // 默认'/'当前程序跟目录下都有效
session . cookie_domain , // 默认为空
)

d、如果存在那么session_id = $_COOKIE [ session_name ];然后去session . save_path指定的文件夹里去找名字为 ’ SESS_ ’ . session_id ()的文件 . 读取文件的内容反序列化,然后放到 $_SESSION中。怎么去查看session保存内容?如果session.save_handler为files,则到设置目录下查看以sess_开拓,session_id结尾的文件内容,我这里win下目录为D:\wamp\tmp,如果为session.save_handler为memcache,则telnet到该端口get session_id即可。 注意:这里有个技巧,当http请求不支持cookie时,比方说是sdk客户端与服务器通话,那怎么来维持上下文?很简单,只要把session_id通过get参数传到服务器,服务器用动态设置session_id($_GET['session_id']);就可以恢复会话。 2、为 $_SESSION赋值 比如新添加一个值 $_SESSION [ ' test ' ] = ’ blah ’ ; 那么这个 $_SESSION只会维护在内存中 ,当脚本执行结束的时候,用把 $_SESSION的值写入到session_id指定的文件夹中 ,然后关闭相关资源 .       这个阶段有可能执行更改session_id的操作,比如销毁一个旧的的session_id,生成一个全新的session_id . 一半用在自定义 session操作,角色的转换上,比如Drupal . Drupal的匿名用户有一个SESSION的,当它登录后需要换用新的session_id。

1
2
3
4
5
if ( isset ( $_COOKIE [ session_name ()])) {
setcookie ( session_name () , '' , time () - 42000 , ' / ' ); // 旧session cookie过期
}
session_regenerate_id (); // 这一步会生成新的session_id
//session_id()返回的是新的值

3、 写入SESSION操作 在脚本结束的时候会执行SESSION写入操作,把 $_SESSION中值写入到session_id命名的文件中 ,可能已经存在, 可能需要创建新的文件。 4、销毁SESSION SESSION发出去的COOKIE一般属于即时COOKIE,保存在内存中,当浏览器关闭后,才会过期,假如需要人为强制过期, 比如 退出登录,而不是关闭浏览器,那么就需要在代码里销毁SESSION,方法有很多,

1
2
3
/*1*/ setcookie ( session_name () , session_id () , time () - 8000000 , .. ); // 退出登录前执行 
/*2*/ usset( $_SESSION ); // 这会删除所有的$_SESSION数据,刷新后,有COOKIE传过来,但是没有数据。 
/*3*/ session_destroy (); // 这个作用更彻底,删除$_SESSION 删除session文件,和session_id

当不关闭浏览器的情况下,再次刷新,2和3都会有COOKIE传过来,但是找不到数据。 简而言之,浏览器与服务器会话过程中,服务器会生成一个session_id,以session_name为key(默认值为PHPSESSID),session_id为值给浏览器设置cookie(又叫session cookie,区别于persistent cookie),下次请求时浏览器带上这个cookie让服务器找出上次会话的上下文内容。 三、跨域设置cookie 介绍完cookie与session的原理,探讨下常见的cookie跨域问题。 如果是在同个域名下,多级域名的设置有以下技巧, 1)如果需要设置某一个域名下,所有路径生效–domain:abc.com path:/ 2)设置顶级域名,多级域名cookie生效–domain:abc.com path:/ 3)*.abc.com或.abc.com 对二级域名都会生效,对主域abc.com不生效; abc.com会对一级、二级域名均生效。 思考:那多级域名怎么实现共享session? 答案也很简单,理解了http保存上下文会话信息后,我们知道session_id 的处理机制是先读取,空时再生成,那我们只要让其session_id对应的cookie多级域名可读就行了。 跨域写cookie,最常见的场景应该是跨站登录。为了安全,浏览器只会接受当前域设置的cookie,当服务端(abc.com)设置跨域(xxy.com)的cookie时,并不会报错,但是浏览器在接口http包时会自动把该cookie忽略,那很常见的 一种情景,如果A站点、B站点需要实现单点登录要怎么实现?一个很有效的方案是在A站点的a.com/index.php页面设置一个iframe,引入B站点的一个页面b.com/inc.php,b.php实现很简单如下:

1
setcookie('name','value');

这样就可以很方便的给a.com设置b.com的cookie,类似的html标签还有img、link等,当这些标签跨域应用一个页面,实际上是发起了一次GET请求。然后问题又来了, ie下这种方式也是不可用的,就要利用到P3P,在PHP文件头部加  header(‘P3P:CP=”IDC DSP COR ADM DEVi TAIi PSA PSD IVAi IVDi CONi HIS OUR IND CNT”‘); 或者header(“P3P: CP=CURa ADMa DEVa PSAo PSDo OUR BUS UNI PUR INT DEM STA PRE COM NAV OTC NOI DSP COR”); 值得注意的是,P3P header只需要设置一次,这样跟在这个P3P header后面的所有 set-cookie,都可以跨域访问了。也就是说: 被P3P header设置过一次后,之后的请求不再需要P3P header,也能够在iframe里跨域发送这些cookie。 四、javascript操作cookie

?View Code JAVASCRIPT
1
2
3
4
//获取页面cookie
document.cookie
//设置页面cookie
document.cookie = "username=Darren;path=/;domain=qq.com"//不同字段间用;分隔

参考文章:

copy一篇文章,主要看看 cookie 的 path 和 domain

彻底明白php的session机制

【转】PHP有关跨域的请求header(“P3P: CP=CURa ADMa…)cookie -session解决方法

JavaScript 操作 Cookie

发表评论

电子邮件地址不会被公开。 必填项已用*标注

您可以使用这些HTML标签和属性: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>