【前端知识】Cookie, Session,Token和JWT的发展及区别(上)
- 1. 背景
- 2. Cookie
- 2.1 Cookie的定义
- 2.2 Cookie的特点
- 2.3 Cookie的一些重要属性
- ✨2.3.1 Cookie的重要属性
- 🎇2.3.2 Cookie的有效期,max-age和作用域,domain
- 2.4 Cookie的认证流程
- 2.5 Cookie的优缺点及常用场景
- 😎2.5.1 优点
- 🤢2.5.2 缺点
- ✍2.5.3 作用及常用场景
- 2.6 Cookie可能面临的挑战
- 2.6.1 客户端禁用 cookie 首部时,如何传递 cookie 信息?
- 2.7 怎么检查Cookie是否启用/禁用
- 2.8 Cookie的读写
- 💻2.8.1 客户端对Cookie的读取及相关操作
- 👩💻2.8.2 服务端对Cookie的设置
- 3. 下篇章笔记
五一假期第3天,2023年5月1日继续打卡分享自己的前端笔记😜,今天就分享我关于Cookie, Session,Token和JWT的相关笔记和理解吧。本文为原创,未经同意请勿转载
由于篇幅有点长😂,所以笔者将我关于这部分的笔记分为上中下三个篇章(文章开头后面附录上下篇链接),避免读者的阅读疲倦感😵,同时也方便大家的阅读啦🤗。如果下面笔记中存在错误,欢迎大家及时指正,学习与讨论。
- 上章:主要介绍一下背景和Cookie。
- 中章:主要介绍一下Session并总结一下Cookie和Session。
- 下章:主要介绍Token,JWT以及总结一下啦。
1. 背景
首先,先介绍Cookie/Session/Token/JWT它们出现的一个背景(更加准确的描述其实应该是Cookie出现的背景),也就是HTTP的无状态属性。
众所周知,我们访问网页一般都是使用HTTP/HTTPS协议,然而HTTP是一种不保存状态,即无状态协议。那什么是无状态呢?也就是这一次请求和上一次请求是没有任何关联的。这种无状态的好处就是可以快速响应。但是如果服务端需要辨别请求时哪个客户端发送,或者需要关联两个请求/响应时,就需要获取请求或者响应的状态,因此这种无状态便无法满足我们的需求了。因此,为了使某个域名下的所有网页能够共享某些状态数据,引申出了Cookie和Session。
💡总结而言
由于HTTP是无状态协议,不保存通信状态,无法标识客服端,所以Cookie、Session和Token都是用来解决这个问题的(做持久化处理的),目的就是让客户端,也就是浏览器和服务端互相认识。
Cookie、Session、Token和JWT都是用于标识客户端的,而且从发展上来看可以看成网络安全的一个发展吧。那它们之间有什么区别,下面笔者我将详细对每一个部分展开说明。
2. Cookie
2.1 Cookie的定义
首先,Cookie由服务器创建的,只保存在浏览器中的小型文本文件,格式为key=value,一般包含用户信息,登录及访问权限等。
2.2 Cookie的特点
(1)由服务器生成并存储在客户端的
(2)以普通文本方式存储键值对数据,无法执行代码
(3)不可跨域:每个Cookie会绑定单一的域名,无法在别的域名下使用,一级域名和二级域名之间是允许共享使用的(靠的是 domain)。同一个域名下的不同页面之间可以共享Cookie,同域名不同端口也是允许共享使用的。
(4)有过期时限:Cookie会在过期时间到达之后自动删除
(5)文件体积大小,数量有限制:一般在4KB左右,数量在50个左右
(6)自动发送
(7)只能存储String 类型的对象
2.3 Cookie的一些重要属性
✨2.3.1 Cookie的重要属性
cookie集合中的每个cookie都拥有下面这些重要的属性,而且每个cookie的这些属性都是独立分开的,各自控制各自的cookie。
-
数据类型:在Cookie中,设置键值对的键名name和键值value都必须是字符串类型,如果是Unicode
字符,需要为字符编码;如果值为二进制数据,则需要使用 BASE64 编码。 -
domain:指定 Cookie 所属域名,默认是当前域名
-
path: 指定 Cookie 在哪个路径(路由)下生效,默认是 ‘/’
-
maxAge: Cookie 失效的时间,单位秒,默认为 -1。如果为正数,则该 Cookie 在 maxAge 秒后失效。如果为负数,该 Cookie 为临时 cookie ,关闭浏览器即失效,浏览器也不会以任何形式保存该 cookie 。如果为 0,表示删除该 Cookie 。
-
secure :设置Cookie是否使用安全协议传输。安全协议有 HTTPS,SSL等,在网络上传输数据之前先将数据加密。默认为false。当 secure 值为 true 时,Cookie 在 HTTP 中是无效,在 HTTPS 中才有效。
-
HttpOnly:如果给某个 Cookie 设置了HttpOnly属性,则无法通过 JS 脚本 读取到该Cookie 的信息,但还是能通过 Application 中手动修改 Cookie,所以只是在一定程度上可以防止 XSS 攻击,不是绝对的安全。
-
SameSite:设置cookie在跨域请求的时候不能被发送。
🎇2.3.2 Cookie的有效期,max-age和作用域,domain
- 默认有效期:虽然客户端计算机上 Cookie 的持续时间还取决于客户端上的 Cookie 过期处理和用户干预,但Cookie默认的有效期是短暂的,即Cookie只能维持在Web浏览器的会话期间,一旦用户关闭浏览器,Cookie保存的数据就丢失了。
- 默认有效期作用域:Cookie的作用域不是局限在浏览器的单个窗口中,它的有效期和整个浏览器进程而不是单个浏览器窗口的有效期一致。
- max-age设置——>数据持久性:要知道Cookie的优点还有数据持久性,那这不是跟上面的有效期短暂矛盾了吗?其实不然。数据持久性不是指在默认有效期的情况下,而是由于max-age的设置,所以Cookie具有数据持久性的特点是基于max-age的。一旦设置了有效期,浏览器就会将Cookie数据存储在一个文件中,并且直到过了指定的有效期才会删除该文件。这个到期时间可以是具体的日期时间也可以是相对时间,这样就让 Cookie 能够在指定时间范围内存在,从而实现数据持久化。
- 作用域:Cookie的作用域默认由文档源限制,可以通过文档源和文档路径来确定的。该作用域通过Cookie的path和domain属性也是可配置的。默认情况下,Cookie和创建它的Web页面有关,并对该Web页面以及和该Web页面同目录或者子目录的其他Web页面可见。
- domain设置——>同域子域名可访问:在没有设置 domain 的情况下,默认 Cookie 只设置在当前域名下。当然我们可以设置domain属性,但是需要注意domain只能设置为当前服务器的域名,也就是这个 domain 只能是当前域名的上级域名,这样上级域名相同的网站就都能读取到这个Cookie了。比如:我在网站 aa.ryDomain.com 下设置 cookie:“myName=xiaobai_Ry; domain=.ryDomain.com”,这样在 bb.ryDomain.com 下也能读取到 myName=xiaobai_Ry。
2.4 Cookie的认证流程
-
认证流程简述:在用户第一次访问网站服务器时,服务器会通过响应头Set-Cookie字段发给浏览器,浏览器接收后会把Cookie信息以键值对的形式保存到浏览器本地某个txt文件中。在后面访问的时候,浏览器就都会将保存的Cookie发送给服务器,以此让服务器识别身份(让服务器知道这个请求来自于哪个客户端)。
一个例子:Set-Cookie: "name=value;domain=.domain.com;path=/;expires=Mon, 01 May 2023 14:00:00 GMT;HttpOnly;secure"
📢
注意:
这里需要注意的一点是客户端第一次向浏览器请求时,携带的Cookie是空的(也就是相当于没有Cookie),响应页面也没有给Cookie设置,所以Cookie实际上就是在服务器中设置和生成的,并返回给客户端保存 -
认证流程步骤叙述:发布——》检索——》验证
1、发布:当用户想要访问和使用网站里经过认证的资源时,Web服务器会检测与核查用户是否提供了cookie,对用户的请求进行审核与验证。
2、检索:用户提出了访问请求,客户端浏览器会检索与用户请求相匹配的cookie。
3、验证:Web服务器会验证是否有访问令牌,如果有访问令牌的话,则同意用户的请求,如果没有这个令牌,则会拒绝用户的访问和登录请求。
2.5 Cookie的优缺点及常用场景
😎2.5.1 优点
优点总结
:极高的扩展性和可用性,便于使用、实现和管理,占用内存少,具有可持久性,透明性。优点展开
:- 简单性,便于使用和实现:Cookie是一种基于文本,以键值对形式存储数据的轻量结构,数据形式简单,实现Cookie的使用要比其他协议更加简单容易。
- 轻量化,占用内存少,不需要任何服务资源:Cookie 存储在客户端并在发送后由服务器读取,因此不会给服务器带来额外的负担。
- 数据持久性和稳定性:虽然客户端计算机上 Cookie 的持续时间取决于客户端上的 Cookie 过期处理和用户干预,Cookie 通常是客户端上持续时间最长的数据保留形式。这也是Cookie很大的一个优点所在。当在客户端的浏览器上设置Cookie时,它可以持续数天,数月甚至数年。这样可以轻松保存用户首选项和访问信息,并在用户每次返回站点时保持此信息可用。另外,由于Cookie存储在客户端的硬盘上,因此如果服务器崩溃,它们仍然可用。
- 透明性:Cookie以明文形式存储,透明地工作,用户不知道需要存储的信息。
- 灵活性,可配置到期规则,可通过加密和安全传输计数来提高Cookie安全性:Cookie 可以在浏览器会话结束时到期,或者可以在客户端计算机上无限期存在,这取决于客户端的到期规则。通过加密和安全传输技术(ssl),可以减少cookie被破解的可能性。
- 易于管理:Cookie存储在用户硬盘驱动器上的cookie.txt下的文本文件中,因为它是一个文本文件,我们可以使用任何查看器或文本编辑器来显示,编辑和删除它们。
- 可跨页面传输数据(
注:同域
):cookie 可以在同一个网站的不同页面之间传递数据,比如购物车中的商品信息 - 可保存用户状态信息:cookie 可以将用户的登录状态保存在浏览器中,避免了每次访问页面都需要重新验证身份的问题。
- 提高用户体验:例如记录用户的偏好设置,可以为用户提供更加个性化的服务。
🤢2.5.2 缺点
缺点总结
:虽然Cookie简单便于管理,但是Cookie存在隐私隐患,安全性问题,禁用限制问题和大小及访问限制等问题。缺点展开
:- 隐私泄漏问题:启用Cookie的Web浏览器会跟踪访问过的所有网站。这意味着,经许可(或不在Google的情况下),第三方(广告商,其他用户,甚至黑客)可以访问这些Cookie存储的信息。因此,Cookie 存储的用户信息可能违背用户的隐私权,因此应该尽量少用无关信息的 Cookie,且应该经过用户同意后再进行存储。
- 安全性问题:由于Cookie 存储在客户端,并且是以明文形式存储,所以Cookie中存储的数据可能被其他人窃取或者篡改,特别是在使用不安全网络时。Cookie很容易受到CSRF(跨站请求伪造)攻击。
- 大小数量限制问题:每个Cookie 文本的大小和数量有所限制,一般情况下体积大小不能超过4kb,如果超过会被截掉,因此无法存储大量的信息。此外,Cookie仅限于简单的字符串信息,他们无法存储复杂的信息。Cookie的数量也存在一些限制,不同浏览器限制不同:
- IE6及以下的版本最多20个cookie
- IE7以后的可以有50个cookie
- Firefox可以有50个cookie
- Chrome和Safri没有限制
- 禁用限制问题:Cookie可以被浏览器禁用,当浏览器选择禁用Cookie模式,意味着用户可以决定不在其浏览器上使用Cookie,这可能会在浏览器的运行中产生一些问题。
- 访问限制问题(
主要指跨域
):Cookie 是不可跨域的,要实现跨域需要使用Token等。此外,Cookie与浏览器相关,不能互相访问。 - 加密解密困难问题:可以手动加密和解密Cookie来提高Cookie安全性,但由于加密和解密需要额外的编码,并且加密和解密需要时间,因此会影响应用程序的性能。
- 有些状态不可能保存在客户端:如,为了防止重复提交表达,需要在服务器端保存一个计时器,如果把这个计时器保存在客户端,它将不起作用。
✍2.5.3 作用及常用场景
常用场景总结
:(1)登录状态及用户信息的管理;(2)跟踪用户行为,统计分析,广告定位;(3)记住用户偏好设置,定制页面;(4)创建购物车;(5)缓存数据,用于搜索历史和浏览记录;(6)跨页面数据传递,实现数据共享与同步 …展开
:- 登录状态及用户信息的管理——》用户身份认证,登录状态保持:用户登录和用户信息管理是常见的功能。可以使用 cookie 来存储用户登录状态信息,例如用户的登录凭证、用户信息等。通过 Cookie,可以在客户端和服务器之间传递用户信息,实现用户登录状态的保持,避免了每次访问页面都需要重新验证身份的问题。
- 跟踪用户行为(自动性)——》统计分析,统计用户访问网站的习惯,广告定位:通过记录用户行为等信息,跟踪用户的访问、页面浏览、点击等数据,进行统计分析,根据这些统计分析信息,可以为客户提供定制化的上网服务。同时,广告商也可借此为向用户展示相关的广告。
- 记住用户偏好设置(设置性/被动)——》定制页面,提供个性化服务:可以使用 Cookie 来存储用户的偏好设置信息来提供个性化的服务,例如用户的语言、主题等,使得用户下次打开浏览器时可以继续使用之前的偏好设置。
- 缓存数据——》用于搜索历史和浏览记录,减少服务器压力:可以使用 Cookie 来存储搜索历史和浏览记录等信息,提高网站的性能。比如自动填写表单场景,如果用户曾经输入过某些信息,那么这些信息可以被保存在 Cookie 中,在用户返回该页面时可以自动带出。
- 跨页面数据传递——》实现数据的共享与同步:Cookie 可以在同一个网站的不同页面之间传递数据,比如购物车中的商品信息。
经典场景之购物车
:Cookie购物车一般指网站上的电子商务功能,在用户浏览产品后,将所选商品信息保存到浏览器的Cookie中,并在结账时读取Cookie中的信息以便显示或更新所选商品内容和数量。通常情况下,Cookie购物车还会在用户离开网站后保存所选商品信息,以便用户下次访问同一网站时继续购物,或在用户登录到网站时提供更个性化的服务。然而,由于安全原因,有些用户可能不愿意让浏览器储存他们的个人信息(例如地址和支付方式),因此一些商家采用了其他方法来保存购物车内容。需要注意的是,使用 Cookie 存储数据时应当注意数据的安全性和敏感性。敏感信息,例如用户的密码、支付信息等,不应当存储在Cookie中,而应当使用更加安全的方式
2.6 Cookie可能面临的挑战
面临的挑战当然也包括Cookie的缺点,这里就不再赘述,这里主要讲一下禁用限制问题的解决方法:
2.6.1 客户端禁用 cookie 首部时,如何传递 cookie 信息?
可以将 cookie 信息放到 url 的 params 中或者请求的 body 中,但一般的解决方案是放在 url 的 params 中,通过重写 url 的方式传递。
由于cookie可以被人为的禁止,必须有其他机制以便在cookie被禁止时仍然能够把session id传递回服务器。经常被使用的一种技术叫做URL重写,就是把session id直接附加在URL路径的后面,附加方式也有两种:
- 一种是作为URL路径的附加信息,表现形式为
http://…/xxx;jsessionid=ByOK3vjFD75aPnrF7C2HmdnV6QZcEbzWoWiBYEnLerjQ99zWpBng!-145788764
- 另一种是作为查询字符串附加在URL后面,表现形式为
http://…/xxx?jsessionid=ByOK3vjFD75aPnrF7C2HmdnV6QZcEbzWoWiBYEnLerjQ99zWpBng!-145788764
这两种方式对于用户来说是没有区别的,只是服务器在解析的时候处理的方式不同,采用第一种方式也有利于把session id的信息和正常程序参数区分开来。
2.7 怎么检查Cookie是否启用/禁用
前面我们讲了Cookie是可以被人为禁止的,那我们确保在执行我们的Cookie是可用的?通过判断是否禁用来选择不同的解决方案。
要检查浏览器是否禁用Cookie,可以使用JavaScript中的navigator.cookieEnabled属性来判断。这个属性返回布尔值,指示浏览器是否允许Cookie,如果值为true,则当前Cookie是启用的;反之则可能是禁用的。
if (navigator.cookieEnabled) {
alert("Cookies are enabled");
} else {
alert("Cookies are disabled");
}
⚠ 这里需要注意有2点
:
(1)这种方法并不能完全确定用户的浏览器是否完全禁用了Cookie。因为有一些非持久化的cookie仍然可以在当前浏览器会话生命周期内使用,即使用户明确禁用了所有cookie。
(2)返回false时并不意味着用户明确禁用了Cookie。 还可能存在其他因素干扰Cookie,例如隐私设置或运行安全软件等。
💡 因此,在实际开发中,使用navigator.cookieEnabled
属性来判断是否启用Cookie并不可靠。更好的方法是尝试写入一个持久化的Cookie,如果成功则表示用户的浏览器支持Cookie。否则,建议提醒用户在其浏览器设置中启用Cookie功能。
2.8 Cookie的读写
💻2.8.1 客户端对Cookie的读取及相关操作
在Web中,客户端对Cookie的操作主要包括读取和设置(修改更新和删除等)。
(1)读取Cookie
通过document.cookie
属性可以访问当前页面所有存在的Cookie信息,比如:
var cookies = document.cookie;
document.cookie
返回值为一个字符串,该字符串有一系列键/值对组成,比如:
"fryname1=value1; fryname2=value2"
其中每个cookie用分号(;)隔开,而每个cookie的键和值用等号(=)隔开。而且返回的每个Cookie值并不包含键/值以外的其他Cookie属性。
如果要获取某个特定Cookie的值,可以采用字符串截取或者正则表达式进行匹配。例如,获取名为fryname2
的Cookie值:
var cookies = document.cookie;
var cookieValue = null;
if (cookies && cookies !== '') {
var cookieArray = cookies.split(';');
for (var i = 0; i < cookieArray.length; i++) {
var cookie = cookieArray[i].trim();
if (cookie.substring(0, 8) === 'fryname2') {
cookieValue = cookie.substring(9, cookie.length);
break;
}
}
}
console.log(cookieValue);
(2)设置Cookie相关属性
通过JavaScript可以向客户端设置Cookie值。可以使用document.cookie
来设置Cookie的相关属性。
document.cookie = "key=value;expires=date;path=path;domain=domain;secure";
由于Cookie的键/值中的值是不允许包含分号、逗号和空白符,因此,在存储前一般可以采用 encodeURIComponent() 函数对值进行编码。相应的,读取cookie值的时候要用 decodeURIComponent() 函数解码。
(3)更新cookie
要更新一个 Cookie,可以直接覆盖它。例如,若有一个名为 oldCookie 的Cookie,并想将它的值设为 newCookieValue,则可以:
document.cookie = 'oldCookie=newCookieValue';
这样子便可直接覆盖旧Cookie 的所有属性,包括它的到期时间和路径。但如果只是更新某个值,则分别指定新的值便可。
(4)删除cookie
要删除一个Cookie,可以通过设置它的过期时间来实现。
可以将过期时间设置为任何早于当前时间的日期,这样子就可以立即将 Cookie 删除。下面以为删除fryname2
对应的Cookie为例子:
document.cookie = 'fryname2=; expires=' + new Date(0).toUTCString();
将 expires
属性设置为 0(也可以设置为日期对象,但是要比当前时间早),表示该 Cookie 已经过期了。当然,除了设置 expires
属性,我们也可以通过设置max-age
属性为 0 来实现。注意,我们还有一个空值 fryname2=
,这是把 value 设置为空的方法。
此外,还可以进一步通过设置path
和domain
属性来选择删除Cookie,因为它们允许选择性地删除指定域名下的Cookie。
// 要删除的 cookie 名称
var cookieName = "ryCookie";
// 设置 cookie 过期时间为过去的时间,让浏览器自动删除该 cookie
document.cookie = cookieName + "=;expires=Mon, 01 May 2023 14:00:00 UTC;path=/;domain=example.com";
在上面的代码中,将 path
设置为 “/”,这将使得浏览器删除主域名下所有具有相同名称的Cookie。如果只想删除某个子目录下的Cookie,则需要将 path
设置为该子目录路径。同样的,需要注意将 domain
替换为特定的域名。
👩💻2.8.2 服务端对Cookie的设置
在Web中,服务端对Cookie的操作主要包括创建和读取。
(1)创建Cookie
当服务器向客户端发送HTTP响应时,在响应头中可以包含Set-Cookie字段来创建一个新的Cookie。下面是一个用 Node.js
代码创建一个名称为“ryCookie”
的Cookie,并将其值设为“hello world”
和持续时间为10秒钟的示例:
var http = require('http');
http.createServer(function(req, res) {
res.setHeader('status', '200 OK');
res.setHeader('Set-Cookie', 'ryCookie=hello%20world;Max-Age=10'); // 这里创建
res.write('Hello World');
res.end();
}).listen(8080);
console.log('running localhost:8080')
如果想设置多个cookie,在设置时可以将多个cookie存放在数组中,例如:
// 存储name为username,value为xiaobaiRy的cookie,过期时间为一小时后
const cookie1 = 'username=xiaobaiRy; Max-Age=3600';
// 存储name为user_id,value为123456的cookie
const cookie2 = 'user_id=123456';
res.setHeader('Set-Cookie', [cookie1, cookie2]);
(2)读取Cookie
当客户端向服务器发出HTTP请求时,其中可能包含它之前由该服务器设置的Cookies。在Node.js中,可以通过request对象的headers属性访问所有HTTP头信息,所以读取Cookies信息可以:
const cookies = request.headers.cookie;
3. 下篇章笔记
通过上面的知识,我们也对背景和Cookie有了一个大概的了解,所以在中篇中,笔者我将主要介绍一下Session的相关要点以及Session和Cookie的区别。
笔记链接:【前端知识】Cookie, Session,Token和JWT的发展及区别(中)
码字不易,可能当中存在某些字体错误(笔者我没有发现),如果有错误,欢迎大家指正。🤗