Featured image of post session_token 和 Cookie:你以为你登录了,其实你只是拿着一张票

session_token 和 Cookie:你以为你登录了,其实你只是拿着一张票

session_token 和 Cookie:你以为你登录了,其实你只是拿着一张票

很多刚接触 Web 开发或者好奇上网原理的朋友,经常把 Cookie 和 Session 混为一谈。其实在技术底层,它们分工明确:Cookie 是搬运工,Session Token 是身份证。

如果把你访问网站比作去一家高级私人会所,这个过程大概是这样的:

1. Cookie:会所发给你的“临时胸卡”

当你第一次访问一个网站(会所)时,服务器根本不知道你是谁。HTTP 协议是“无状态”的,这意味着服务器像个患了严重失忆症的接待员,你每点一个页面,他都会问你:“你是谁?请重新出示证件。”

为了不用每次点击都输入账号密码,服务器在验证你的身份后,会发给你一个 Cookie

Cookie 就像是一张胸卡。它被保存在你的浏览器(本地)里。下次你请求页面时,浏览器会自动把这张胸卡贴在请求头(Request Header)里发给服务器。服务器一看:“哦,胸卡号 123,是那个叫 Bosh 的老板,让他进去。”

Cookie 的特点:

  • 存在本地:由浏览器管理。
  • 自动发送:只要域名匹配,浏览器每次请求都会自动带上。
  • 容量极小:通常只有 4KB 左右,塞不下太多东西。

2. session_token:会所后台的“会员档案号”

但问题来了:如果把所有用户信息(权限、购物车、个人偏好)都写在 Cookie 这张胸卡上怎么办?

首先,胸卡太小,塞不下。其次,极度不安全。如果你的胸卡上写着 role=admin,任何懂一点 F12 的人都可以把自己的胸卡改成 admin,直接黑进你的后台。

于是,服务器引入了 Session (会话) 机制。

服务器不再把敏感信息发给你,而是在自己的内存或数据库(比如 Redis)里开辟一块空间,记录你的所有信息,并给这块空间起个唯一的 ID,这就是 session_token(或 session ID)。

现在,服务器发给你的 Cookie 里只包含一个东西:session_id=abc123xyz

这个 token 就像是一张“存包票”或者“档案索引号”。它本身不包含任何个人信息,它只是一个指向服务器后台档案的“指针”。

完整流程是这样的:

  1. 你输入账号密码 $\rightarrow$ 发给服务器。
  2. 服务器验证通过 $\rightarrow$ 在后台创建 Session $\rightarrow$ 生成 session_token $\rightarrow$ 把 token 放入 Cookie 发回浏览器。
  3. 浏览器存储 Cookie $\rightarrow$ 之后每次请求都带上这个 token。
  4. 服务器收到 token $\rightarrow$ 去后台查这个 ID 对应哪个用户 $\rightarrow$ 返回对应的内容。

3. 为什么得区分开?(架构设计的权衡)

你可能会问:为什么不直接用 Token,非要套一层 Cookie?

因为 Cookie 提供了自动化。如果不用 Cookie,你得在 JavaScript 里手动地把 token 塞进每一个 API 请求的 Header 里(比如 Authorization: Bearer ***)。Cookie 是浏览器的原生行为,只要设置好,你不需要写一行代码,浏览器就会帮你处理。

但这种便捷带来了巨大的安全漏洞。

4. 这里的坑:安全漏洞与黑客手段

既然 Cookie 会自动发送,那么黑客就开始想办法偷这张“胸卡”。

XSS (跨站脚本攻击)

黑客通过在网页里植入一段 JS 代码,直接调用 document.cookie。如果你的 session_token 就在这里,黑客直接把它发到自己的服务器上。结果:黑客现在拥有了你的 session_token,他不需要密码,直接就能以你的身份登录。这就是“会话劫持”。

对策: 给 Cookie 加上 HttpOnly 标志。这样 JS 代码就没法读取这个 Cookie,只能由浏览器在请求时发送。

CSRF (跨站请求伪造)

这是 Cookie “自动发送”特性的反噬。 假设你登录了银行网站 $\text{Bank.com}$,Cookie 里存着你的 token。此时你访问了一个钓鱼网站 $\text{Evil.com}$,页面上有一个隐藏的按钮或脚本,向 $\text{Bank.com}$ 发起了一个 transfer_money 请求。 由于浏览器看到请求目标是 $\text{Bank.com}$,它会自动把你的银行 Cookie 带上。银行服务器一看:“token 正确,是老板本人发起的请求”,于是钱就被转走了。

对策: 使用 SameSite 属性(限制跨站发送)或在请求中加入随机的 CSRF Token。

5. 现代演进:JWT 与无状态架构

随着前后端分离和微服务流行,传统的 Session 机制遇到了瓶颈:服务器压力太大

如果你的网站有 100 万个在线用户,服务器得在内存里存 100 万个 Session。如果是有多个服务器节点(集群),你还得搞一个统一的 Redis 集群来共享 Session,否则用户在 A 服务器登录,跳转到 B 服务器就失效了。

于是 JWT (JSON Web Token) 出现了。

JWT 的核心理念是:把身份证信息加密后直接发给用户,服务器不再存档案。

JWT 就像是一张带防伪水印的电子通行证。它包含:

  • Header: 算法信息。
  • Payload: 用户 ID、过期时间等(明文,但被签名了)。
  • Signature: 服务器用私钥生成的签名。

服务器收到 JWT 后,不需要查数据库,只需要用私钥验签。如果签名正确,就说明这张票是真的。

JWT vs Session:

  • Session:服务器记得你是谁(有状态),安全但费资源。
  • JWT:凭票入场,服务器不记得你是谁,只认票(无状态),省资源但撤销困难(一旦发出去,除非到期,否则很难强制让某个 token 失效)。

6. 小H的总结

简单来说:

  • Cookie 是浏览器和服务器之间传输数据的通道
  • session_token 是存储在通道里的密钥,用来在服务器端检索你的状态。

作为开发者,不要迷信某种方案。如果你做的是传统的单体 Web 应用,HttpOnly Cookie + Redis Session 是最稳妥的;如果你做的是大规模分布式 API 或移动端 App,JWTOAuth2 才是正解。

最重要的一点:永远不要在 Cookie 或 Token 里存明文密码,除非你想在第二天看到自己的域名出现在黑客的公开列表里。


本文由 BOSH 的博客助手 HerMes 整理 📝

原文链接:用户提供科普需求

热爱生活 学无止境
使用 Hugo 构建
主题 StackJimmy 设计