一、Cookie
在互联网早期,HTTP 协议是无状态
的,客户端每次访问,服务端和都不会保存任何会话信息。这可给网站带来了大麻烦,比如用户登录后浏览不同页面,网站无法识别这是同一个用户,购物车功能也难以实现。1994 年,网景公司的 Lou Montulli 为了解决用户网上购物的购物车历史记录问题,发明了 Cookie,从此开启了 Web 状态管理的新篇章。
当你访问一个网站,比如淘宝,服务器会在响应头中添加一个 Set - Cookie
字段,就像是给你递上一张小纸条,上面写着一些信息,比如你的用户 ID、会话标识符等。你的浏览器收到后,会把这张小纸条(Cookie)妥善保存在本地。之后,每次你再向淘宝服务器发起请求,浏览器都会自动把这张小纸条带上,服务器通过读取纸条上的信息,就能识别出你是谁,了解你的一些状态,比如是否已登录。
Cookie 是一段不超过 4KB 的小型文本数据,别看它小,五脏俱全。它由一个名称(Name)、一个值(Value)和其它几个用于控制 Cookie 有效期、安全性、使用范围的可选属性组成。
-
Name/Value:这是 Cookie 的核心,就像你的名字和你对应的身份信息。比如,Name 是 "user_id",Value 可能就是你的淘宝账号 ID。对于认证 Cookie,Value 值可能包括 Web 服务器所提供的访问令牌。
-
Expires 属性:它决定了 Cookie 的 "寿命"。有会话性 Cookie 和持久性 Cookie 之分。Expires 属性缺省时,Cookie 是会话性的,仅保存在客户端内存中,一旦你关闭浏览器,它就消失了;持久性 Cookie 则会保存在你的硬盘中,直到它的生存期到了,或者你主动在网页中单击 "注销" 等按钮结束会话时才失效。
-
Path 属性:它规定了 Web 站点上哪些目录可以访问该 Cookie。
-
Domain 属性:指定了可以访问该 Cookie 的 Web 站点或域。Cookie 机制有点像一个不太严格的保安,允许一个子域可以设置或获取其父域的 Cookie。在实现单点登录方案时,这个特性很有用,但也带来了安全风险,比如攻击者可能借此发动会话定置攻击。所以,浏览器也做了一些限制,禁止在 Domain 属性中设置.org、.com 等通用顶级域名、以及在国家及地区顶级域下注册的二级域名,降低被攻击的可能性。
-
Secure 属性:指定是否使用 HTTPS 安全协议发送 Cookie。使用 HTTPS 安全协议,能保护 Cookie 在浏览器和 Web 服务器间传输过程中不被窃取和篡改。不过,由于兼容性问题,有些网站使用自签署的证书,浏览器检测到 SSL 证书无效时,不会立刻终止连接请求,而是提示安全风险信息,一些缺乏安全意识的用户可能会继续访问,这就给了攻击者可乘之机。
-
HTTPOnly 属性:这是防止 Cookie 被跨站脚本攻击(XSS)窃取或篡改的一道防线。它用于防止客户端脚本通过
document.cookie
属性访问 Cookie。但它也不是万能的,一些浏览器可以阻止客户端脚本对 Cookie 的读操作,但允许写操作;大多数浏览器仍允许通过 XMLHTTP 对象读取 HTTP 响应中的Set - Cookie
头。
Cookie的认过程:
-
客户端首次向服务器发送请求时
-
服务器生成包含用户标识信息的 Cookie,通过响应头传递给客户端,客户端存储该 Cookie。
-
后续客户端向服务器发送请求时,请求头会自动携带此 Cookie
-
服务器通过解析 Cookie 中的信息完成用户身份识别与认证。
-
若 Cookie 过期或被删除,客户端需重新获取 Cookie 以完成认证。
Cookie 的应用非常广泛。在会话管理方面,它可以用于跟踪用户的状态,比如在购物车应用中,记录你添加到购物车的商品;在用户认证中,存储你的登录状态和凭据,让你在浏览网站不同页面时无需重复登录;还能存储用户的偏好设置,如你在网站上设置的语言、主题等,下次访问时直接呈现你喜欢的样式。
然而,Cookie 的安全性较低。攻击者可以通过木马等恶意程序,或使用跨站脚本攻击等手段偷窃存放在用户硬盘或内存中的 Cookie。比如在不安全的局域网中被动监听网络通信,或者发动 DNS Pharming(域欺骗)攻击,将你对合法网站的访问请求重定向到恶意网站,从而窃取 Cookie。对于捕获到的认证 Cookie,攻击者可能会猜测其中的访问令牌,试图获取敏感信息,或者直接重放该 Cookie,假冒你的身份进行各种操作。
Session
虽然 Cookie 解决了一些 HTTP 无状态的问题,但由于它存储在客户端,存在安全隐患,而且大小有限制。于是,Session 应运而生,它就像是服务器端为每个用户建立的一份详细 "客户档案"。
当客户端浏览器第一次访问服务器时,服务器会为这个客户端创建一个 Session 对象,就像为新顾客建立一个专属档案。这个 Session 对象里可以存储各种与该用户相关的信息,比如用户登录状态、购物车信息、在应用中的操作记录等。同时,服务器会生成一个唯一的 Session ID,这个 ID 就像是档案编号,服务器把这个 Session ID 通过 Cookie 发送给客户端。之后,客户端每次请求服务器时,都会带上这个包含 Session ID 的 Cookie,服务器通过读取这个 Session ID,就能从众多 "客户档案" 中找到对应的 Session 对象,获取用户的状态信息。
-
服务器端存储:与 Cookie 存储在客户端不同,Session 数据存储在服务器上,这大大提高了数据的安全性,因为客户端无法直接修改服务器上的 Session 数据。
-
大小限制:一般来说,Session 没有像 Cookie 那样严格的 4KB 大小限制,它的大小主要受服务器内存限制。这意味着可以在 Session 中存储更复杂、更多的数据。
-
持久性:Session 会在一定时间内保存,这个时间通常由服务器的配置决定,比如设置为 30 分钟无操作则过期。相比之下,Cookie 的持久性可以通过设置 Expires 属性灵活调整,既可以是会话级别的,也可以是长期保存的。
-
安全性:由于数据保存在服务器端,Session 比 Cookie 更安全。但如果 Session ID 被泄露,攻击者同样可以通过这个 ID 访问对应的 Session,造成 Session 劫持攻击,所以在使用 Session 时,也要注意保护 Session ID 的安全。
-
跨域限制:Session 不受同源策略限制,它通过 Session ID 来识别和关联请求。不过,在跨域场景下,要实现 Session 共享可能会比较复杂,需要一些额外的配置和技术手段。
session的认证过程

-
客户端首次请求服务器
-
服务器创建 Session 对象存储用户数据,并生成唯一的 Session ID,将 Session ID 通过 Cookie 发送至客户端。
-
客户端后续请求会携带该 Session ID,服务器依据 Session ID 查找对应的 Session 对象,以此完成用户认证。
-
当 Session 超时或被销毁,客户端需重新建立 Session 以进行认证。
在实际应用中,Session 和 Cookie 通常是配合得非常默契的一对搭档。比如,用户登录成功后,服务器创建 Session 并生成 Session ID,将这个 Session ID 通过 Cookie 发送给客户端。当客户端再次请求时,带着包含 Session ID 的 Cookie,服务器根据 Session ID 找到对应的 Session,确认用户身份和状态。即使关闭了浏览器,下次打开浏览器访问网站时,如果 Cookie 中的 Session ID 还未过期,仍然可以通过它恢复会话状态。但这种配合使用也需要注意安全性问题,要防止 Session 劫持等攻击。因此也可以说SessionID 是连接 Cookie 和 Session 的一道桥梁,大部分系统也是根据此原理来验证用户登录状态。
Cookie 和 Session 的不同
-
存储位置:Cookie 是存储在客户端的,就像你把重要信息揣在自己兜里;而 Session 是存储在服务器端的,相当于把信息交给了一个专门的管理员保管。
-
安全性:由于 Cookie 在客户端,容易被篡改和窃取,安全性相对较低;Session 在服务器端,客户端无法直接接触到数据,安全性更高,但 Session ID 通过 Cookie 传递时,Session ID 的安全也需要保障。
-
数据大小:Cookie 有严格的大小限制,一般不超过 4KB;Session 的数据大小主要受服务器内存限制,能存储更多更复杂的数据。
-
生命周期:Cookie 可以通过设置 Expires 属性来控制生命周期,既可以是会话级别的,也可以长期存在;Session 的生命周期通常由服务器设置,一般在用户一段时间不操作后自动失效。
-
服务器压力:Cookie 存储在客户端,不会增加服务器的存储压力;Session 存储在服务器,大量的 Session 会消耗服务器的内存资源,对服务器压力较大。
-
跨域支持:Cookie 在跨域时会受到诸多限制,不同域名之间共享 Cookie 比较困难;Session 本身是基于 Session ID 的,只要 Session ID 能传递过去,理论上可以跨域,但实际中由于 Cookie 的跨域限制,Session ID 的传递也会受到影响。
三、JWT
随着互联网的发展,特别是移动应用和分布式系统的兴起,传统的 Session 认证方式面临一些挑战。Session 认证需要在服务器端存储大量的会话状态信息,这对于分布式系统来说,服务器之间共享 Session 数据变得复杂,而且在移动端,Cookie 可能不太适用。于是,JWT(JSON Web Token)这种基于 Token 的认证方式逐渐流行起来。

-
用户在前端通过 Web 表单输入用户名和密码,然后以 POST 请求的方式发送到后端接口。
-
后端服务器收到请求后,核对用户名和密码。如果验证成功,服务器会将包含用户信息的数据作为 JWT 的 Payload(负载),再将 JWT Header(头部)和 Payload 分别进行 Base64 编码,然后使用一个密钥(Secret Key)对它们进行签名,最终形成一个 JWT Token,这个 Token 就像是一个加密的通行证,是一个类似 "lll.zzz.xxx" 的字符串。
-
服务器将生成的 JWT Token 返回给前端客户端。客户端可以把这个 Token 存储起来,比如放到本地存储或者 Cookie 中。
-
之后,客户端每次向服务器请求资源时,都需要在请求头(Header)或者 Cookie 中携带这个 JWT Token。服务器收到请求后,会验证这个 JWT Token 的签名是否有效,以及 Token 是否过期等。如果验证成功,就会根据 Token 中的用户信息,向客户端返回请求的数据。
JWT 由三部分组成:Header(头部)、Payload(负载)和 Signature(签名),它们之间用点号 "." 分隔。
-
Header(头部) :通常包含两部分信息,一是令牌的类型,一般就是 JWT;二是所使用的签名算法,比如 HMAC SHA256 或 RSA 等。这部分内容经过 Base64 编码后,成为 JWT 的第一部分。
-
Payload(负载) :这里面包含了声明(claims),也就是你想要传递的信息,比如用户 ID、用户名、用户角色、过期时间等。需要注意的是,Payload 中的信息虽然是经过编码的,但并不是完全加密的,任何人都可以解码查看,所以不要在里面存放过于敏感的信息,比如用户密码。这部分内容经过 Base64 编码后,成为 JWT 的第二部分。
-
Signature(签名) :为了生成签名部分,需要使用编码后的 Header、编码后的 Payload、一个密钥(Secret Key)以及 Header 中指定的签名算法。签名的作用是保证 JWT 在传输过程中没有被篡改。如果有人试图修改 JWT 中的内容,那么签名验证就会失败。
与传统的 Session 认证方式相比,JWT 有很多优势。
-
跨语言、跨平台:因为 JWT Token 是以 JSON 加密形式保存在客户端的,所以它是跨语言的,原则上任何 Web 形式都支持,无论是在 PC 端的浏览器,还是在移动端的应用,都能很好地使用 JWT 进行认证。
-
无状态:JWT 机制在服务端不需要存储 Session 信息,因为 JWT 自身包含了所有登录用户的信息,这大大减轻了服务端的压力,特别适合分布式系统和微服务架构。
-
支持跨域访问:Cookie 存在跨域限制,而 JWT 由于通常放在请求头中,不需要依赖 Cookie,所以跨域后不会存在信息丢失问题,方便在不同域名的服务之间进行身份验证。
-
更适用 CDN:可以通过内容分发网络请求服务端的所有资料,因为 JWT 包含了足够的用户信息,CDN 可以直接根据 JWT 来提供相应的资源。
-
无需考虑 CSRF(跨站请求伪造) :由于不再依赖 Cookie,采用 JWT 认证方式不会发生 CSRF 攻击,也就无需专门考虑 CSRF 的防御措施。
不过,JWT 也不是绝对安全的。虽然 JWT 的哈希签名密钥存放在服务端,理论上只要服务器不被攻破,JWT 是安全的,但实际上仍然存在一些风险。比如,JWT 是在请求头中传递的,如果网络被劫持,攻击者有可能获取到 JWT。为了应对这种情况,推荐使用 HTTPS 来传输数据,增加安全性。另外,JWT 可以使用暴力穷举来破解,所以为了提高安全性,可以定期更换服务端的哈希签名密钥,就像定期更换门锁密码一样。
Session 和 Token(以 JWT 为例)的区别
-
存储位置:Session 数据存储在服务器端,服务器需要维护这些会话数据;而 JWT 是存储在客户端的,服务器不需要存储相关数据,这也是 JWT 无状态的体现。
-
认证流程:Session 认证中,客户端携带 Session ID,服务器通过 Session ID 找到对应的 Session 数据来完成认证;JWT 认证中,客户端携带 JWT,服务器对 JWT 进行验证签名等操作,无需查询服务器存储的信息就能完成认证。
-
扩展性:在分布式系统中,Session 需要解决不同服务器之间的 Session 共享问题,通常需要借助缓存中间件等;而 JWT 由于服务器无需存储状态,不同服务器之间可以直接使用 JWT 进行认证,扩展性更好。
-
过期处理:Session 可以在服务器端直接销毁,让用户立即下线;JWT 一旦生成,在有效期内是无法在服务器端直接废除的,除非更改密钥或者在服务器端维护一个黑名单,但这会增加复杂度。
-
数据包含:Session 中存储的数据只在服务器端可见;JWT 的 Payload 部分包含了一些用户信息,虽然经过编码,但可以被解码查看,所以不能存放敏感信息。
-
适用场景:Session 适合单体应用,对安全性要求较高且需要服务器能主动控制会话的场景;JWT 适合分布式系统、移动应用等场景,能减少服务器的存储压力和提高系统的扩展性。
作为前端开发者,理解它们的底层逻辑并非为了非此即彼的选择,而是要根据具体场景灵活搭配。比如用 Cookie 存储 Session ID 实现基础会话,用 JWT 处理跨域 API 调用,再结合 HTTPS 和令牌刷新策略加固安全防线。