Cookie、Session、Token
认证
认证(Authentication)简单来讲就是验证当前者的身份,证明你是你自己。
最常见的认证方式是通过用户名和密码,除此之外还有:
①:通过用户手机:手机短信、手机二维码扫描、手势密码
②:用户的邮箱、身份证号码、基于时间序列和用户相关的一次性口令
③:用户的生物学特征:指纹、语音、眼睛虹膜等
为了确认用户的身份,防止请求伪造,在安全要求高的场合,经常会使用组合认证(也叫多因素认证),也就是同时使用多个认证方式对用户的身份进行校验
授权
授权(Authorization)简单来讲就是授予第三方访问用户资源的权限
在互联网应用开发中,主要通过下面几种方式实现授权:
①:通过 session 机制,一个访问会话保持着用户的授权信息
②:通过 cookie 机制,一个网站的 cookie 保持着用户的授权信息
③:颁发授权令牌(token),一个合法有效的令牌中保持着用户的授权信息
凭证
凭证(Credential)表示你如何证明你的身份,双方都认可的证明
凭证(Credentials)的出现就是系统保证它与用户之间的承诺是双方当时真实意图的体现,是准确、完整且不可抵赖的
HTTP协议是无状态的
Cookie和Session是为了在无状态的HTTP协议之上维护会话状态,使得服务器可以知道当前是和哪个客户在打交道。
因为HTTP协议是无状态的,即每次用户请求到达服务器时,HTTP服务器并不知道这个用户是谁、是否登录过等。现在的服务器之所以知道我们是否已经登录,
是因为服务器在登录时设置了浏览器的Cookie!Session则是借由Cookie而实现的更高层的服务器与浏览器之间的会话。
Cookie
Cookie是由客户端保存的小型文本文件,其内容为一系列的键值对。 Cookie是由HTTP服务器设置的,保存在浏览器中, 在用户访问该服务器的其他页面时,会在HTTP请求中附上该服务器之前设置的Cookie
注意:cookie 是不可跨域的,每个 cookie 都会绑定单一的域名(包括子域),无法在别的域名下获取使用
下面是Cookie的整个传递流程:
1、浏览器向某个URL发起HTTP请求(可以是任何请求,比如GET一个页面,POST一个登录表单等)
2、对应的服务器收到该HTTP请求,并计算应当返回给浏览器的HTTP响应(状态行,消息报头,空行、响应正文)
3、在响应头中加入Set-Cookie字段,它的值是要设置的Cookie。
4、浏览器收到来自服务器的HTTP响应
5、浏览器在响应头中发现Set-Cookie字段,就会将该字段的值保存在内存或者硬盘中,Set-Cookie字段的值可以是很多项Cookie,每一项都可以指定过期时间Expires。默认的过期时间是用户关闭浏览器时。
6、浏览器下次给该服务器发送HTTP请求时,会将服务器设置的Cookie附加在HTTP请求头字段Cookie中。浏览器可以存储多个域名下的Cookie,但只发送当前请求的域名曾经指定的Cookie,这个域名也可以在Set-Cookie字段中指定。
7、服务器收到这个HTTP请求,发现请求头中有Cookie字段,便知道之前就和这个用户打过交道了
8、过期的Cookie会被浏览器删除。
总之,服务器通过Set-Cookie响应头字段来指示浏览器保存Cookie,浏览器通过Cookie请求头字段来告诉服务器之前的状态。Cookie中包含若干个键值对,每个键值对都可以单独设置过期时间。
Cookie 的安全隐患
Cookie提供了一种手段可以使得HTTP请求可以附加当前状态,现今的网站也是靠Cookie来标识用户的登录状态的:
1、用户提交用户名和密码的表单,这通常是一个POST HTTP请求
2、服务器验证用户名和密码,如果合法则返回200(OK),并设置Set-Cookie为authed=true。
3、浏览器存储该Cookie
4、浏览器发送请求时,在请求头中设置Cookie字段为authed=true。
5、服务器收到第二次请求,从Cookie字段得知该用户已经登录。按照已经登录用户的权限来处理此次请求。
但是,有个严重的问题:
发送HTTP请求的不只是浏览器,很多HTTP客户端软件(curl、Node.js)都可以发送任意的HTTP请求,可以设置任何头字段。假如我们直接设置Cookie字段为authed=true并发送该HTTP请求,服务器岂不是被欺骗了?这种攻击非常容易,Cookie是可以被篡改的。
Cookie 防篡改机制
服务器可以为每个Cookie项生成签名,由于用户篡改Cookie后无法生成对应的签名,服务器便可以得知用户对Cookie进行了篡改。一个简单的校验过程如下:
1、在服务器中配置一个不为人知的字符串(我们叫它Secret),比如:想x%#4
2、当服务器需要设置Cookie时(比如authed=false),不仅设置authed的值为false。在值的后面进一步设置一个签名,最终设置的Cookie是authed=false|djdjjddlleeke
3、签名 djdjjddlleeke 是这样生成的:hash('x%#4'+'false')。要设置的值与Secret想加再取哈希
4、用户收到HTTP响应并发现头字段set-Cookie:authed=false|djdjjddlleeke
5、用户在发送HTTP请求时,发现Cookie:authed=true|???。服务器开始进行校验:Hash('x%#4'+'true''),便会发现用户提供的签名不正确。通过给Cookie签名,使得服务器得以知道Cookie被篡改。然而,因为Cookie是明文传输的,只要服务器设置过一次authed=true|xxx,用户就知道true的签名是xxx了,以后就可以用这个签名在没有登录的情况下来欺骗服务器了。因此Cookie中最好不要放敏感数据。一般来讲Cookie中只放一个SessionId,而Session存储在服务器端。
Session
Session特点
Session是另一种记录服务器和客户端会话状态的机制
Session是存储在服务端的,避免了在客户端Cookie中存储敏感数据。Session可以存储在HTTP服务器的内存中,也可以存在内存数据库如redis中,对于重量级的应用甚至可以存储在数据库中。
Session 一般基于 cookie 实现。session 中包含敏感信息存储在服务器端,通常将 sessionId 存储在客户端的 cookie 中,客户端每次请求携带 sessionId 即可识别用户
以存储在redis中的Session为例,考察如何验证用户登录状态的问题:
1、用户提交包含用户名和密码的表单,发送HTTP请求。
2、服务器验证用户发来的用户名和密码
3、如果正确则 把当前用户名(通常是用户对象)存储到redis中,并生成它在redis中的key(ID),这个ID称为SessionID,通过SessionID可以从redis中取出对应的用户对象,敏感数据(比如authId=true)都存储在这个用户对象中。
4、设置Cookie为SessionId=xxxx|checksum并发送HTTP响应,仍然为每一项Cookie都设置签名
5、用户收到HTTP响应后,便看不到任何敏感数据了。在此后的请求中发送该Cookie给服务器。
6、服务器收到此后的HTTP请求后,发现Cookie中有SessionID,进行防篡改验证
7、防篡改验证通过后,根据ID从Redis中取出对应的用户对象,查看该对象的状态并继续执行业务逻辑
Web应用框架都会实现上述过程,在Web应用中可以直接获得当前用户。相当于在HTTP协议之上,通过Cookie实现了持久的会话。这个会话便称为Session。
Cookie和Session的区别
存储:
都是保存用户信息,不同在于cookie 数据存放在客户的浏览器上,session 数据放在服务器上
Session中可以保存任意对象,Cookie只能保存字符串
Session用来保存重要信息,Cookie用来保存不重要的用户信息
很多浏览器限制单个 cookie 保存的数据不能超过4K,一个站点最多保存20个cookie,session 没有类似的限制
安全性:
cookie 是本地存储,不是很安全,别人可以分析存放在本地的 cookie 并进行欺骗
生存周期:
cookie 可设置为长时间保持,Session 一般失效时间较短,一般客户端关闭 session 就会失效
Token
token 是验证用户身份的凭证,我们通常叫它:令牌
最简单的token组成: uid(用户唯一的身份标识)、time(当前时间的时间戳)、sign(签名,以哈希算法压缩成一定长的十六进制字符串)
特点:
-
- 无状态、可扩展
- 支持移动端设备
- 支持跨程序调用
- 安全
token工作流程:
①、客户端使用用户名密码或者扫码等形式请求登录
②、服务端收到请求后进行鉴权,鉴权成功后服务端会生成一个 token,缓存起来,如redia中,设置有效期,并发送给客户端,客户端收到 token 以后,会把它存储起来,比如放在 cookie 里或者 localStorage 里
③、客户端下一次向服务端请求资源的时候需要带着存储的 token
④、服务端收到请求,然后去验证客户端请求里面带着的 token ,如果验证成功,就向客户端返回请求的数据
需要注意:
客户端请求时可以将 token 放到 HTTP 的 Header 里
基于 token 的用户认证是一种服务端无状态的认证方式,服务端不用存放 token 数据
用解析 token 的计算时间换取 session 的存储空间,从而减轻服务器的压力,减少频繁的查询数据库
END.
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构
· AI与.NET技术实操系列(六):基于图像分类模型对图像进行分类