hualinux 编程概念 3.8:解决http无状态 session cookie token发展史(新手必看!)

本文深入探讨了HTTP协议下session、cookie和token三种状态管理技术,分析了各自的优缺点及应用场景,特别是token在解决CSRF攻击和分布式环境下session管理问题中的优势。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

目录

一、前言

二、 session

2.1 session概述

2.2 session缺点

2.3 cookie的产生

三、cookie

3.1 cookie介绍

3.1.1 概述

3.1.2 cookie分类

 3.2 cookie缺点

四、解决http无状态的几种方式

4.1 Session的实现方式

4.1.1 使用Cookie来实现

4.1.2 使用URL回写来实现

4.1.3 通过表单变量保持状态

4.1.4 通过QueryString保持状态

五、 token

5.1 token概述

5.1.1 token的定义

5.1.2 token的目的

5.1.3 Token 实现流程

附录一、Token 认证的来龙去脉

1. 为什么要用 Token?

2.  需要为 Token 设置有效期吗?

2.1 需要设置有效期吗?

2.2 那么有效期多长合适呢?

2.3 时序图表示


前面介绍了HTTP是无状态的,为了解决http的“无状态”,出现了session cookie token 几种技术。

一、前言

计算机的技术日新月异,计算机的世界危机四伏......随着科技的发展,人类的进步,前端在网络安全方面,也日益发挥着它不可忽视的作用。

今天我们就一起看一看在Web 交互发展史上,对客户端记录发展的一些问题和解决办法,以及 token 在安全方面所发挥的一定的作用。

Token 在计算机身份认证中是令牌(临时)的意思,在词法分析中是标记的意思。一般作为邀请、登录系统使用。其实说的更通俗点可以叫暗号,在一些数据传输之前,要先进行暗号的核对,不同的暗号被授权不同的数据操作。

其实,在Web交互兴起之前,Web网页只有文档的浏览,不需要记录是谁干了什么。后来,随着电商等类型网站的崛起,记录用户行为的意义就变得尤为重要。

由于http是无状态的会话,所以我们需要一个东西来记录。目前我们用到的主要有三种:sessioncookie  token

 

二、 session

2.1 session概述

在服务器端记录,每一个会话会产生一个sessionId。当用户打开某个web应用时,便与web服务器产生一次session。服务器使用 sessionId 把用户的信息临时保存在了服务器上,用户离开网站后session会被销毁。这样服务器就会根据每个人sessionId的不同,区别开谁是谁了,从而返回给用户不同的请求结果。

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

2.2 session缺点

如果使用单个服务器的话,用户过多的话,会造成服务器开销太大。如果我们系统采用分布式的话,我们登录时,响应我们的那台机器会记录我们登录信息,万一下一个请求,响应我们的不是原来那台机器的话,它并没有存储我们之前会话信息,就会认为我们并没有登录。session粘连或者session复制都不是特别好的方案。

2.3 cookie的产生

那既然服务端存储这些 SessionId 这么麻烦,人类又想出一招,那就是把这些SessionId 都存储在客户端。这个时候,cookie运用而生......

 

三、cookie

3.1 cookie介绍

3.1.1 概述

cookie是服务端保存在客户端的临时的少量的数据。cookie由服务器生成,发送给浏览器,浏览器把cookiekv形式保存到某个目录下的文本文件内,下一次请求同一网站时会把该cookie发送给服务器。由于cookie是存在客户端上的,所以浏览器加入了一些限制确保cookie不会被恶意使用,同时不会占据太多磁盘空间,所以每个域的cookie数量是有限的。

 

3.1.2 cookie分类

cookie分为会话cookie和持久cookie

会话cookie

会话cookie是指在不设定它的生命周期expires时的状态,浏览器的开启到关闭就是一次会话,当关闭浏览器时,会话cookie就会跟随浏览器而销毁。当关闭一个页面时,不影响会话cookie的销毁。会话cookie就像我们没有办理积分卡时,单一的买卖过程,离开之后,信息则销毁。

持久cookie

持久cookie则是设定了它的生命周期expires,此时,cookie像商品一样,有个保质期,关闭浏览器之后,它不会销毁,直到设定的过期时间。对于持久cookie,可以在同一个浏览器中传递数据,比如,你在打开一个淘宝页面登陆后,你在点开一个商品页面,依然是登录状态,即便你关闭了浏览器,再次开启浏览器,依然会是登录状态。这就是因为cookie自动将数据传送到服务器端,在反馈回来的结果。持久cookie就像是我们办理了一张积分卡,即便离开,信息一直保留,直到时间到期,信息销毁。

 3.2 cookie缺点

但是,cookie 这种方式很容易被恶意攻击者入侵,那么又怎么验证客户端发给我的session id 的确是我生成的呢?  如果不去验证,服务器都不知道他们是不是合法登录的用户, 那些不怀好意的家伙们就可以伪造session id , 为所欲为了。这就需要我们用一种加密的方法或者可以说暗号,来验证这个id是否由我自己的服务器之前生成而非恶意攻击者篡改的。

说到这里,就不得不提一下 CSRF 跨站点请求伪造(Cross—Site Request Forgery)

举个简单的栗子:

  1. 小明下班回家,打开电脑浏览器,点开了某购物商城,输入自己用户名和密码请求登录该网站;
  2. 就在当小明用户信息通过验证后,该商城产生Cookie信息并返回给浏览器,此时小明
  3. 在这个购物商城   登录成功,兴奋地点开商品详情,添加购物车,。。。。;
  4. 在小明还未退出这个购物商城之前,他在同一浏览器中,打开一个TAB页访问网站B;网站B接收到小明请求后,给他返回一些攻击性代码,并发出一个请求要求访问他刚刚浏览的网站;
  5. 浏览器在接收到这些攻击性代码后,根据网站B的请求,在小明不知情的情况下携带Cookie信息,向该购物商城发出请求。但是该购物商城并不知道该请求其实是由B发起的,所以会根据小明的Cookie信息      以小明的权限处理该请求,导致来自网站B的恶意代码被执行。

(啰嗦这么多,其实说白了就是利用他人某些特征,冒充他人,但这些特征不能被购物商城所鉴别是不是冒充的)

 目前防御 CSRF 攻击主要有三种策略:

验证 HTTP Referer 字段;

在请求地址中添加 token 并验证;

在 HTTP 头中自定义属性并验证。

 

四、解决http无状态的几种方式

4.1 Session的实现方式

4.1.1 使用Cookie来实现

服务器给每个Session分配一个唯一的JSESSIONID,并通过Cookie发送给客户端。
当客户端发起新的请求的时候,将在Cookie头中携带这个JSESSIONID。这样服务器能够找到这个客户端对应的Session。

4.1.2 使用URL回写来实现

URL回写是指服务器在发送给浏览器页面的所有链接中都携带JSESSIONID的参数,这样客户端点击任何一个链接都会把JSESSIONID带会服务器。如果直接在浏览器输入服务端资源的url来请求该资源,那么Session是匹配不到的。
Tomcat 对Session的实现,是一开始同时使用Cookie和URL回写机制,如果发现客户端支持Cookie,就继续使用Cookie,停止使用URL回 写。如果发现Cookie被禁用,就一直使用URL回写。jsp开发处理到Session的时候,对页面中的链接记得使用 response.encodeURL() 。

Cookie和Session有以下明显的不同点:
1)Cookie将状态保存在客户端,Session将状态保存在服务器端;
2)Cookies 是服务器在本地机器上存储的小段文本并随每一个请求发送至同一个服务器。Cookie最早在RFC2109中实现,后续RFC2965做了增强。网络服务 器用HTTP头向客户端发送cookies,在客户终端,浏览器解析这些cookies并将它们保存为一个本地文件,它会自动将同一服务器的任何请求缚上 这些cookies。Session并没有在HTTP的协议中定义;
3)Session是针对每一个用户的,变量的值保存在服务器上,用一个sessionID来区分是哪个用户session变量,这个值是通过用户的浏览器在访问的时候返回给服务器,当客户禁用cookie时,这个值也可能设置为由get来返回给服务器;
4)就安全性来说:当你访问一个使用session 的站点,同时在自己机子上建立一个cookie,建议在服务器端的SESSION机制更安全些。因为它不会任意读取客户存储的信息。

4.1.3 通过表单变量保持状态

除了Cookies之外,还可以使用表单变量来保持状态,比如Asp.net就通过一个叫ViewState的Input=“hidden”的框来保持状态,比如:

<input type="hidden" name="__VIEWSTATE" id="__VIEWSTATE"
 value="/wEPDwUKMjA0OTM4MTAwNGRkXUfhlDv1Cs7/qhBlyZROCzlvf5U=" />

这个原理和Cookies大同小异,只是每次请求和响应所附带的信息变成了表单变量。
 

4.1.4 通过QueryString保持状态

QueryString通过将信息保存在所请求地址的末尾来向服务器传送信息,通常和表单结合使用,一个典型的QueryString比如:

:www.xxx.com/xxx.aspx?var1=value&var2=value2

 

五、 token

在上面在cookie的缺点中讲到 目前防御 CSRF的其中一个方式就是token,如果在接触过安卓开发、其它其它开发多少都会的到token的名字,像dnspod、阿里云后面授权都是基于token的。

ps:现在使用比较多的是JWT(JSON Web Token),有兴趣的可能阅读一下阮一峰的《JSON Web Token 入门教程

5.1 token概述

5.1.1 token的定义

Token是服务端生成的一串字符串,以作客户端进行请求的一个令牌,当第一次登录后,服务器生成一个Token便将此Token返回给客户端,以后客户端只需带上这个Token前来请求数据即可,无需再次带上用户名和密码。 (就类似于你第一次去白马会所办了会员卡,第二次去了直接拿着会员卡就好了,不需要再去登记预约了,别人去了冒充你的名字,但是他拿着假的会员卡,一刷就能看出他是个冒牌货。。。)

token的意思是令牌,是用户身份的验证方式,最简单的token组成:uid(用户唯一的身份标识)time(当前时间的时间戳)sign(签名,由token的前几位+盐以哈希算法压缩成一定长的十六进制字符串,可以防止恶意第三方拼接token请求服务器)。还可以把不变的参数也放进token,避免多次查库

5.1.2 token的目的

  1. Token的目的是为了减轻服务器的压力,减少频繁的查询数据库,使服务器更加健壮。
  2. 使得验证更加安全,一定程度上弥补了cookie的不足。

5.1.3 Token 实现流程

服务端收到请求,去验证用户名与密码
验证成功后,服务端会签发一个 Token,再把这个 Token 发送给客户端
客户端收到 Token 以后可以把它存储起来,比如放在 Cookie 里或者 Local Storage
客户端每次向服务端请求资源的时候需要带着服务端签发的 Token
服务端收到请求,然后去验证客户端请求里面带着的 Token,如果验证成功,就向客户端返回请求的数据

 

附录一、Token 认证的来龙去脉

1. 为什么要用 Token?

而要回答这个问题很简单——因为它能解决问题!可以解决哪些问题呢?

1. Token 完全由应用管理,所以它可以避开同源策略

2. Token 可以避免CSRF 攻击

3. Token 可以是无状态的,可以在多个服务间共享

Token 是在服务端产生的。如果前端使用用户名/密码向服务端请求认证,服务端认证成功,那么在服务端会返回 Token 给前端。前端可以在每次请求的时候带上 Token 证明自己的合法地位。如果这个 Token 在服务端持久化(比如存入数据库),那它就是一个永久的身份令牌。

 

2.  需要为 Token 设置有效期吗?

2.1 需要设置有效期吗?

对于这个问题,我们不妨先看两个例子。一个例子是登录密码,一般要求定期改变密码,以防止泄漏,所以密码是有有效期的;另一个例子是安全证书。SSL 安全证书都有有效期,目的是为了解决吊销的问题,对于这个问题的详细情况,来看看知乎的回答。所以无论是从安全的角度考虑,还是从吊销的角度考虑,Token 都需要设有效期。

 

2.2 那么有效期多长合适呢?

只能说,根据系统的安全需要,尽可能的短,但也不能短得离谱——想像一下手机的自动熄屏时间,如果设置为 10 秒钟无操作自动熄屏,再次点亮需要输入密码,会不会疯?如果你觉得不会,那就亲自试一试,设置成可以设置的最短时间,坚持一周就好(不排除有人适应这个时间,毕竟手机厂商也是有用户体验研究的)。

然后新问题产生了,如果用户在正常操作的过程中,Token 过期失效了,要求用户重新登录……用户体验岂不是很糟糕?

为了解决在操作过程不能让用户感到 Token 失效这个问题,有一种方案是在服务器端保存 Token 状态,用户每次操作都会自动刷新(推迟) Token 的过期时间——Session 就是采用这种策略来保持用户登录状态的。然而仍然存在这样一个问题,在前后端分离、单页 App 这些情况下,每秒种可能发起很多次请求,每次都去刷新过期时间会产生非常大的代价。如果 Token 的过期时间被持久化到数据库或文件,代价就更大了。所以通常为了提升效率,减少消耗,会把 Token 的过期时保存在缓存或者内存中。

还有另一种方案,使用 Refresh Token,它可以避免频繁的读写操作。这种方案中,服务端不需要刷新 Token 的过期时间,一旦 Token 过期,就反馈给前端,前端使用 Refresh Token 申请一个全新 Token 继续使用。这种方案中,服务端只需要在客户端请求更新 Token 的时候对 Refresh Token 的有效性进行一次检查,大大减少了更新有效期的操作,也就避免了频繁读写。当然 Refresh Token 也是有有效期的,但是这个有效期就可以长一点了,比如,以天为单位的时间。

 

2.3 时序图表示

使用 Token 和 Refresh Token 的时序图如下:

1)登录

2)业务请求

3)Token 过期,刷新 Token

上面的时序图中并未提到 Refresh Token 过期怎么办。不过很显然,Refresh Token 既然已经过期,就该要求用户重新登录了。

当然还可以把这个机制设计得更复杂一些,比如,Refresh Token 每次使用的时候,都更新它的过期时间,直到与它的创建时间相比,已经超过了非常长的一段时间(比如三个月),这等于是在相当长一段时间内允许 Refresh Token 自动续期。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值