cookie、session、token理论知识
前言
阅读本文前请注意最后编辑时间,文章内容可能与目前最新的技术发展情况相去甚远。欢迎各位评论与私信,指出错误或是进行交流等。
Cookie
注意:本文只涉及理论知识,如需代码以及实操请自行查阅相关资料。
Cookie是什么 ?
- Cookie,有时也写作其复数形式Cookies。类型为“小型文本文件”,是一种用于在客户端浏览器和服务器之间进行状态跟踪的技术。当用户访问一个网站时,服务器将一小段用于标识用户和跟踪用户访问行为的信息发送到用户的浏览器,浏览器将这些信息存储在用户的计算机上(通常经过加密),由用户客户端计算机暂时或永久保存的信息。然后,在用户下次访问该网站时,浏览器会将这些信息发送回服务器,从而实现用户的状态跟踪。
为什么要使用Cookie?
-
先举个例子:我们想象一个场景,当我们打开一个网站时,如果这个网站我们曾经登录过,那么当我们再次打开网站时,发现就不需要再次登录了,而是直接进入了首页。
-
这是怎么做到的呢?其实就是浏览器保存了我们的cookie,里面记录了一些登录信息,当然,这些cookie是服务器创建后返回给浏览器的。浏览器只进行了保存。
-
而如果没有cookie,那么我们每次打开相同的网站进行某些操作,都要进行登录,这带来了不好的用户体验。
-
这是由于web程序是使用HTTP协议传输的,而HTTP协议是无状态的协议,对于事务处理没有记忆能力。无状态意味着如果后续处理需要前面的信息,则它必须重新传输前面的信息。这样可能导致每次连接传送的数据量增大。因此,使用cookie就可以解决这一问题。
Cookie的工作流程
- 客户端向服务器端发送一个请求的时,服务端向客户端发送响应数据和Cookie,然后浏览器将Cookie保存
- cookie有2种存储方式,一种是会话性,一种是持久性。
会话性:如果cookie为会话性,那么cookie仅会保存在客户端的内存中,当我们关闭客户端时cookie也就失效了
持久性:如果cookie为持久性,那么cookie会保存在用户的硬盘中,直至生存期结束或者用户主动将其销毁。
- 当该用户发送第二次请求的时候,就会自动的把上次存储的Cookie数据自动的携带给服务器,服务器通过携带的Cookie数据就能判断当前用户是哪个了。之后每次HTTP请求浏览器都会将上次所保存的Cookie发送给服务器端。

如上图,在客户端第一次访问服务器的时候,本地没有cookie信息。服务器在接收到HTTP请求后创建cookie,并添加到HTTP响应中。通过响应头中的Set-Cookie通知客户端保存cookie。客户端收到HTTP响应后,解析响应报文,在响应头中发现存在Set-Cookie,就去查看本地是否存储了cookie信息。如果本地没有存储那么就新建,如果已存在则对原cookie内容进行修改。

如上图,客户端中已带有cookie,那么在随后的HTTP请求中,会将cookie信息也携带上。这样服务器会顺便解析cookie信息,随即进行后续的处理。
补充:
- Cookie 是服务器返回给浏览器的,通常是首次登录成功之后;
- 不同的客户端保存的 Cookie 是不同的,即使是同一个主机使用不同的浏览器,Cookie 大概率也不会相同;
- Cookie 在本地硬盘中进行保存,是按照不同域名的维度分别进行存储的,比如我们浏览器访问百度会有一组 Cookie ,访问搜狗也有一组 Cookie;
- Cookie 的用途就是在客户端保存数据,最主要的就是保存用户的身份标识,这样服务器就可以通过标识来区分用户了。
Cookie的格式
Cookie 中存的是键值对格式的数据,这里的内容是程序员自定义的。
常见的属性有:
Name:这个是cookie的名字
Value:这个是cooke的值
Path:这个定义了服务器上可以访问该Cookie的目录
Expires:这个值表示cookie的过期时间,也就是有效值,cookie在这个值之前都有效。
Size:这个表示cookie的大小
想要了解cookie所有属性,请自行查找资料
通过抓包进行查看cookie在HTTP请求中是怎样进行表示的。
HTTP请求

再来查看cookie在HTTP响应中是如何进行表示的。
HTTP响应

Cookie的有效路径(展开)
Cookie 的有效路径(path)属性可以有效的选择哪些 Cookie 可以发送给服务器,哪些不发。

- 最先访问的是www.A.com 这个网站,那么服务器会返回一个cookie1,浏览器在保存时会将cookie1的Path设置为当前页面的URL(www.A.com/);
- 用户点击了查看商品的按钮,页面跳转到了www.A.com/goods/ 这个目录下,服务器返回cookie2,浏览器就会将其继续保存,并将其Path设置为(www.A.com/goods/ );
- 后面的cookie3、cookie4都是相同的逻辑,浏览器在接收到cookie后会根据当前页面的URL进行保存;
补充:如果你在 www.A.com/goods/ 这个页面下点击了一个按钮,发起了一个 http 请求,那么该http请求头中的 Cookie 属性将会包含两个 Cookie:cookie1(上一级页面)、cookie2(本页面)。
如果把URL比作文件目录的话,当子目录中的cookie发送时,必然携带父目录中的cookie。
Cookie的生存周期?
- Cookie在生成时就会被指定一个Expire(失效)值,这就是Cookie的生存周期,在这个周期内Cookie有效,超出周期Cookie就会被清除。有些页面将Cookie的生存周期设置为“0”或负值,这样在关闭浏览器时,就马上清除Cookie,不会记录用户信息,更加安全。
Cookie的特点
- 可扩展性:Cookie可以存储任意类型的数据,如用户标识、用户首选项等。这使得网站可以根据用户的需求和行为来提供个性化的服务。
- 灵活性:Cookie可以通过设置路径和域来限制它们的作用范围,使得不同的网页或子域可以拥有各自的Cookie。
- cookie存储的数据量有限,不同的浏览器有不同的存储大小,但一般不超过4KB。因此使用cookie只能存储一些小量的数据。
Cookie有哪些缺陷 ?
- 数量受到限制。一个浏览器能创建的 Cookie 数量最多为 300 个,并且每个不能超过 4KB,每个 Web 站点能设置的Cookie 总数不能超过 20 个
- 安全性无法得到保障。通常跨站点脚本攻击往往利用网站漏洞在网站页面中植入脚本代码或网站页面引用第三方法脚本代码,均存在跨站点脚本攻击的可能,在受到跨站点脚本攻击时,脚本指令将会读取当前站点的所有Cookie 内容,然后通过某种方式将 Cookie 内容提交到指定的服务器。一旦 Cookie 落入攻击者手中,它将会重现其价值。
- 浏览器可以禁用Cookie,禁用Cookie后,也就无法享有Cookie带来的方便。
补充:关于cookie的安全性问题,cookie常见的不安全表现形式有以下方式:
(关于cookie安全方面的问题,请自行查阅资料,本文仅作简单介绍)
1)cookie欺骗; cookie既然不安全,为何不加密呢?加密后就算拿到cookie不是也没有用么?关键问题就在这里了,一些别有用心的人不需要知道这个cookie的具体含义,只需要将这个cookie向服务器提交(模拟身份验证),身份验证通过之后,就可以冒充被窃取cookie的用户来访问网站,甚至获取到用户的隐私信息,对于用户的隐私造成非常严重的危害,这种方式就叫做cookie欺骗。
2)cookie截获; cookie以纯文本的形式在浏览器和服务器之间传递,在web通信时极容易被非法用户截获和利用。非法用户截获cookie后,在cookie的有效时间内重新发送给服务器,那么这个非法用户就拥有了这个合法用户的所有权限。
3)Flash的内部代码隐患; Flash中有一个getURL()函数,Flash利用它自动打开指定的页面。那么这个就意味着,你在观看Flash动画时,在Flash的内部可以悄无声息的打开一个极小的不易发现的包含特殊操作的页面,可以是木马,可以向远端输入当前cookie或者用户信息,这是非常危险的,由于这个是Flash内部的操作,所以网站无法禁止,要想避免,尽量打开本地防火墙以及访问正规网站。
Cookie的应用场景

Session
什么是会话
用户开一个浏览器,点击多个超链接,访问服务器多个web资源,然后关闭浏览器,整个过程称之为一个会话。用户可能会多次请求访问同一个资源,也有可能请求访问各种不同的服务器资源。
什么是Session ?
- Session在计算机中,尤其是在网络应用中,称为“会话控制”。Session 对象存储用户会话所需的属性及配置信息。
Session的作用
我们先来想一个问题,在Web开发中,防止表单重复提交是一个常见需求。尤其是在用户点击提交按钮后,如果用户不小心再次点击或者在表单提交过程中网络出现问题导致表单未能即时响应,用户可能会尝试再次提交。
为了解决这个问题,我们可以使用一种新的技术,Session。session是存储于服务器端的特殊对象,服务器会为每一个浏览器(客户端)创建一个唯一的session。这个session是服务器端共享,每个浏览器(客户端)独享的。
通过在服务器端使用Session变量来跟踪表单是否已经被提交过,可以有效地防止重复提交。
session的简单原理示意图

Session的可使用场景
Session在Web开发中具有多种重要作用,主要包括以下几个方面:
- 保持用户状态:Session通过在服务器端存储用户相关的信息(如登录状态、购物车内容等),使得用户在不同页面之间的切换时,能够保持其状态不变,实现无缝的用户体验。
- 跟踪用户行为:Session可以帮助开发人员收集用户在网站上的行为数据,例如页面访问路径、点击行为等,从而进行用户行为分析和网站优化。
- 个性化服务:根据用户的喜好和历史行为,Session可以为用户提供个性化的内容和服务,提升用户体验。
- 权限验证和安全:Session可以用于存储用户的登录状态和权限信息,确保用户只能访问其被授权的资源。此外,Session还可以用于防止表单重复提交等安全问题。
Session的工作流程
- 当用户请求服务器端的 Web 页面时,如果该用户还没有结束会话,则 Web 服务器将自动创建一个 Session 对象,同时会创建一个特殊的Cookie(name为JSESSIONID的固定值,value为session对象的ID)。(如下图所示)
- 这样,当用户在 Web 页之间跳转时,存储在 Session 中的变量将不会丢失,而是在整个用户会话中一直存在下去。
- 由于第一次访问服务器时,没有携带这种特殊的Cookie,所以服务器会创建一个Session 对象。

- 服务器会向客户浏览器发送一个每个用户特殊的Cookie,其中携带了独有的会话编号sessionID。服务器同时也把sessionID和对应的用户信息、用户操作记录在服务器上,这些记录就是session。(如下图所示)

- 当用户再次访问服务器时会携带发送cookie给服务器,其中携带了独有的sessionID。(如下图所示)

- 服务器从cookie里找到sessionID,再根据sessionID找到以前记录的用户信息就可以知道他之前所作的操作、访问过哪里等信息,随后再发送响应信息。(如下图所示)

Session的格式
session类似于一个Map,里面可以存放多个键值对,是以key-value形式进行存放的。
Session的生命周期 ?
-
超时:Session通常有一个超时设置(由服务器端设定),如果在指定时间内没有活动,Session将自动过期。一旦有操作,session 会重新计时。
举个例子,有一个服务器设置Session为30分钟超时。你登录该服务器,服务器返回给你一个sessionID。登录成功之后的半小时之内没有对该服务器进行任何HTTP请求,半小时后你进行一次HTTP请求,会提示你重新登录。 -
手动注销:用户可以主动注销,销毁Session。
Cookie与Session的区别
- Cookie存储在客户端,Session存在服务器
- Session比Cookie更具有安全性(Cookie有安全隐患,通过拦截或本地文件找得到你的cookie后可以进行攻击)
- Session占用服务器性能,Session过多,增加服务器压力
- 单个Cookie保存的数据不能超过4K,很多浏览器都限制一个站点最多保存20个Cookie,Session是没有大小限制和服务器的内存大小有关。
- cookie作用于他所表示的有效路径(path)中,范围较小。session代表客户端和服务器的一次会话过程,web页面跳转时也可以共享数据,范围是本次会话,客户端关闭也不会消失。会持续到我们设置的session生命周期结束。
Cookie和Session的联系
-
目的相同:
Session和Cookie都用于在无状态的HTTP协议中维护用户的状态和信息。 -
协同工作:
通常,Session和Cookie一起使用。服务器使用Session来存储用户状态信息,而Cookie用于在客户端存储Session ID,以便在后续的请求中识别用户的Session。 -
数据传递:
当服务器创建一个Session时,它会生成一个唯一的Session ID,并通过设置Cookie的方式将Session ID发送给客户端。客户端在后续的请求中携带这个Session ID,以便服务器能够识别和恢复用户的Session状态。
token
什么是token
token(令牌) 是一种在计算机系统中用于标识用户身份、授权访问权限或传递安全信息的数字签名凭证。
例如,访问令牌(access token)用于身份验证和授权,API令牌(API token)则用于访问和使用特定的API服务。token的主要作用是帮助系统识别和管理用户的权限,确保只有经过授权的用户才能访问特定的资源或服务。
token产生过程通常是由后端开发人员通过代码生成,用户登录后返回给前端,在本地保存起来,后续在访问、使用特定API服务或者进行身份验证的时候,拿出来用作身份识别。Token 的一个显著特点是其 无状态性,这意味着服务器不需要存储关于用户会话的数据,而是通过解析客户端携带的 Token 来获取所有的身份信息。
为什么要用token
session 的痛点(负载均衡导致的)
实际在生产上,为了保障高可用,一般服务器至少需要两台机器,通过负载均衡的方式来决定到底请求该打到哪台机器上。

如图示:客户端请求后,由负载均衡器(如 Nginx)来决定到底打到哪台机器
假设登录请求打到了 A 机器,A 机器生成了 session 并在 cookie 里添加 sessionId 返回给了浏览器,那么问题来了:下次添加购物车时如果请求打到了 B 或者 C,由于 session 是在 A 机器生成的,此时的 B,C 是找不到 session 的,那么就会发生无法添加购物车的错误,就得重新登录了,此时请问该怎么办。主要有以下三种方式
1.session 复制
A 生成 session 后复制到 B, C,这样每台机器都有一份 session,无论添加购物车的请求打到哪台机器,由于 session 都能找到,故不会有问题

这种方式虽然可行,但缺点也很明显:
- 同一样的一份 session 保存了多份,数据冗余
- 如果节点少还好,但如果节点多的话,特别是像阿里,微信这种由于 DAU 上亿,可能需要部署成千上万台机器,这样节点增多复制造成的性能消耗也会很大。
2.session 粘连
这种方式是让每个客户端请求只打到固定的一台机器上,比如浏览器登录请求打到 A 机器后,后续所有的添加购物车请求也都打到 A 机器上,Nginx 的 sticky 模块可以支持这种方式,支持按 ip 或 cookie 粘连等等,如按 ip 粘连方式如下
upstream tomcats {
ip_hash;
server 10.1.1.107:88;
server 10.1.1.132:80;
}

3.session 共享
这种方式也是目前各大公司普遍采用的方案,将 session 保存在 redis,memcached 等中间件中,请求到来时,各个机器去这些中间件取一下 session 即可。

缺点其实也不难发现,就是每个请求都要去 redis 取一下 session,多了一次内部连接,消耗了一点性能,另外为了保证 redis 的高可用,必须做集群,当然了对于大公司来说, redis 集群基本都会部署,所以这方案可以说是大公司的首选了。
通过上文分析我们知道通过在服务端共享 session 的方式可以完成用户的身份定位,但是不难发现也有一个小小的瑕疵:搞个校验机制我还得搭个 redis 集群?大厂确实 redis 用得比较普遍,但对于小厂来说可能它的业务量还未达到用 redis 的程度。
所以有没有其他不用 server 存储 session 的用户身份校验机制呢,那么就是token。
token的特点
-
无状态性:在 Token 认证机制中,服务器不需要保存任何关于会话的状态数据。每次请求,客户端都会在请求头中附带 Token,服务器通过解析 Token 来验证身份。这样的设计有助于减少服务器存储压力,尤其适合分布式和微服务架构。
-
自包含性:以 JWT 为代表的 Token,通常包含了用户的身份信息、权限信息等数据,这些信息直接存储在 Token 本身中。这样,服务器在接收到 Token 后无需查询数据库或其他后端服务,直接通过解析 Token 获取信息。
token的使用场景和工作流程
身份验证(Authenticatin)
token在网络通信中的身份验证过程通常包括以下步骤:
1、用户登录:
用户向服务器提供有效的身份凭证(如用户名、密码),经过服务器验证通过后,表明用户身份已得到确认
2、token生成:
服务器在用户身份验证成功后,生成一个Token。这个Token通常包含用户标识符、过期时间、可能还有一些其他安全属性(如发行时间、会话ID等)。对于某些Token类型(如JWT),还可能包含用户的角色、权限等附加信息。
3、token发放:
服务器将生成的Token返回给用户端(如浏览器、移动端应用)。用户端可以将其存储在Cookie、LocalStorage、HTTP Only Cookie、内存中,或者作为HTTP请求头的一部分发送。
4、token携带:
在后续的网络通信中,用户端在发起请求时,将Token附在请求中(通常在Authorization HTTP头中以Bearer Token的形式)。例如:
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9…
5、服务器验证:
服务器接收到请求后,首先提取请求中的Token。然后,根据Token的类型和配置,服务器执行相应的验证逻辑,如:
- 验证Token的签名以确保其未被篡改。
- 检查Token是否已过期。
- 核实Token中的用户标识符是否存在且有效。
- 解析Token中的附加信息,如角色、权限等。
如果Token验证通过,服务器认为请求发起者的身份已得到确认,从而完成身份验证过程。

授权(Authorization)
Token在网络通信中实现授权的主要方式如下:
权限编码:
Token可以内嵌用户的权限信息,如角色、操作权限、访问资源的范围等。这些信息通常在Token生成时被服务器写入,并在验证Token时被解析和使用。
访问决策:
当服务器接收到带有Token的请求时,除了验证Token以确认用户身份外,还会进一步检查Token中包含的授权信息,以确定用户是否有权执行请求的操作或访问请求的资源。这一步骤可能涉及:
- 解析Token载荷中的权限字段(如scope、roles等)。
- 将Token中的权限与请求所需的权限进行比较。
- 根据比较结果决定是否允许请求继续执行。
细粒度控制:
Token可以支持细粒度的访问控制策略,如基于资源的访问控制(RBAC)、基于属性的访问控制(ABAC)等。服务器可以根据Token中编码的权限数据,精确控制用户对特定资源的操作权限,如读、写、删除等。
token的格式
JWT (JSON Web Token)
JWT是最常用的Token格式之一,其组成非常明确且标准化。一个JWT由三部分组成,各部分之间用.(点号)分隔:
1、Header(头部)
描述Token的基本元数据,通常包含:
typ (type): 标识Token的类型,对于JWT,通常是 “JWT”。
alg (algorithm): 指定用于签名Token所使用的加密算法,如 “HS256”(HMAC SHA-256)、“RS256”(RSA with SHA-256)等。
Header通常以Base64 URL安全编码表示。
2、Payload(载荷)
存储实际的声明(claims),即携带的用户信息和额外数据。常见的标准声明包括:
iss (issuer): 发行Token的实体。
sub (subject): Token所代表的主体(如用户ID)。
aud (audience): 接收Token的受众(如服务端API)。
iat (issued at): Token的发行时间。
exp (expiration time): Token过期时间,以Unix时间戳表示。
jti (JWT ID): Token的唯一标识符,有助于防止重放攻击。
除此之外,还可以包含自定义声明,用于传递特定应用所需的信息。Payload同样以Base64 URL安全编码表示。
3、Signature(签名)
通过对Header和Payload的组合进行指定算法(Header中alg字段指定的算法)的计算,生成一个用于验证Token完整性和防篡改的签名。计算过程中通常结合一个密钥(secret),确保只有持有该密钥的实体才能生成有效的Token。签名也是Base64 URL安全编码表示。
以下为一个JWT格式的token
eyJhbGciOiAiSFMyNTYiLCAidHlwIjogIkpXVCJ9.eyJzdWIiOiAiMTIzNDU2Nzg5MCIsICJuYW1lIjogIkpvaG4gRG9lIiwgImVtYWlsIjogImpvaG4uZG9lQGV4YW1wbGUuY29tIiwgImlhdCI6IDE1MTYyMzkwMjIsICJleHAiOiAxNTE2MjM5MzIyLCAicm9sZSI6ICJ1c2VyIn0.
非JWT Token
对于非JWT类型的Token,其组成可能更为灵活,但通常仍包括以下核心元素:
1、身份标识符
用户的唯一标识符,如用户ID(uid)。这是识别Token关联用户的最基本信息。
2、时间戳
发行时间(iat)和/或过期时间(exp),用于判断Token的有效期。过期时间有助于确保短期访问权限,并减少长期未使用的Token带来的安全风险。
3、签名或哈希
使用密钥和特定算法(如HMAC、RSA等)对Token的其他部分或部分信息进行签名或哈希运算,生成一个验证Token完整性和来源的值。这可以防止Token被篡改。
4、附加信息(可选)
角色、权限、会话ID、设备信息等附加数据,根据应用需求可能包含在Token中,用于更精细的访问控制和上下文识别。
加密Token
对于需要更高安全级别的场景,Token可能会采用加密方式来保护敏感信息。加密Token除了包含上述组成部分外,还会对载荷(Payload)部分进行加密处理,使得未经解密无法直接读取其中的内容。解密通常需要持有对应的解密密钥。
加密Token通常会对Payload进行加密处理,以保护敏感信息。
token的优缺点
| 优点 | 详细说明 |
|---|---|
| 无状态 | 服务器无需存储会话数据,减轻了服务器的负担,适用于分布式架构和微服务。 |
| 跨平台支持 | Token 可以跨域、跨平台传递,适用于前后端分离的架构。 |
| 灵活性高 | 可以自定义 Payload,携带用户信息、权限等数据。 |
| 高效 | 无需频繁查询数据库或其他服务,验证过程通过解析 Token 完成。 |
| 支持跨域认证 | 使用 Token 作为身份认证机制,可以跨域验证,避免了 Cookie 的跨域限制。 |
| 缺点 | 详细说明 |
|---|---|
| Token 长度较大 | JWT 的大小通常较大,尤其是当 Payload 包含大量数据时,影响网络传输性能。 |
| Token 被盗用风险 | 如果 Token 被窃取,攻击者可以利用它访问用户数据,因此需要妥善保管 Token。 |
| 不易撤销 | Token 一旦颁发并使用后,无法轻易撤销或失效,除非通过设置短有效期或实现其他机制来定期更新 Token。这使得 Token 的失效管理较为复杂。 |
Session和token的区别
- token存储在客户端;session存储在服务器端;
- token提供认证和授权功能,作为身份认证,token安全性比session好,因为每个请求都有签名还能防止监听以及重放攻击;session就必须靠链路层来保障通讯安全,如果你需要实现有状态的会话,仍然可以增加session来在服务器端保存一些状态
- token不一定存储;session存在服务器中,增加服务器压力;
- token可以跨域;session不可以跨域,它是与域名绑定的,扩展性不强;
- token是时间换空间;session是空间换时间
- Session 是一种记录服务器和客户端会话状态的机制,使服务端有状态化,可以记录会话信息。而 Token 是令牌,访问资源接口(API)时所需要的资源凭证。Token 使服务端无状态化,不会存储会话信息。
- 如果你的用户数据可能需要和第三方共享,或者允许第三方调用 API 接口,用 Token 。
参考目录
https://blog.csdn.net/weixin_45393094/article/details/104747360
https://blog.csdn.net/m0_51545690/article/details/123359959
https://blog.csdn.net/weixin_52533007/article/details/131734560
https://blog.csdn.net/qq9808/article/details/104932886
https://blog.csdn.net/m0_51545690/article/details/123384986
https://blog.csdn.net/wendao76/article/details/143194793
https://blog.csdn.net/qq_52758588/article/details/137457841
https://blog.csdn.net/Stromboli/article/details/143651913
https://blog.csdn.net/huangpb123/article/details/103933400
https://blog.csdn.net/weixin_42672802/article/details/132511713
更多推荐
所有评论(0)