Cookie 和 Session

一、Cookie

Cookie属性项

当前Cookie有两个版本:Version 0和Version 1。通过它们有两种设置响应头的标识,分别是“Set-Cookie”和“Set-Cookie2”。

image

Cookie如何工作

image

真正构建Cookie是在org.apache.catalina.connector. Response类中完成的,调用generateCookieString方法将Cookie对象构造成一个字符串,构造的字符串的格式如userName=“junshan”;Version=“1”; Domain=“xulingbo.net”; Max-Age=1000。然后将这个字符串命名为Set-Cookie添加到MimeHeaders中。
在这里有几点需要注意:
◎ 创建的Cookie的NAME不能和Set-Cookie或者Set-Cookie2的属性项值一样,如果一样会抛IllegalArgumentException异常。
◎ 创建Cookie的NAME和VALUE的值不能设置成非ASSIC字符,如果要使用中文,可以通过URLEncoder将其编码,否则将会抛IllegalArgumentException异常。
◎ 当NAME和VALUE的值出现一些TOKEN字符(如“\”、“,”等)时,构建返回头会将该Cookie的Version自动设置为1。
◎ 当该Cookie的属性项中出现Version为1的属性项时,构建HTTP响应头同样会将Version设置为1。

使用Cookie的限制
image

二、Session

Cookie可以让服务端程序跟踪每个客户端的访问,但是每次客户端的访问都必须传回这些Cookie,如果Cookie很多,这无形地增加了客户端与服务端的数据传输量,而Session的出现正是为了解决这个问题。
同一个客户端每次和服务端交互时,不需要每次都传回所有的Cookie值,而是只要传回一个ID,这个ID是客户端第一次访问服务器的时候生成的,而且每个客户端是唯一的。
这样每个客户端就有了一个唯一的ID,客户端只要传回这个ID就行了,这个ID通常是NANE为JSESIONID的一个Cookie。

Session与Cookie

下面详细讲一下Session如何基于Cookie来工作。实际上有三种方式能可以让Session正常工作:
◎ 基于URL Path Parameter,默认支持。
◎ 基于Cookie,如果没有修改Context容器的cookies标识,默认也是支持的。
◎ 基于SSL,默认不支持,只有connector.getAttribute("SSLEnabled")为TRUE时才支持。
Session如何工作
有了Session ID服务端就可以创建HttpSession对象了,第一次触发通过request.getSession()方法。
如果当前的Session ID还没有对应的HttpSession对象,那么就创建一个新的,并将这个对象加到org.apache.catalina. Manager的sessions容器中保存。
Manager类将管理所有Session的生命周期,Session过期将被回收,服务器关闭,Session将被序列化到磁盘等。
只要这个HttpSession对象存在,用户就可以根据Session ID来获取这个对象,也就达到了状态的保持。

image

session恢复
StandardManager类负责Servlet容器中所有的StandardSession对象的生命周期管理。
当Servlet容器重启或关闭时StandardManager负责持久化没有过期的StandardSession对象,它会将所有的StandardSession对象持久化到一个以“SESSIONS.ser”为文件名的文件中。
到Servlet容器重启时,也就是StandardManager初始化时,会重新读取这个文件解析出所有Session对象,重新保存在StandardManager的sessions集合中。

session过期
当Servlet容器关闭时StandardManager类会调用unload方法将sessions集合中的StandardSession对象写到“SESSIONS.ser”文件中,然后在启动时再按照上面的状态图重新恢复,
注意要持久化保存Servlet容器中的Session对象,必须调用Servlet容器的stop和start命令,而不能直接结束(kill)Servlet容器的进程,因为直接结束进程,Servlet容器没有机会调用unload方法来持久化这些Session对象。

另外,StandardManager中的sessions集合中的StandardSession对象并不是永远保存的,否则Servlet容器的内存将很容易被消耗尽,
所以必须给每个Session对象定义一个有效时间,超过这个时间Session对象将被清除。
在Tomcat中这个有效时间是60(maxInactiveInterval属性控制)秒,超过60秒该Session将会过期。检查每个Session是否失效是在Tomcat的一个后台线程中完成的(backgroundProcess()方法中)。

了后台进程检查Session是否失效外,当调用request.getSession()时也会检查该Session是否过期。
值得注意的是,request.getSession()方法调用的StandardSession永远都会存在,即使与这个客户端关联的Session对象已经过期。
如果过期,又会重新创建一个全新的StandardSession对象,但是以前设置的Session值将会丢失。

如果你取到了Session对象但是通过session.getAttribute取不到前面设置的Session值,请不要奇怪,因为很可能它已经失效了,请检查一下<Manager pathname="" maxInactiveInterval="60" />中maxInactiveInterval配置项的值,如果不想让Session过期可以设置为-1。
Cookie安全问题
虽然Cookie和Session都可以跟踪客户端的访问记录,但是它们的工作方式显然是不同的,Cookie通过把所有要保存的数据通过HTTP协议的头部从客户端传递到服务端,
又从服务端再传回到客户端,所有的数据都存储在客户端的浏览器里,所以这些Cookie数据可以被访问到,就像我们前面通过Firefox的插件HttpFox可以看到所有的Cookie值。
不仅可以查看Cookie,甚至可以通过Firecookie插件添加、修改Cookie,所以Cookie的安全性受到了很大的挑战。

相比较而言Session的安全性要高很多,因为Session是将数据保存在服务端,只是通过Cookie传递一个SessionID而已,所以Session更适合存储用户隐私和重要的数据。

分布式Session框架

Session和Cookie各自有优点和缺点。在大型互联网系统中,单独使用Cookie和Session都是不可行的,原因很简单。
因为如果使用Cookie,可以很好地解决应用的分布式部署问题,大型互联网应用系统一个应用有上百台机器,而且有很多不同的应用系统协同工作,
由于Cookie是将值存储在客户端的浏览器里,用户每次访问都会将最新的值带回给处理该请求的服务器,所以也就解决了同一个用户的请求可能不在同一台服务器处理而导致的Cookie不一致的问题。

存在哪些问题
    ◎ 客户端Cookie存储限制。随着应用系统的增多Cookie数量也快速增加,但浏览器对于用户Cookie的存储是有限制的。
    ◎ Cookie管理的混乱。
    ◎ 安全令人担忧。
    
下面是分布式Session框架可以解决的问题:
◎ Session配置的统一管理。
◎ Cookie使用的监控和统一规范管理。
◎ Session存储的多元化。
◎ Session配置的动态修改。
◎ Session加密key的定期修改。
◎ 充分的容灾机制,保持框架的使用稳定性。
◎ Session各种存储的监控和报警支持。
◎ Session框架的可扩展性,兼容更多的session机制如wapSession。
◎ 跨域名Session与Cookie如何共享,现在同一个网站可能存在多个域名,如何将Session和Cookie在不同的域名之间共享是一个具有挑战性的问题。

总体实现思路

为了达成上面所说的几点目标,我们需要一个服务订阅服务器,在应用启动时可以从这个订阅服务器订阅这个应用需要的可写Session项和可写Cookie项,这些配置的Session和Cookie可以限制这个应用能够使用哪些Session和Cookie,
甚至可以控制Session和Cookie可读或者可写。这样可以精确地控制哪些应用可以操作哪些Session和Cookie,可以有效控制Session的安全性和Cookie的数量。

统一通过订阅服务器推送配置可以有效地集中管理资源,所以可以省去每个应用都来配置Cookie,简化Cookie的管理。如果应用要使用一个新增Cookie,可以通过一个统一的平台来申请,
申请通过才将这个配置项增加到订阅服务器。如果是一个所有应用都要使用的全局Cookie,那么只需将这个Cookie通过订阅服务器统一推送过去就行了,省去了要在每个应用中手动增加Cookie的配置。
关于这个订阅服务器现在有很多开源的配置服务器,如Zookeeper集群管理服务器,可以统一管理所有服务器的配置文件。

image

image

Cookie压缩

Cookie是在HTTP的头部,所以通常的gzip和deflate针对HTTP Body的压缩不能压缩Cookie,如果Cookie量非常大,可以考虑将Cookie也做压缩,压缩方式是将Cookie的多个k/v对看成普通的文本,做文本压缩。
压缩算法同样可以使用gzip和deflate算法,但是需要注意的一点是,根据Cookie的规范,Cookie中不能包含控制字符,仅仅只能包含ASCII码为(34~126)的可见字符。所以要将压缩后的结果再进行转码,可以进行Base32或者Base64编码。

表单重复提交问题

要能够防止表单重复提交,就要标识用户的每一次访问请求,使得每一次访问对服务端来说都是唯一确定的。为了标识用户的每次访问请求,可以在用户请求一个表单域时增加一个隐藏表单项,这个表单项的值每次都是唯一的token。
当用户在请求时生成这个唯一的token时,同时将这个token保存在用户的Session中,等用户提交请求时检查这个token和当前的Session中保存的token是否一致。如果一致,说明没有重复提交,否则用户提交上来的token已经不是当前的这个请求的合法token。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值