cookie、session、token一文看懂到底有什么区别
一个例子
一位顾客每次都去同一家理发店剪头,但是可能因为脸盲,老板每次都不记得他,所以每次都不记得他想剪什么发型,这让顾客很苦恼,每次沟通都要花费很长时间,大大影响了效率。
所以,后来顾客找到老板
顾客:“老板,我是你这常客,你能不能把我记一下,下次我就不用在说我到底想剪啥发型了”
老板看着顾客的脸,若有所思。心中一叹:“如果不是你长得这么大众,我怎么会记不住”。苦恼的老板挠了挠头想到了一个办法,那就是每个用户来这里消费的时候都可以告诉老板他的姓名和电话号。老板用一个小本本记录,每来一次就划一横。
这种办法果然可行,顾客满意的离开了。
但是后来遇到了问题,顾客越来越多,老板的小本本已经记满了,满了之后就需要加本子,这样下去每次都要花很长时间去查顾客到底是来过几次,并加以修改。
后来老板意识到这样效率太低,于是更换了方法。他给每位第一次来的顾客都发一张vip卡,卡上有着这位顾客专属的vip号码,然后老板用一个新本子来记录,因为每个vip号码都是有顺序的,老板就可以批量存储,根据vip号码的开头数字来做目录查询。
这样就完成了高效率的存储和记录用户信息。
会话保持
根据上面的例子我们可以知道,因为http不能保持会话(记录顾客),所以老板(服务器)给第一次来的客户(浏览器)发了一张卡片(set-cookie),上面有vip号码(sessionId,根据每个会话对象生成的id)。后来,每个顾客来的时候都会带着卡片来(每次请求都发送cookie),然后老板就知道来的是哪位顾客,并进行个性化的服务提供。
这样就完成了我们想要的会话保持。
关键问题
上面的例子可以说明cookie和session的本质,但是其实还有一些潜在的安全问题。
比如,cookie 是一个非常具体的东西,指的就是浏览器里面能永久存储的一种数据,仅仅是浏览器实现的一种数据存储功能。
cookie由服务器生成,发送给浏览器,浏览器把cookie以kv形式保存到某个目录下的文本文件内,下一次请求同一网站时会把该cookie发送给服务器。由于cookie是存在客户端上的,所以浏览器加入了一些限制确保cookie不会被恶意使用,同时不会占据太多磁盘空间,所以每个域的cookie数量是有限的。
所以绝大部分的会话保持都是cookie保存的sessionId,这样就可以杜绝信息泄露。
cookie能独立使用,并不一定就要和session结合。
比如用户名登录密码发送到服务器之后,服务器验证信息正确之后,会对信息进行加密然后返回浏览器设置cookie,这就是一份登陆凭证。接下来每次发送cookie都要进行解密。cookie是一个键值对,所以务必保持键名固定。
cookie和session都会受到跨域限制。
服务器集群也不会共享session,session是由单个服务器创建的,但是处理用户请求的服务器不一定是那个创建session的服务器,这样他就拿不到之前已经放入到session中的登录凭证之类的信息了。同时session保存的会话量过多,对服务器说是一个巨大的开销 , 严重的限制了服务器扩展能力。
前面两种会话管理方式因为都用到cookie,不适合用在native app里面:native app不好管理cookie,毕竟它不是浏览器。这两种方案都不适合用来做纯api服务的登录认证。要实现api服务的登录认证,就要考虑下面要介绍的第三种会话管理方式。
token(令牌)的好处
token相对cookie的优势
1、支持跨域访问 ,将token置于请求头中,而cookie是不支持跨域访问的;
2、无状态化, 服务端无需存储token ,只需要验证token信息是否正确即可,而session需要在服务端存储,一般是通过cookie中的sessionID在服务端查找对应的session;
3、 无需绑定到一个特殊的身份验证方案(传统的用户名密码登陆),只需要生成的token是符合我们预期设定的即可;
4、 更适用于移动端 (Android,iOS,小程序等等),像这种原生平台不支持cookie,比如说微信小程序,每一次请求都是一次会话
5、 避免CSRF跨站伪造攻击 ,还是因为不依赖cookie
使用token和使用cookie方式差不多,但是区别在于token可以保存在url和请求头中,同时适合移动端使用,所以通常来说token使用更为广泛。
基于Token的验证原理
基于Token的身份验证是无状态的,我们不将用户信息存在服务器或Session中。
这种概念解决了在服务端存储信息时的许多问题。NoSession意味着你的程序可以根据需要去增减机器,而不用去担心用户是否登录。
基于Token的身份验证的过程如下:
- 用户通过用户名和密码发送请求。
- 程序验证。
- 程序返回一个签名的token 给客户端。
- 客户端储存token,并且每次用于每次发送请求。
- 服务端验证token并返回数据。
每一次请求都需要 token。token 应该在HTTP的头部发送从而保证了Http请求无状态。我们同样通过设置服务器属性Access-Control-Allow-Origin:*,让服务器能接受到来自所有域的请求。
- 用户登录校验,校验成功后就返回Token给客户端。
- 客户端收到数据后保存在客户端
- 客户端每次访问API是携带Token到服务器端。
- 服务器端采用filter过滤器校验。校验成功则返回请求数据,校验失败则返回错误码
- 当我们在程序中认证了信息并取得token之后,我们便能通过这个Token做许多的事情。
我们甚至能基于创建一个基于权限的token传给第三方应用程序,这些第三方程序能够获取到我们的数据(当然只有在我们允许的特定的token)
基于Token验证的优势
无状态、可扩展
在客户端存储的 Token 是无状态的,并且能够被扩展。基于这种无状态和不存储Session信息,负载负载均衡器能够将用户信息从一个服务传到其他服务器上。
如果我们将已验证的用户的信息保存在Session中,则每次请求都需要用户向已验证的服务器发送验证信息(称为Session亲和性)。用户量大时,可能会造成 一些拥堵。
但是不要着急。使用Token之后这些问题都迎刃而解,因为Token自己hold住了用户的验证信息。
安全性
请求中发送token而不再是发送cookie能够防止CSRF(跨站请求伪造)。
假如用户正在登陆银行网页,同时登陆了攻击者的网页,并且银行网页未对csrf攻击进行防护。攻击者就可以在网页放一个表单,该表单提交src为http:/ /www.bank.com/api/transfer,body为count=1008&to=Tom。倘若是session+cookie,用户打开网页的时候就已经转给Tom1000元了.因为form发起的POST请求并不受到浏览器同源策略的限制,因此可以任意地使用其他域的Cookie向其他域发送POST请求,形成CSRF攻击。在post请求的瞬间,cookie会被浏览器自动添加到请求头中。但token不同,token是开发者为了防范csrf而特别设计的令牌,浏览器不会自动添加到headers里,攻击者也无法访问用户的token,所以提交的表单无法通过服务器过滤,也就无法形成攻击。
那为什么 token 不会存在这种问题呢?
一般情况下在我们登录成功获得 token 之后,一般会选择存放在 local storage 中。然后我们在前端通过某些方式会给每个发到后端的请求加上这个 token,这样就不会出现 CSRF 漏洞的问题。因为,即使有个你点击了非法链接发送了请求到服务端,这个非法请求是不会携带 token 的,所以这个请求将是非法的。
但是这样会存在 XSS 攻击中被盗的风险,为了避免 XSS 攻击,你可以选择将 token 存储在标记为httpOnly 的cookie 中。但是,这样又导致了你必须自己提供CSRF保护。
具体采用上面哪两种方式存储 token 呢,大部分情况下存放在 local storage 下都是最好的选择,某些情况下可能需要存放在标记为httpOnly 的cookie 中会更好。
即使在客户端使用cookie存储token,cookie也仅仅是一个存储机制而不是用于认证。不将信息存储在Session中,让我们少了对session操作。
Token是有时效的,一段时间之后用户需要重新验证。我们也不一定需要等到Token自动失效,Token有撤回的操作,通过token revocataion可以使一个特定的Token或是一组有相同认证的token无效。
可扩展性
Token能够创建与其它程序共享权限的程序。例如,能将一个随便的社交帐号和自己的大号(Fackbook或是Twitter)联系起来。当通过服务登录Twitter(我们将这个过程Buffer)时,我们可以将这些Buffer附到Twitter的数据流上(we are allowing Buffer to post to our Twitter stream)。
使用Token时,可以提供可选的权限给第三方应用程序。当用户想让另一个应用程序访问它们的数据,我们可以通过建立自己的API,得出特殊权限的tokens。
多平台跨域
我们提前先来谈论一下CORS(跨域资源共享),对应用程序和服务进行扩展的时候,需要介入各种各种的设备和应用程序。
只要用户有一个通过了验证的token,数据和资源就能够在任何域上被请求到。
Access-Control-Allow-Origin: *
本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!
