cookie和session 详析

一、    基本概念

Cookie和Session都是为了保存用户与后端服务器的交互状态,基本来说Cookie是存在客户端浏览器中,每次访问服务器都带着,HTTP请求字段中就有一个Cookie字段携带信息;而Session是存在服务器端的,每次用户携带一个SID过来服务器就知道是谁了。

问题:HTTP对Cookie的大小是有限制的,假如一天的PV有几个亿,每个Cookie几百个字节,那就大大的占用了网络带宽;而Session在分布式集群时如何保持同步也是一个难题?

 

面试Cookie和Session区别:

1、cookie数据存放在客户的浏览器上,session数据放在服务器上。

2、cookie不是很安全,别人可以分析存放在本地的COOKIE并进行COOKIE欺骗
   考虑到安全应当使用session。

3、session会在一定时间内保存在服务器上。当访问增多,会比较占用你服务器的性能
   考虑到减轻服务器性能方面,应当使用COOKIE。

4、单个cookie保存的数据不能超过4K,很多浏览器都限制一个站点最多保存20个cookie。

5、所以个人建议:
   将登陆信息等重要信息存放为SESSION
   其他信息如果需要保留,可以放在COOKIE中

二、    Cookie总结

2.1 基本格式

  • NAME=VALUE:键值对,设置要保存的key/value
  • Expires:过期时间,如果不设置过期时间则表示会话Cookie,生命周期是浏览器会话器件,保存在内存中,浏览器关闭则消失;否则保存在硬盘上,可以在不同的浏览器进程间共享;
  • Domain:生成该Cookie的域名,如:domain=”xunbo.net”;
  • Path:该Cookie是当前那个路径下生成的,比如:path=/wp-admin/;
  • Secure:如果设置了该属性,那么只有在SSH连接时才会返回该Cookie;
  • Comment:注释;
  • Port:该Cookie在什么端口下可以回传服务端,多个端口以逗号隔开;

2.2 HTTP协议和Cookie相关的字段

  • HTTP请求头:Cookie字段携带保存的Cookie信息发送到服务器端
  • HTTP响应头:Set-Cookie字段携带Cookie信息,例如: Set-Cookie: sc=4c31523a; path=/; domain=.acookie.taobao.com

2.3 Cookie大小限制

         虽然HTTP本身并没有限制Cookie大小,但是浏览器考虑到内存占用和网络带宽给出了Cookie大小限制;而且Cookie太长,有可能SID冲没了,导致Session丢失。

以下数据不准确,各个博客给出的不一致:和浏览器版本有关

  • FireFox浏览器:每个域名最多50个;Cookie总大小4097个字节;
  • Chrome浏览器:每个域名最多50个;Cookie总大小4097个字节;

自己在前端用JS写一个函数:

 

 

 2.4 Servlet中如何写Cookie

 

注意:

  • 创建的Cookie的Name不能和属性值相同,否则会抛出异常;
  • 创建的Cookie的NAME和Value都必须是ASCII字符,如果要支持中文,必须先URLEncoder将其编码,否则会抛出异常;
  • NAME 和 VALUE 的值出现一些 TOKEN 字符(如“\”、“,”等)时,构建返回头会将该 Cookie 的 Version 自动设置为 1。
  • 注意每个addCookie方法会给HTTP响应头中创建一个Set-Cookie,所以最终会有多个;

 

2.5 Cookie的安全性问题

虽然 Cookie 和 Session 都可以跟踪客户端的访问记录,但是它们的工作方式显然是不同的,Cookie 通过把所有要保存的数据通过 HTTP协议的头部从客户端传递到服务端,又从服务端再传回到客户端,所有的数据都存储在客户端的浏览器里,所以这些 Cookie 数据可以被访问到,就像我们前面通过 Firefox 的插件 HttpFox 可以看到所有的 Cookie 值。不仅可以查看 Cookie,甚至可以通过 Firecookie 插件添加、修改 Cookie,所以 Cookie 的安全性受到了很大的挑战。

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

 

2.6 Cookie压缩问题

Cookie 是在 HTTP 的头部,所以通常的 gzip 和 deflate 针对 HTTP Body 的压缩不能压缩 Cookie,如果 Cookie 量非常大,可以考虑将 Cookie 也做压缩,压缩方式是将 Cookie 的多个 k/v 对看成普通的文本,做文本压缩。

压缩算法同样可以使用 gzip 和 deflate 算法,但是需要注意的一点是,根据 Cookie 的规范,Cookie 中不能包含控制字符,仅仅只能包含 ASCII 码为(34 ~ 126)的可见字符。所以要将压缩后的结果再进行转码,可以进行 Base32 或者 Base64 编码。

可以配置一个 Filter 在页面输出时对 Cookie 进行全部或者部分压缩。

 

上面的代码是用 DeflaterOutputStream 对 Cookie 进行压缩的,Deflater 压缩后再进行 BASE64 编码,相应地用InflaterInputStream 进行解压。

 

2KB 大小的 Cookie 压缩前与压缩后字节数相差 20% 左右,如果您的网站的 Cookie 在 2KB~3KB 左右,一天有 1 亿的 PV,那么一天就能够产生 4TB 的带宽流量了,从节省带宽成本来说压缩还是很有必要的。

 

三、    Session总结

如果Cookie太多,则会增加网络流量,因此服务端Session机制应运而生;同一个客户端每次和服务端交互时,不需要每次都传回所有的Cookie值,而只是传回一个ID即可;这个ID是客户端第一次访问服务器端自动生成的,而且保证每个客户端是唯一的。ID通常是一个NAME为JSESIONID的一个Cookie。

3.1 Session机制如何实现

  • 基于URL Path Parameter,默认支持;
  • 基于Cookie,如果没有修改Context容器的Cookies标识,默认是支持的;
  • 基于SSL,默认不支持,只有connector.getAttributes(”SSLEnabled”)为true时才支持;

 

客户端禁止Cookie怎么回传SessionID面试回答:

  • 经常使用的一个技术是URL重写,就是把SessionID直接附加到URL后面,比如:www.netesay.com?key1=value1&key2=value2
  • 表单隐藏;服务器会自动修改表单,添加一个隐藏字段,以便在提交表单的时候能够把Session-ID传递回服务器;比如:

<form name="testform" action="/xxx"> 
<input type="hidden" name="jsessionid" value="ByOK3vjFD75aPnrF7C2HmdnV6QZcEbzWoWiBYEnLerjQ99zWpBng!-145788764"> 
<input type="text"> 
</form> 

 

注意:

  • 第一中情况下,当浏览器不支持Cookie功能时,浏览器会自动将用户的SessionCookieName重写到URL参数中。关于这个SessionCookieName,如果在web.xml中配置session-config配置项,其name属性就是这个SessionCookieName值;如果没有配置name属性那么就是大家熟悉的JSESSIONID;接着Request根据这个SessionCookieName到Parameters中拿到SessionID并设置到request.setRequestSessionId中;
  • 如果客户端支持Cookie,Tomcat仍然会解析Cookie中的SessionID,并且会覆盖URL中的SessionID;
  • 第三种情况,将会根据javax.servlet.request.ssl_session属性设置SessionID;

 

3.2 Session如何工作

有了SessionID服务端就可以创建HttpSession对象了,第一次触发是requst的getSession()方法。如果当前的SessionID还没有对应的HttpSession对象,那就创建一个新的,并将这个对象加到org.apache.catalina.Manager的sessions容器中保存。

Manager容器会管理所有的Session的生命周期,Session过期将会被回收,服务器关闭,Session将会被序列化保存到硬盘上。只要这个HttpSession对象存在,用户就可以根据SessionID来获取这个对象,也就达到了状态的保持。

 

  • 面试回答:

当程序需要为某个客户端的请求创建一个session时,服务器首先检查这个客户端的请求里是否已包含了一个session标识(称为session id),如果已包含则说明以前已经为此客户端创建过session,服务器就按照session id把这个session检索出来使用(检索不到,会新建一个),如果客户端请求不包含session id,则为此客户端创建一个session并且生成一个与此session相关联的session id,session id的值应该是一个既不会重复,又不容易被找到规律以仿造的字符串,这个session id将被在本次响应中返回给客户端保存。保存这个session id的方式可以采用cookie,这样在交互过程中浏览器可以自动的按照规则把这个标识发送给服务器。

 

  • Session如何恢复?

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

 

 

四、    分布式Session问题

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

4.1 大面积使用Cookie的隐患

使用Cookie就是“谁家的孩子谁抱走”确实比较简单,但是也带来很多问题:

  • 一般客户端浏览器对Cookie数量和大小有限制,50个以内,总大小4k以内;
  • Cookie管理混乱。在大型互联网系统中,如果每个应用系统都自己管理每个应用使用的Cookie,将会导致混乱;
  • 安全令人担忧,Cookie很容易被查看、篡改。

4.2 分布式Session架构图

4.2.1 统一订阅服务器

统一通过订阅服务器推送配置可以有效地集中管理资源,所以可以省去每个应用都来配置 Cookie,简化 Cookie 的管理。

如果应用要使用一个新增 Cookie,可以通过一个统一的平台来申请,申请通过才将这个配置项增加到订阅服务器。

如果是一个所有应用都要使用的全局 Cookie,那么只需将这个 Cookie 通过订阅服务器统一推送过去就行了,省去了要在每个应用中手动增加 Cookie 的配置。

关于这个订阅服务器现在有很多开源的配置服务器,如 Zookeeper 集群管理服务器,可以统一管理所有服务器的配置文件。

 

4.2.2 分布式缓存

由于应用是一个集群,所以不可能将创建的 Session 都保存在每台应用服务器的内存中,因为如果每台服务器有几十万的访问用户,服务器的内存肯定不够用,即使内存够用,这些 Session 也无法同步到这个应用的所有服务器中。

所以要共享这些 Session 必须将它们存储在一个分布式缓存中,可以随时写入和读取,而且性能要很好才能满足要求。当前能满足这个要求的系统有很多,如 MemCache 或者淘宝的开源分布式缓存系统 Tair 都是很好的选择。

 

 

4.2.3 存取Session和Cookie的步骤

既然是一个分布式 Session 的处理框架,必然会重新实现 HttpSession 的操作接口,使得应用操作 Session 的对象都是我们实现的InnerHttpSession 对象,这个操作必须在进入应用之前完成,所以可以配置一个 filter 拦截用户的请求。

先看一下如何封装 HttpSession 对象和拦截请求,图 10-10 是时序图。

我们可以在应用的 web.xml 中配置一个 SessionFilter,用于在请求到达 MVC 框架之前封装 HttpServletRequest 和HttpServletResponse 对象,并创建我们自己的 InnerHttpSession 对象,把它设置到 request 和 response 对象中。这样应用系统通过 request.getHttpSession() 返回的就是我们创建的 InnerHttpSession 对象了,我们可以拦截 response 的 addCookies 设置的 Cookie。

在时序图中,应用创建的所有 Session 对象都会保存在 InnerHttpSession 对象中,当用户的这次访问请求完成时,Session 框架将会把这个 InnerHttpSession 的所有内容再更新到分布式缓存中,以便于这个用户通过其他服务器再次访问这个应用系统。

另外,为了保证一些应用对 Session 稳定性的特殊要求可以将一些非常关键的 Session 再存储到 Cookie 中,如当分布式缓存存在问题时,可以将部分 Session 存储到 Cookie 中,这样即使分布式缓存出现问题也不会影响关键业务的正常运行。

 

 

 

4.2.4 跨域名共享Cookie和Session

参考:http://my.oschina.net/kevinair/blog/192829#OSC_h2_19

我们知道 Cookie 是有域名限制的,也就是一个域名下的 Cookie 不能被另一个域名访问,所以如果在一个域名下已经登录成功,如何访问到另外一个域名的应用且保证登录状态仍然有效,这个问题大型网站应该经常会遇到。如何解决这个问题呢?

下面介绍一种处理方式,如图 10-11 所示。

要实现 Session 同步,需要另外一个跳转应用,这个应用可以被一个或者多个域名访问,它的主要功能是从一个域名下取得 sessionID,然后将这个 sessionID 同步到另外一个域名下。这个 sessionID 其实就是一个 Cookie,相当于我们经常遇到的 JSESSIONID,所以要实现两个域名下的 Session 同步,必须要将同一个 sessionID 作为 Cookie 写到两个域名下。

总共 12 步,一个域名不用登录就取到了另外一个域名下的 Session,当然这中间有些步骤还可以简化,也可以做一些额外的工作,如可以写一些需要的 Cookie,而不仅仅只传一个 sessionID。

 

4.2.5 解决Cookie盗取问题

该框架还能处理 Cookie 被盗取的问题。如您的密码没有丢失,但是您的账号却有可能被别人登录的情况,这种情况很可能就是因为您登录成功后,您的 Cookie 被别人盗取了,盗取您的 Cookie 的人将您的 Cookie 加入到他的浏览器,然后他就可以通过您的 Cookie 正常访问您的个人信息了,这是一个非常严重的问题。

在这个框架中我们可以设置一个 Session 签名,当用户登录成功后我们根据用户的私密信息生成的一个签名,以表示当前这个唯一的合法登录状态,然后将这个签名作为一个 Cookie 在当前这个用户的浏览器进程中和服务器传递,用户每次访问服务器都会检查这个签名和从服务端分布式缓存中取得的 Session 重新生成的签名是否一致,如果不一致,显然这个用户的登录状态不合法,服务端将清除这个 sessionID 在分布式缓存中的 Session 信息,让用户重新登录。

 

五、       表单重复提交问题

网站中在很多地方都有表单重复提交问题,一种情况是用户在网速慢的情况下可能会重复提交表单,还有就是恶意用户通过程序来发送恶意请求,在这些情况下都要设计一个防止表单重复提交的机制。

参考:http://www.cnblogs.com/lovebaoqiang/p/3753488.html

(1)对按钮进行控制

1

2

3

4

var $button = document.getElementById("btn");//获取button对象

   $button.attr("disabled","disabled");

   window.setTimeout(function(){

   $button.removeAttr("disabled");},1000);

当然这么操作的前提是,你在disbaled后,要对表单进行处理,比如清空操作...

(2)做状态位进行标识...

1

2

3

4

5

6

7

8

9

10

11

12

13

<script language="javascript">

var checkSubmitFlg = false;

function checkSubmit() {

    if (!checkSubmitFlg) {

        checkSubmitFlg = true;

        return true;

        }

    else{

            alert("不能重复提交");

            return false;

            }

}

</script>

<form action="XXXX" method="POST" οnsubmit="return checkSubmit()">

内容:<input type="text" name="content" value=""/><br>

<input type="submit" value="提交"><br>

</form>

疑问:做这种标识,如何判断你是换了另一个表单...

(3)加验证码,在每次提交时进行验证...防止重复提交..

后台程序解决:
大概主要用到一个token机制..
可以参考struts2的token机制,还有Token Session(令牌机制)
在每次表单提交时,action会调用isValidToken()方法,进行判断是否相同的token,如果相同,进行提交,如果不同,认为是重复提交..
当然这种前提是:在你打开新增表单的时候,会调用action,生成token码..然后在你的表单和session中各保存一份,当提交调用action时,会进行token检查,并且在action处理完后,会重置session 中的token,此时你再提交,就会导致token不一致,没法提交...当然...意思就是要重新调用action生成新的token,和session保持一致...

要能够防止表单重复提交,就要标识用户的每一次访问请求,使得每一次访问对服务端来说都是唯一确定的。为了标识用户的每次访问请求,可以在用户请求一个表单域时增加一个隐藏表单项,这个表单项的值每次都是唯一的 token,如:

 <form id=”form” method=”post”> 

 <input type=hidden name=“crsf_token” value=“xxxx”/> 

</form>

当用户在请求时生成这个唯一的 token 时,同时将这个 token 保存在用户的 Session 中,等用户提交请求时检查这个 token 和当前的Session 中保存的 token 是否一致。如果一致,说明没有重复提交,否则用户提交上来的 token 已经不是当前的这个请求的合法 token。其工作过程如图 10-12 所示。

5.1 发起请求

图 10-12.工作过程

图 10-12 是用户发起对表单页面的请求过程,生成唯一的 token 需要一个算法,最简单的就是可以根据一个种子作为 key 生成一个随机数,并保存在 Session 中,等下次用户提交表单时做验证。验证表单的过程如图 10-13 所示。

5.2 表单验证

 

当用户提交表单时会将请求时生成的 token 带回来,这样就可以和 Session 中保存的 token 做对比,从而确认这次表单验证是否合法。

六、       总结

Cookie 和 Session 都是为了保持用户访问的连续状态,之所以要保持这种状态,一方面是为了方便业务实现,另一方面就是简化服务端程序设计,提高访问性能,但是这也带来了另外一些挑战,如安全问题、应用的分布式部署带来的 Session 的同步问题及跨域名 Session 的同步等一系列问题。本章分析了 Cookie 和 Session 的工作原理,并介绍了一致分布式 Session 的解决方案。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
基于Django+python编写开发的毕业生就业管理系统支持学生教师角色+db数据库(毕业设计新项目).zip 【备注】 1、该资源内项目代码都经过测试运行成功,功能ok的情况下才上传的,请放心下载使用!有问题请及时沟通交流。 2、适用人群:计算机相关专业(如计科、信息安全、数据科学与大数据技术、人工智能、通信、物联网、自动化、电子信息等)在校学生、专业老师或者企业员工下载使用。 3、用途:项目具有较高的学习借鉴价值,不仅适用于小白学习入门进阶。也可作为毕设项目、课程设计、大作业、初期项目立项演示等。 4、如果基础还行,或热爱钻研,亦可在此项目代码基础上进行修改添加,实现其他不同功能。 欢迎下载!欢迎交流学习!不清楚的可以私信问我! 基于Django+python编写开发的毕业生就业管理系统支持学生教师角色+db数据库(毕业设计新项目).zip基于Django+python编写开发的毕业生就业管理系统支持学生教师角色+db数据库(毕业设计新项目).zip基于Django+python编写开发的毕业生就业管理系统支持学生教师角色+db数据库(毕业设计新项目).zip基于Django+python编写开发的毕业生就业管理系统支持学生教师角色+db数据库(毕业设计新项目).zip基于Django+python编写开发的毕业生就业管理系统支持学生教师角色+db数据库(毕业设计新项目).zip基于Django+python编写开发的毕业生就业管理系统支持学生教师角色+db数据库(毕业设计新项目).zip基于Django+python编写开发的毕业生就业管理系统支持学生教师角色+db数据库(毕业设计新项目).zip基于Django+python编写开发的毕业生就业管理系统支持学生教师角色+db数据库(毕业设计新项目).zip基于Django+python编写开发的毕业生就业管理系统支持学生教师角色+db数据库(毕业设计新项目).zip
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值