Cookie、Session、Token、Authenticat
前言
HTTP协议是一种无状态协议,即每次服务端接收到客户端的请求时,都是一个全新的请求,服务器并不知道客户端的历史请求记录,为了解决这个问题就提出了Cookie、Session、Token
Cookie
Cookie是服务器生成发送到用户浏览器并保存在本地的一小块数据,它会在浏览器下次向同一服务器发送请求时被携带发送到服务器上.通常它用于告知服务端两个请求是否来自同一浏览器。
生成原理
用户登录网站的时候,浏览器发出请求,服务器响应请求后,会在响应头里面添加一个Set-Cookie,将Cookie放入到响应请求中,在浏览器第二次发送请求的时候,会通过HTTP请求头将Cookie信息发送给服务器,服务器会辨别用户身份.注意Cookie的过期时间、域、路径、有效期、适用站点都可以根据需要来指定,生成Cookie的内容主要包括:名字,值,过期时间,路径和域.
分类
有两种类型的Cookie
- 会话Cookie: 如果Cookie没有指定过期时间或有效期,它只会存在于浏览器中,不会被写入磁盘,浏览器关闭之后它会被自动删除
- 持久性Cookie: 如果Cookie指定过期时间(Expires)或有效期(Max-Age),Cookie将会被写入磁盘,到了指定时间或有效期Cookie将从磁盘中被删除(打开浏览器自动登录就是使用了持久性Cookie特性)
Cookie设置安全性

Cookie 存储的方式

Cookie存储的方式缺点
- 每次发送请求都带着Cookie,信息越多,占用带宽资源就越多
- Cookie在客户端是明文存储,容易解析,可以伪造登录用户的,很不安全
- 单个Cookie保存的数据不能超过4K,很多浏览器都限制一个站点最多保存20个Cookie
那么鉴于Cookie存储方式的不足,Session存储的方式应运而生
Session
Session是将用户的会话数据存储在服务端,没有大小限制,通过一个session_id进行用户识别
生成原理
用户向服务器发送用户名和密码,服务器验证通过后会为用户生成一个session,同时为其分配唯一的 sessionId,sessionId就会与这个用户绑定,然后将sessionid通过 cookie传给浏览器,浏览器随后的每一次请求,都会通过Cookie将sessionid 传回服务器,服务器通过session_id验证用户的身份。必须注意的是:Session不一定必须依赖Cookie,也可以放在其他地方比如Authorization或url后面.
Session 存储的方式

Session存储的方式优点
- 服务器返回的session-id相比于Cookie要小很多,节省带宽资源
- 服务器把Session存储在数据库或者redis(内存)中,实现了本地化,相比于Cookie每次请求发送整个Cookie更安全。
Session存储的方式缺点
- 每个用户发起请求时,服务器需要去创建一个记录来存储信息,当越来越多的用户发送请求时,服务器的压力也会越来越大
- 实际在生产上,一般服务器至少需要两台机器,通过负载均衡的方式来决定到底请求该发到哪台机器上.假设登录请求发到了A机器,A 机器生成了session,下次请求如果发到B或者C怎么办,此时的 B,C 是找不到对应session的,那么就会发生请求失败,就得重新登录了.解决这个问题主要有以下三种方式:
1.session 复制: A 生成session后复制到 B,C,这样每台机器都有一份 session,无论请求发到哪台机器,都不会有问题,但是同一样的一份 session 保存了多份,数据冗余.
2.session 粘连: 这种方式是让每个客户端请求只发到固定的一台机器上(比如用户登录请求发到 A 机器后,后续所有请求也都发到 A 机器上),缺点是对应的机器挂了就会一直登录失败
3.session 共享: 这种方式也是目前各大公司普遍采用的方案,将session保存在 redis中间件中,浏览器发送请求到服务器上,服务器去redis中间件取一下session.缺点是每个请求都要去redis取一下session,多了一次内部连接,消耗了一点性能,另外为了保证 redis 的高可用,必须做集群,当然了对于大公司来说, redis 集群基本都会部署,所以这方案可以说是大公司的首选了.
针对Session的缺点推出了JSON WEB TOKEN
JSON WEB TOKEN(token)
生成原理
客户端登录的时候会将用户信息发送到服务端,服务端对用户信息使用算法以及密钥进行签名,再将这个签名数据作为Token返回给客户端并存储在客户端,客户端后续请求会将Token发送给服务端,服务端验证通过表示用户已登陆就会将请求数据返回给客户端
JWT使用方式
客户端收到服务器返回的 JWT,可以储存在 Cookie 里面,也可以存储在localStorage中,你可以把它放在 Cookie 里面自动发送,但是这样不能跨域,需要配置,所以更好的做法是放在 HTTP 请求头Authorization字段里面。
Authorization: Bearer <token>
另一种做法是,跨域的时候,JWT 就放在 POST 请求的数据体里面,JWT是目前最流行的跨域认证解决方案,JWT 解决的最大问题就是Cookie不能跨域.
JWT缺点
由于服务器不需要存储 Session 状态,因此使用过程中无法废弃某个 Token 或者更改 Token 的权限。也就是说一旦 JWT 签发了,到期之前就会始终有效,除非服务器部署额外的逻辑。
Cookie、Session、Token三者区别
- 存储位置: Cookie和Token存储在客户端上,Session存储在服务端上(服务器上session的实现对客户端的Cookie有依赖关系,因为session生成的sessionId存在Cookie上)
- 安全性: Cookie容易被CSRF攻击,考虑到安全性应当使用Session或Token
- 占用资源不同: Cookie和Token存储在客户端不占用服务器资源,Session存储在服务端占用服务器性能,Session过多,会增加服务器压力
- 依赖不同: Cookie是紧跟域名的,Session和Token不需要
- 加密不同: Token具有加密签名,而 Session Cookies 则没有
- 跨域不同: Cookie默认是不能跨域的,要实现单点登录需要使用Token
- 平台不同: 移动端原生请求是没有Cookie的,而Session依赖Cookie,所以一般用Token
Cookie、Session、Token相同点
- Cookie、Session、Token都是用来保持用户会话状态
- Cookie、Session、Token都是HTTP明码传输,为了减少盗用可以使用 HTTPS 协议传输
Authentication(认证)
HTTP www-Authenticate
验证用户身份的凭据(例如用户名/用户id和密码),通过这个凭据系统才知道你是谁,所以Authentication被称为身份/用户凭证
Authorization(授权)
HTTP协议中的Authorization请求头含有服务器用于验证用户代理身份的凭证,通常会在服务器返回401状态码以及WWW-Authenticate小洗头之后在后续请求中发送此消息头
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,所以提交的表单无法通过服务器过滤,也就无法形成攻击。
参考文章:
https://mp.weixin.qq.com/s/DvYIbC-vBOz4teKSLb-K-A
https://blog.mimvp.com/article/39467.html
https://juejin.cn/post/6844903955714015240
https://www.cnblogs.com/cxuanBlog/p/12635842.html
https://segmentfault.com/a/1190000039303557