Web开发

首页 » 常识 » 预防 » 一文彻底弄懂cookiesession
TUhjnbcbe - 2024/5/15 17:06:00

前言

作为一个JAVA开发,之前有好几次出去面试,面试官都问我,JAVAWeb掌握的怎么样,我当时就不知道怎么回答,Web,日常开发中用的是什么?今天我们来说说JAVAWeb最应该掌握的三个内容。

发展历程

1、很久很久以前,Web基本上就是文档的浏览而已,既然是浏览,作为服务器,不需要记录谁在某一段时间里都浏览了什么文档,每次请求都是一个新的HTTP协议,就是请求加响应,尤其是我不用记住是谁刚刚发了HTTP请求,每个请求对我来说都是全新的。

2、但是随着交互式Web应用的兴起,像在线购物网站,需要登录的网站等等,马上就面临一个问题,那就是要管理会话,必须记住哪些人登录系统,哪些人往自己的购物车中放商品,也就是说我必须把每个人区分开,这就是一个不小的挑战,因为HTTP请求是无状态的,所以想出的办法就是给大家发一个会话标识(sessionid),说白了就是一个随机的字串,每个人收到的都不一样,每次大家向我发起HTTP请求的时候,把这个字符串给一并捎过来,这样我就能区分开谁是谁了。

3、这样大家很嗨皮了,可是服务器就不嗨皮了,每个人只需要保存自己的sessionid,而服务器要保存所有人的sessionid!如果访问服务器多了,就得由成千上万,甚至几十万个。

这对服务器说是一个巨大的开销,严重的限制了服务器扩展能力,比如说我用两个机器组成了一个集群,小F通过机器A登录了系统,那sessionid会保存在机器A上,假设小F的下一次请求被转发到机器B怎么办?机器B可没有小F的sessionid啊。

有时候会采用一点小伎俩:sessionsticky,就是让小F的请求一直粘连在机器A上,但是这也不管用,要是机器A挂掉了,还得转到机器B去。

那只好做session的复制了,把sessionid在两个机器之间搬来搬去,快累死了。

后来有个叫Memcached的支了招:把sessionid集中存储到一个地方,所有的机器都来访问这个地方的数据,这样一来,就不用复制了,但是增加了单点失败的可能性,要是那个负责session的机器挂了,所有人都得重新登录一遍,估计得被人骂死。

也尝试把这个单点的机器也搞出集群,增加可靠性,但不管如何,这小小的session对我来说是一个沉重的负担

4于是有人就一直在思考,我为什么要保存这可恶的session呢,只让每个客户端去保存该多好?

可是如果不保存这些sessionid,怎么验证客户端发给我的sessionid的确是我生成的呢?如果不去验证,我们都不知道他们是不是合法登录的用户,那些不怀好意的家伙们就可以伪造sessionid,为所欲为了。

嗯,对了,关键点就是验证!

比如说,小F已经登录了系统,我给他发一个令牌(token),里边包含了小F的userid,下一次小F再次通过Http请求访问我的时候,把这个token通过Httpheader带过来不就可以了。

不过这和sessionid没有本质区别啊,任何人都可以可以伪造,所以我得想点儿办法,让别人伪造不了。

那就对数据做一个签名吧,比如说我用HMAC-SHA算法,加上一个只有我才知道的密钥,对数据做一个签名,把这个签名和数据一起作为token,由于密钥别人不知道,就无法伪造token了。

这个token我不保存,当小F把这个token给我发过来的时候,我再用同样的HMAC-SHA算法和同样的密钥,对数据再计算一次签名,和token中的签名做个比较,如果相同,我就知道小F已经登录过了,并且可以直接取到小F的userid,如果不相同,数据部分肯定被人篡改过,我就告诉发送者:对不起,没有认证。

Token中的数据是明文保存的(虽然我会用Base64做下编码,但那不是加密),还是可以被别人看到的,所以我不能在其中保存像密码这样的敏感信息。

当然,如果一个人的token被别人偷走了,那我也没办法,我也会认为小偷就是合法用户,这其实和一个人的sessionid被别人偷走是一样的。

这样一来,我就不保存sessionid了,我只是生成token,然后验证token,我用我的CPU计算时间获取了我的session存储空间!

解除了sessionid这个负担,可以说是无事一身轻,我的机器集群现在可以轻松地做水平扩展,用户访问量增大,直接加机器就行。这种无状态的感觉实在是太好了!

Cookie

1.什么是Cookie

Cookie翻译成中文的意思是‘小甜饼’,是由W3C组织提出,最早由Netscape社区发展的一种机制。目前Cookie已经成为标准,所有的主流浏览器如IE、Netscape、Firefox、Opera等都支持Cookie。

服务器单从网络连接上无从知道客户身份。怎么办呢?就给客户端们颁发一个通行证吧,每人一个,无论谁访问都必须携带自己通行证。这样服务器就能从通行证上确认客户身份了。这就是Cookie的工作原理。

Cookie是客户端保存用户信息的一种机制,用来记录用户的一些信息,也是实现Session的一种方式。Cookie存储的数据量有限,且都是保存在客户端浏览器中。不同的浏览器有不同的存储大小,但一般不超过4KB。因此使用Cookie实际上只能存储一小段的文本信息(key-value格式)。

2.Cookie的机制

当用户第一次访问并登录一个网站的时候,cookie的设置以及发送会经历以下4个步骤:

客户端发送一个请求到服务器;

服务器发送一个HttpResponse响应到客户端,其中包含Set-Cookie的头部;

客户端保存cookie,之后向服务器发送请求时,HttpRequest请求中会包含一个Cookie的头部;

服务器返回响应数据。

为了探究这个过程,写了代码进行测试,如下:

我在doGet方法中,new了一个Cookie对象并将其加入到了HttpResponse对象中

浏览器输入地址进行访问,结果如图所示:

可见ResponseHeaders中包含Set-Cookie头部,而RequestHeaders中包含了Cookie头部。name和value正是上述设置的。

3.Cookie的属性

Expires

该属性用来设置Cookie的有效期。Cookie中的maxAge用来表示该属性,单位为秒。Cookie中通过getMaxAge()和setMaxAge(intmaxAge)来读写该属性。maxAge有3种值,分别为正数,负数和0。

如果maxAge属性为正数,则表示该Cookie会在maxAge秒之后自动失效。浏览器会将maxAge为正数的Cookie持久化,即写到对应的Cookie文件中(每个浏览器存储的位置不一致)。无论客户关闭了浏览器还是电脑,只要还在maxAge秒之前,登录网站时该Cookie仍然有效。下面代码中的Cookie信息将永远有效。

Cookiecookie=newCookie("jiangwang",System.currentTimeMillis()+"");

//设置生命周期为MAX_VALUE,永久有效

cookie.setMaxAge(Integer.MAX_VALUE);resp.addCookie(cookie);

当maxAge属性为负数,则表示该Cookie只是一个临时Cookie,不会被持久化,仅在本浏览器窗口或者本窗口打开的子窗口中有效,关闭浏览器后该Cookie立即失效。

修改或者删除Cookie

HttpServletResponse提供的Cookie操作只有一个addCookie(Cookiecookie),所以想要修改Cookie只能使用一个同名的Cookie来覆盖原先的Cookie。如果要删除某个Cookie,则只需要新建一个同名的Cookie,并将maxAge设置为0,并覆盖原来的Cookie即可。

新建的Cookie,除了value、maxAge之外的属性,比如name、path、domain都必须与原来的一致才能达到修改或者删除的效果。否则,浏览器将视为两个不同的Cookie不予覆盖。

Cookie的域名

Cookie是不可以跨域名的,隐私安全机制禁止网站非法获取其他网站的Cookie。

正常情况下,同一个一级域名下的两个二级域名也不能交互使用Cookie,比如a1.jiangwang.

1
查看完整版本: 一文彻底弄懂cookiesession