cookie/session/token概念辨析
1 cookie
cookie是一个对象,在服务端通过new cookie创建,将信息保存进去后传给前端,由浏览器负责保存,cookie很小只有4KB,由于是公开的,所以一般只保存一些简单的信息,比如商城购物车的信息。
cookie作为一个浏览器保存信息的对象,可以以key-value方式保存程序员希望前端保存的数据。
比如保存sessionID,如果session是tomcat提供的,那么key就是JSESSIONID,value是tomcat自动生成的一长串字符串,如果session是用户自定义的,key就可以自定义,value就是用户自定义生成的一长串字符串
或者保存JWT的token,但token除了放在cookie,也可以选择放在别的地方,比如vue的state,或者sessionStorage、localStorage。
2 最初的session
https://www.cnblogs.com/songyao666/p/12172013.html
session用来保存用户的登录信息等数据。
传统的session在访问tomcat服务器HttpServletRequest的getSession(true)的时候创建,tomcat的ManagerBase类提供创建sessionid的方法:随机数+时间+jvmid。
tomcat的StandardManager类将session存储在内存中,也可以持久化到file,数据库,memcache,redis等地方。
而浏览器只将sessionID(如果是用tomcat方法生成的session,那么有一个专属名词叫JsessionID)当作一个cookie进行保存。
Cookie与 Session,一般认为是两个独立的东西,什么禁用Cookie就不能得到Session呢?因为Session是用Session ID来确定当前对话所对应的服务器Session,而Session ID是通过Cookie来传递的,禁用Cookie相当于失去了Session ID,也就得不到Session了。
3 共享session
一开始,网站都很简单,访问量也不大,都是单机模式,也没有集群。
后面互联网发展起来了,网站访问量也大了,就得考虑集群,此时传统的session生成方式依然是将session保存在tomcat服务器上,那么当用户下次访问网站时,可能会因为响应登录请求的不是用户第一次登录的服务器,导致用户需要重新登录,相关配置也会丢失。
除了使用Nginx的ip_hash策略让用户总是收到相同的服务器的响应外,更常用的是使用共享session,也就是把session保存在redis中,所有tomcat服务器都去redis获取session进行验证。
而这个过程的实现方式被spring封装成了springsession,实现起来非常方便。
4 token
https://www.cnblogs.com/chenxiaomeng/p/14236525.html
https://blog.csdn.net/qq_36204764/article/details/98599148
4.1 token的组成
session需要占用服务端的资源,所以诞生了token,简单 token 的组成一般是uid(用户唯一身份标识)+time(时间戳)+sign(签名,token 的前几位以哈希算法压缩成的一定长度的十六进制字符串,防止第三方恶意拼接)+固定参数(可选)。
4.2 token的验证流程
当用户登录时,验证账号密码通过后,后端对当前用户数据进行加密,生成一个加密字符串token,返还给客户端,当用户下次登录时,把这个token发送给后端,后端对浏览器传来的token值进行解密,解密完成后进行用户数据的查询,如果查询成功,则通过认证,实现状态保持,所以,即时有了多台服务器,服务器也只是做了token的解密和用户数据的查询,它不需要在服务端去保留用户的认证信息或者会话信息,这就意味着基于token认证机制的应用不需要去考虑用户在哪一台服务器登录了,这就为应用的扩展提供了便利,解决了session扩展性的弊端。
4.3 token的保存方式
https://blog.csdn.net/qq_48960335/article/details/117674525
session要保存在服务端,占用服务端的资源,同时还要传给前端sessionID,保存在cookie中(在cookie中的key为固定名称JSESSIONID,value为sessionID)。
token不需要保存在服务端,也就不占用服务端的资源,只需要传给前端保存。
Token 在用户登录成功之后返回给客户端,客户端组有三种存储方式
-
储存在 localStorage 中,每次调用接口时放在http请求头里面,长期有效
-
储存在 sessionStorage 中,每次调用接口时,把它当为一个字段传给后台,浏览器关闭自动清除
-
储存在 cookie 中,每次调用接口会自动发送,不过缺点是不能跨域
如果是IE678之类的,建议存cookie,通常推荐保存在cookie中,因为相比较而言,Web Storage比Cookie更容易受到攻击。
但是保存在cookie中就要考虑跨域资源共享问题。
4.4 其他关于token保存位置的讨论
https://bbs.csdn.net/topics/396947929
https://segmentfault.com/q/1010000024439725
https://segmentfault.com/q/1010000010338604
有的说存在cookie中,有的说存在localStorage中,有的说存在vue的state里
cookie
正常就放在cookie,然后设置httponly就可以了。当然你的token必须是跟sessionid一样,能够追溯到一个唯一用户的。 如果这个担心攻击利用的话,你倒是模拟一个攻击方法看看,至少我不知道这种可以怎么利用(不暴露我自己的登录信息的情况下)。而且如果这种能够攻击的话,那现在的整个http协议都有问题,几乎所有的需要登录的网站都存在问题,因为session就是这么实现的啊,现在几乎所有的网络系统都是基于session来实现登录状态保持的啊。
如果你的token并没有和登录信息绑定,无法追溯到一个唯一用户的话,那你不管放在哪里都不安全,跟放在哪里没有关系,你只要在网络上传输就会暴露。
localstorage
支持者1
前端存入localstorage就可以,localstorage不参与服务器交互,没有抓包一说,绝对安全, 但后端要验证,前端就必须传入,比如:http://x.x.com/save?token=xxx&a=1&b=2, 这种方式相当于裸奔,post也是,建议改良一下: 先用MD5混淆token,示例代码:var token = md5(md5('a=1&b=2&time=当前时间&token=xxx')); 再调接口:http://x.x.com/save?token=混淆后的token&time=当前时间&a=1&b=2 MD5不可逆,加上时间有效性验证,即使被抓包,也无法获取真实token, 参数一起混淆不能篡改,用相同参数时间已过期, 前后校验端逻辑保持一致,安全系数可达99.9%
支持者2
一般来说,如果每次登陆都会请求获取token鉴权接口的话,存放在sessionStorage就可以了,如果需要token数据持久化,实现自动登陆等功能,则存在localStorage,cookie只在设置的cookie过期
时间之前才有效,并且cookie适合保存很小的数据,会在客户端与服务端之间来回传递,而localStorage需要指定,不会自动把数据发给服务器。一般token里面保存了token的有效时间及用户信息,后端从请求头中获取后解出来判断,再给前端返回相应的状态码。(token过期跳转至登陆页面,403表示无权限,无法访问接口)
支持者3
localstorage安全一点点点, 这样可以减少一些csrf攻击
支持者4
我们项目里都是存到localstorage里面的,如果没有其他需求,没必要存在cookie里面
支持者5
我是在 local storage 中保存,每次请求从storage中获取添加的,项目运转良好,虽然放在storage会被用户修改,但用户不能修改后台的token,如果用户修改了前端token,后台会认为会话失效,无法请求
state+localStorage
因为state是单页的,为了同一个浏览器打开第二个网页而不需要登录,所以要使用cookie或者localstorage存储,为什么不选用cookie:1,cookie存储量小;2,cookie存储个数有限;3,其实是最重要的 请求时会带上cookie,增加网络负担,所以建议用state+localStorage,当然要处理好加密,过期等问题
为什么不在所有地方直接使用localStorage呢?
用State是为了不每次都去读取localStorage
5 现代应用场景
在Web领域基于Token的身份验证随处可见。在大多数使用Web API的互联网公司中,tokens 是多用户下处理认证的最佳方式。大部分你见到过的API和Web应用都使用tokens。例如Facebook, Twitter, Google+, GitHub等。
对于一个分布式的web系统,通用的解决方案就是cookie+token 。
由服务端生成token,将用户信息与token进行关联,token返回给浏览器,存储到cookie中。后续请求都携带cooke或者将token从cookie取出以进行参数传递。
6 现在还有人用session吗
https://www.zhihu.com/question/315397046
Session的功能是把一个个分离的HTTP请求关联起来,只要能实现这个功能,基本上都能叫Session的一种实现。
-
在Cookie里放个JSESSIONID,在服务器中存上状态,用户请求来了,根据JSESSIONID去服务器里查状态,这是Tomcat的实现方法。
-
把所有状态都存在Cookie里,服务器给个签名防止伪造,每次请求来了,直接从Cookie里提取状态,这是JWT的实现方法。
-
在Cookie里放个token,状态不存在中间件里,而是存在Redis里,这也是一种Session实现方法。
正确的说法是,把Session存储在Web中间件中(比如存储在Tomcat中),这种做法正在被淘汰,因为这种方案对负载均衡不友好,也不利于快速伸缩。
把Session存在Redis和前端的方案正在慢慢崛起,尤其是现在微服务架构大行其道的情况下。
只要HTTP还是无状态的,只要保存状态还是刚需,Session就不会消失,变化的只是它的实现方式。