写在前面:

session ?cookie ?token ?

相信大家对这几个词并不陌生,不管是面试还是工作都会有涉及的,可想而知它的重要性。

网上关于 session、cookie、token 的文章有很多,每篇文章都有一些独特的见解。

在写文章之前,我看了很多篇 session、cookie、token 的文章,感觉很多都没有讲的很清楚,泛泛而谈。

在看了这么多的文章之后,我对这几次词又有了不一样的理解,在这里和大家分享一下。


目录

写在前面:

一、聊一下发展史

1. 第一阶段:请求+响应

2. 第二阶段:请求+下发会话标识+响应

1. http是一个无状态协议

3. 第三阶段:请求+请求会话标识+响应

1. 解释一下这里的服务器拓展能力

2. 集中session

4. 第四阶段:token代替session

1. 签名完成token验证

2. 签名形成过程:

3. 签名验证token过程:

4. cookie

5. 注意点:

5. 总结:

二、Cookie

1. 什么是Cookie

2. Cookie 起源:

3. Cookie时效性

4. Cookie使用限制

5. 执行流程:

1. HTTP Request

2. HTTP Response + Set-Cookie

3. HTTP Response + Cookie

4. HTTP Response

6. 浏览器中cookie所在位置

三、Session

四、Token

1. 什么是token

1. 简介

2. 组成

3. 存放

2. 基于Token的身份验证的优势:

1. 无状态

2. 安全性

3. 可扩展性

4. 多平台跨域

3. 基于服务器验证方式暴露的一些问题

4. 基于Token的验证原理

1. 基于Token的身份验证的过程如下:

2. 实现思路:

3. 注意:

4. 总结:

五、Cookie和Session的区别:

六、Token 和 Session 的区别:

七、token可以抵抗csrf,cookie+session不行

八、总结

写在最后:

九、专栏分享


一、聊一下发展史

1. 第一阶段:请求+响应

在很久以前,Web基本上就是文档的浏览而已,服务器不需要记录谁在某一段时间里都浏览了什么文档,每次请求都是一个新的HTTP请求,都会建立有一个新的连接。

就是请求加响应,不需要记住谁刚刚发了HTTP请求,每个请求对服务器来说都是全新的。

2. 第二阶段:请求+下发会话标识+响应

随着交互式Web应用的兴起,像在线购物网站,需要登录的网站等等,马上就面临一个问题,那就是要管理会话,必须记住哪些人登录系统,哪些人往自己的购物车中放商品,也就是说服务器必须把每个用户分开。

然而,这是个不小的挑战,因为HTTP请求是无状态的,所以想出的办法就是给大家发一个会话标识( session id ),说白了就是一个随机的字串,每个人收到的都不一样,每次大家向浏览器发起HTTP请求的时候,把这个字符串给一并捎过来, 这样就能区分开来了。

1. http是一个无状态协议

什么是无状态呢?

就是说这一次请求和上一次请求是没有任何关系的,互不认识的,没有关联的。

这种无状态的的好处是快速。

坏处是假如我们想要把www.zhihu.com/login.html和www.zhihu.com/index.html关联起来,必须使用某些手段和工具。

3. 第三阶段:请求+请求会话标识+响应

每个用户只需要保存自己的 session id,而服务器要保存所有人的 session id,这样的话,服务器的压力就大了。

如果说,访问服务器的用户很多很多,那么,服务器可能就需要存储成千上万,甚至几十万个 session id。

这对服务器说是一个巨大的开销, 严重的限制了服务器扩展能力。

1. 解释一下这里的服务器拓展能力

比如说我用两个机器组成了一个集群,小 F 通过机器 A 登录了系统,那session id会保存在机器 A 上,机器B可没有小F的 session id,假设小F的下一次请求被转发到机器B怎么办呢?

可能会采用一点小伎俩: session sticky。

就是让小F的请求一 直粘连在机器A上,但是这也不管用,要是机器A挂掉了 ,还得转到机器B去。

那只好做session的复制了,把session id在两个机器之间搬来搬去,很麻烦。

编辑

2. 集中session

后来有个叫Memcached的人提出:把session id集中存储到一个地方,所有的机器都来访问这个地方的数据。

这样一来,就不用复制了,但是增加了单点失败的可能性,要是那个负责session的机器挂了,所有人都得重新登录一遍,这无疑是一个很大的问题。

编辑 

4. 第四阶段:token代替session

于是有人提出:能不能只让每个客户端去保存自己的 session 而服务器不需要保存呢 ?

可是问题来了:如果不保存这些 session id,怎么验证客户端发给服务器 session id 的确是服务器生成的呢?

如果不去验证, 服务器都不知道他们是不是合法登录的用户,那黑客们就可以伪造 session id ,为所欲为了。

有了上面的讨论,我们可以想到一个关键点:验证

1. 签名完成token验证

比如说,小F已经登录 了系统,服务器给他发一个令牌,这个令牌就是token, 里边包含了小F的 user id,下一 次小 F 再次通过 Http 请求访问服务器的时候,把这个 token 通过 Http header 带过来不就可以了。

其实这样和 session id 没有本质区别,任何人都可以可以伪造。

又有人提出:录用签名来防止伪造。

2. 签名形成过程:

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

编辑 

3. 签名验证token过程:

这个token服务器不保存,当小F把这个 token 给服务器发过来的时候,我再同样的 HMAC-SHA256 算法和同样的密钥,对数据再计算一次签名,和 token 中的签名做个比较。

如果相同, 我就知道小F已经登录过了 ,并且可以直接取到小F的user id,如果不相同,数据部分肯定被人篡改过,我就告诉发送者: 对不起, 没有认证。

编辑 

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

解除了 session id这个负担,服务器的机器集群就可以可以轻松地做水平扩展,用户访问量增大, 直接加机器就行。

4. cookie

服务器就要给每个客户端分配不同的 token,然后客户端每次向服务器发请求的时候,都带上这个 token,服务器就知道这个请求来自于谁了。

至于客户端怎么保存这个 token,可以有很多种方式,对于浏览器客户端,大家都默认采用cookie的方式。

5. 注意点:

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

如果谋和用户的 token 被盗,那服务器也没办法 ,服务器只认 token ,也就是说会认为小偷就是合法用户,这其实和用户的 session id 被盗是一样的。

5. 总结:

介绍完了发展史相信你对 session、cookie、token 有了一定的认证。

接下来具体再介绍一下这三者。


二、Cookie

1. 什么是Cookie

Cookie 技术产生源于 HTTP 协议在互联网上的急速发展。

随着互联网时代的发展,带宽等限制不存在了,人们需要更复杂的互联网交互活动,就必须同服务器保持活动状态(保活)

于是,在浏览器发展初期,为了适应用户的需求技术上推出了各种保持 Web 浏览状态的手段,其中就包括了 Cookie 技术。

Cookie 在计算机中是个存储在浏览器目录中的文本文件,当浏览器运行时,存储在 RAM 中发挥作用 (此种 Cookies 称作 Session Cookies),一旦用户从该网站或服务器退出,Cookie 可存储在用户本地的硬盘上 (此种 Cookies 称作 Persistent Cookies)。

 cookie 由服务器生成,发送给浏览器,浏览器把 cookie 以 key,value 形式保存到某个目录下的文本文件内,下一次请求同一网站时会把该 cookie 发送给服务器。

由于 cookie 是存在客户端上的,所以浏览器加入了一些限制确保 cookie 不会被恶意使用,同时不会占据太多磁盘空间,所以每个域的 cookie 数量是有限的。

2. Cookie 起源:

1993 年,网景公司雇员 Lou Montulli 为了让用户在访问某网站时,进一步提高访问速度,同时也为了进一步实现个人化网络,发明了今天广泛使用的 Cookie。

3. Cookie时效性

目前有些 Cookie 是临时的,有些则是持续的。临时的 Cookie 只在浏览器上保存一段规定的时间,一旦超过规定的时间,该 Cookie 就会被系统清除。

4. Cookie使用限制

Cookie 必须在 HTML 文件的内容输出之前设置;不同的浏览器对 Cookie 的处理不一致,使用时一定要考虑;客户端用户如果设置禁止 Cookie,则 Cookie 不能建立。

并且在客户端,一个浏览器能创建的 Cookie 数量最多为 300 个,并且每个不能超过 4KB,每个 Web 站点能设置的 Cookie 总数不能超过 20 个。

5. 执行流程:

1. HTTP Request

首先,客户端会发送一个http请求到服务器端。

2. HTTP Response + Set-Cookie

服务器端接受客户端请求后,建立一个session,发送一个http响应到客户端,这个响应头,其中就包含Set-Cookie头部,该头部包含了session id。

Set-Cookie格式:Set-Cookie: value[; expires=date][; domain=domain][; path=path][; secure]

3. HTTP Response + Cookie

在客户端发起的第二次请求提供给了服务器端可以用来唯一标识客户端身份的信息。

(注意:如果服务器需要我们带上Cookie,我们就需要在B步骤上面拿到这个Cookie然后作为请求头一起发起第二次请求),

这时,服务器端也就可以判断客户端是否启用了cookies。

尽管,用户可能在和应用程序交互的过程中突然禁用cookies的使用,但是,这个情况基本是不太可能发生的,所以可以不加以考虑,这在实践中也被证明是对的。

4. HTTP Response

4. 浏览器返回请求内容

为了方便理解,可以先看下这张流程执行图加深概念:

编辑

6. 浏览器中cookie所在位置

编辑


三、Session

session从字面上讲,就是会话。

这个就类似于你和一个人交谈,你怎么知道当前和你交谈的是张三而不是李四呢?

对方肯定有某种特征(如长相)表明他就是张三。

session也是类似的道理,服务器要知道当前发请求给自己的是谁。

为了做这种区分,服务器就要给每个客户端分配不同的"身份标识",然后客户端每次向服务器发请求的时候,都带上这个,服务器就知道这个请求来自于谁了。

至于客户端怎么保存这个"身份标识",可以有很多种方式,对于浏览器客户端,大家都默认采用cookie的方式。

服务器使用session把用户的信息临时保存在了服务器上,户离开网站后session会被销毁。

这种用户信息存储方式相对cookie来说更安全。

Session是对于服务端来说的,客户端是没有Session一说的。

Session是服务器在和客户端建立连接时添加客户端连接标志,最终会在服务器软件(Apache、Tomcat、JBoss)转化为一个临时Cookie发送给给客户端,当客户端第一请求时服务器会检查是否携带了这个Session(临时Cookie),如果没有则会添加Session,如果有就拿出这个Session来做相关操作。

可是session有一个缺陷:如果web服务器做了负载均衡,那么下一个操作请求到了另一台服务器的时候session会丢失。

举例:

用户在www.a.com/login.php里面登陆了,用户在www.a.com/index.php 也希望是登陆状态,但是,这是2个不同的页面,也就是2个不同的HTTP请求,这2个HTTP请求是无状态的,也就是无关联的,所以无法单纯的在index.php中读取到它在login.php中已经登陆了,需要重新登陆。

四、Token

1. 什么是token

1. 简介

token 也称作令牌,由uid+time+sign[+固定参数]

token 的认证方式类似于临时的证书签名, 并且是一种服务端无状态的认证方式,非常适合于 REST API 的场景。

所谓无状态就是服务端并不会保存身份认证相关的数据。

在Web领域基于Token的身份验证随处可见。

在大多数使用Web API的互联网公司中,tokens 多户下处理认证的最佳方式。

例如:Facebook, Twitter, Google+, GitHub等API和Web应用都使用tokens。

2. 组成

uid: 用户唯一身份标识

time: 当前时间的时间戳

sign: 签名, 使用 hash/encrypt 压缩成定长的十六进制字符串,以防止第三方恶意拼接

固定参数(可选): 将一些常用的固定参数加入到 token 中是为了避免重复查库

3. 存放

token在客户端一般存放于localStorage,cookie,或sessionStorage中。在服务器一般存于数据库中

2. 基于Token的身份验证的优势:

无状态、可扩展、支持移动设备、跨程序调用、 安全

1. 无状态

在客户端存储的Tokens是无状态的,并且能够被扩展。

基于这种无状态和不存储Session信 息,负载负载均衡器能够将用户信息从一个服务传到其他服务器上。

如果我们将已验证的用户的信息保存在Session中,则每次请求都需要用户向已验证的服务器发送验证信息(称为Session亲和性)。

用户量大时,可能会造成一些拥堵。但是不要着急。

使用tokens之 后这些问题都迎刃而解,因为tokens自 己hold住了户的验证信息。

2. 安全性

请求中发送token而不再:是发送cookie能够防止CSRF(跨站请求伪造)。

即使在客户端使用cookie存储token, cookie也仅仅是一 个存储机制而不是用于认证。

不将信息存储在Session中,让我们少了对session操作。

token是有时效的,一段时间之后用户需要重新验证。

我们也不一定需要等到token自动失效,token有 撤回的操作,通过token revocataion可以使-个特定的token或是一-组有 相同认证的token无效。

3. 可扩展性

Tokens能够创建与其它程序共享权限的程序。例如,能将一个随便的社交帐号和自己的大号(Fackbook或是Twitter)联系起来。

当通过服务登录Twittr(我们将这个过程Buffer)时,我们可以将这些Buffer附到Twitter的数据流上(we are allowing Buffer to post to our Twitter stream)。

使用tokens时,可以提供可选的权限给第三方应用程序。当用户想让另一个应用程序访问它们的数据,我们可以通过建立自己的API,得出特殊权限的tokens。

4. 多平台跨域

开启CORS(跨域资源共享),对应用程序和服务进行扩展的时候,需要介入各种各种的设备和应用程序。

只要用户有一个通过了验证的token,数据和资源就能够在任何域上被请求到。

3. 基于服务器验证方式暴露的一些问题

1. Seesion 每次认证用户发起请求时,服务器需要去创建一个记录来存储信息。 当越来越多的用户发请求时,内存的开销也会不断增。

2. 可扩展性:在服务端的内存中使用Seesion存储登录信息,伴随而来的是可扩展性问题。

3. CORS(跨域资源共享):当我们需要让数据跨多台移动设备上使用时,跨域资源的共享会是一个让人头疼的问题。在使用Ajax抓取另一个域的资源,就可以会出现禁止请求的情况。

4. CSRF(跨站请求伪造):用户在访问银行网站时,他们很容易受到跨站请求伪造的攻击,并且能够被利用其访问其他的网站。

在这些问题中,可扩展行是最突出的。因此我们有必要去寻求一种更有行之有效的方法。

4. 基于Token的验证原理

基于Token的身份验证是无状态的,我们不将用户信息存在服务器或Session中。

这种概念解决了在服务端存储信息时的许多问题。

NoSession意味着你的程序可以根据需要去增减机器,而不用去担心用户是否登录。

1. 基于Token的身份验证的过程如下:

1.用户通过用户名和密码发送请求。

2.程序验证。

3.程序返回一个签名的token给客户端。

4.客户端储存token,并且每次用于每次发送请求。

5.服务端验证token并返回数据。

每一次请求都需要token,token应该在HTTP的头部发送从而保证了Http请求无状态。

我们同样通过设置服务器属性 Access-Control-Allow-Origin:*,让服务器能接受到来自所有域的请求。

需要主要的是,在ACAO头部标明(designating)*时, 不得带有像HTTP认证,客户端SSL证书和cookies的证书。

2. 实现思路:

编辑

1.用户登录校验,校验成功后就返回Token给客户端。

2.客户端收到数据后保存在客户端

3.客户端每次访问API是携带Token到服务器端。

4.服务器端采用filter过滤器校验。校验成功则返回请求数据,校验失败则返回错误码。

当我们在程序中认证了信息并取得token之后,我们便能通过这个Token做许多的事情。

我们甚至能基于创建一个基 于权限的token传给第三方应用程序,这些第三方程序能够获取到我们的数据( 当然只有在我们允许的特定的token)

3. 注意:

cookie只是实现session的其中一种方案。虽然是最常用的,但并不是唯一的方法。禁用cookie后还有其他方法存储,比如放在url中。

现在大多都是Session + Cookie,但是只用session不用cookie,或是只用cookie,不用session在理论上都可以保持会话状态。可是实际中因为多种原因,一般不会单独使用。

用session只需要在客户端保存一个id,实际上大量数据都是保存在服务端。如果全部用cookie,数据量大的时候客户端是没有那么多空间的。

如果只用cookie不用session,那么账户信息全部保存在客户端,一旦被劫持,全部信息都会泄露。并且客户端数据量变大,网络传输的数据量也会变大。

4. 总结:

简而言之, session 有如用户信息档案表, 里面包含了用户的认证信息和登录状态等信息. 而 cookie 就是用户通行证

五、Cookie和Session的区别:

1. 数据存放位置不同:Session数据是存在服务器中的,cookie数据存放在浏览器当中。

2. 安全程度不同:cookie放在服务器中不是很安全,session放在服务器中,相对安全。

3. 性能使用程度不同:session放在服务器上,访问增多会占用服务器的性能;考虑到减轻服务器性能方面,应使用cookie。

4. 数据存储大小不同:单个cookie保存的数据不能超过4K,session存储在服务端,根据服务器大小来定。

六、Token 和 Session 的区别:

1. token是开发定义的,session是http协议规定的;

2. token不一定存储,session存在服务器中;

3. token可以跨域,session不可以跨域,它是与域名绑定的。

七、token可以抵抗csrf,cookie+session不行

关于什么是CSRF可以看常见web漏洞总结------CSRF

假如用户正在登陆银行网页,同时登陆了攻击者的网页,并且银行网页未对csrf攻击进行防护。

攻击者就可以在网页放一个表单,该表单提交src为http://www.bank.com/api/transfer,body为count=1000&to=Tom

倘若是 session+cookie,用户打开网页的时候就已经转给Tom1000元了。

因为 form 发起的 POST 请求并不受到浏览器同源策略的限制,因此可以任意地使用其他域的 Cookie 向其他域发送 POST 请求,形成 CSRF 攻击。

在 post 请求的瞬间,cookie 会被浏览器自动添加到请求头中。

但token不同,token 是开发者为了防范 csrf 而特别设计的令牌,浏览器不会自动添加到headers 里,攻击者也无法访问用户的 token,所以提交的表单无法通过服务器过滤,也就无法形成攻击。

八、总结

session 存储于服务器,可以理解为一个状态列表,拥有一个唯一识别符号 session id,通常存放于 cookie 中。服务器收到 cookie 后解析出 session id,再去 session 列表中查找,才能找到相应 session,依赖 cookie。

cookie类似一个令牌,装有sessionId,存储在客户端,浏览器通常会自动添加。

token 也类似一个令牌,无状态,用户信息都被加密到token中,服务器收到token后解密就可知道是哪个用户。需要开发者手动添加。

写在最后:

session,cookie,token 其实理解起来不难,就是有点绕。

搞明白了 web 发展的一个历程,理解一下各自原理,区别其实就差不多了。

当然,我是身处安全岗,也是站在安全岗的定位来看的,对于研发岗可能有不一样的深度。

至此,本文基本完成,历时20小时,在这短时间里,自己也收获很多,同时希望能助人理解session,cookie和token。

本文,参考了很多文章,在此申明。

参考文章:Token(计算机术语)_百度百科 (baidu.com)

                  session(计算机术语)_百度百科 (baidu.com)

                  cookie(储存在用户本地终端上的数据)_百度百科 (baidu.com)

                  有了cookie为什么需要session? - SegmentFault 思否

                  session、cookie和token的区别 - 知乎 (zhihu.com)

                  token优势步骤实现_自己对幸福的要求是什么的博客-CSDN博客

                  彻底弄懂session,cookie,token - SegmentFault 思否

                  Cookie、Session、Token那点事儿(原创) - 简书 (jianshu.com)

                  彻底理解cookie,session,token - 墨颜丶 - 博客园 (cnblogs.com)

                  cookie, session, token 发展史 - 天军 - 博客园 (cnblogs.com)

                  Cookie、Session和Token - 掘金 (juejin.cn)

​​

本文到这里就结束了,主要就分享了 session、token、cookie 三个东西。

看完本篇是不是意犹未尽~~~

我们下篇文章见 !^.^