HTTP 完全指南(三):Cookie、Session 与 Token 深度详解

引言

上一篇我们讲了 HTTP 缓存。今天要解决的是 HTTP 最著名的缺陷:无状态

什么叫无状态?服务器每次收到请求,都把它当成一个全新的请求,完全不记得刚才这个客户端来过没有、做过什么。你登录了淘宝,刷新一下页面,服务器问:"你是谁?请重新登录"------这就是无状态带来的问题。

为了让 HTTP "记住"用户,诞生了三套方案:CookieSessionToken。它们各自有不同的工作原理和适用场景,本文将逐一深挖。

第一部分:Cookie

一、Cookie 是什么

Cookie 是服务器让浏览器保存在本地的一小段数据 (通常不超过 4KB)。浏览器每次请求该服务器时,会自动带上所有 Cookie

二、Cookie 的属性

复制代码
Set-Cookie: session_id=abc123; Domain=.example.com; Path=/; Max-Age=3600; HttpOnly; Secure; SameSite=Lax
属性 含义 示例
Name=Value Cookie 的名字和值 session_id=abc123
Domain 允许访问的域名范围 .example.com(所有子域名都能访问)
Path 允许访问的路径范围 /(整个网站);/admin(只管理后台)
Max-Age 存活秒数(相对时间) 3600(1小时后过期)
Expires 过期时间(绝对时间) Mon, 02 Jun 2025 10:00:00 GMT
HttpOnly 禁止 JavaScript 访问 只通过 HTTP 传输,document.cookie 读不到
Secure 只在 HTTPS 连接中传输 HTTP 明文不传输此 Cookie
SameSite 跨站请求控制 Strict / Lax / None

三、HttpOnly 和 Secure 为什么重要

四、SameSite 详解

第二部分:Session

一、Session 是什么

Session 是存储在服务器端 的用户数据。浏览器只保存一个 session_id(通常存在 Cookie 中),服务器根据这个 ID 找到对应的 Session 数据。

二、Session 的存储位置

方式 优点 缺点
内存 最快 重启丢失,不能多服务器共享
文件 重启不丢 慢,不能多服务器共享
Redis 快 + 持久 + 多服务器共享 需要额外部署
数据库 持久可靠 最慢

三、Cookie vs Session

对比 Cookie Session
存储位置 浏览器端 服务器端
安全性 较低(客户端可见) 较高(服务器控制)
容量 约 4KB 无限制
网络开销 每次请求自动带上 只有一个 session_id
服务器压力 需要存储和管理
适用场景 记住用户偏好、主题 登录状态、敏感数据

第三部分:Token(JWT)

一、Token 是什么

Token 是一段自包含的加密字符串 ,服务器签发后交给客户端,客户端每次请求手动携带这个 Token。

最流行的 Token 实现是 JWT(JSON Web Token)。

二、JWT 的结构

JWT 由三部分组成,用 . 分隔:

三、JWT 的验证过程

四、Token vs Session

对比 Session JWT Token
存储位置 服务器端 客户端
服务器状态 有状态(需要存 Session) 无状态(Token 自包含)
扩展性 多服务器需要共享 Session(Redis) 天然支持分布式
注销 删除服务器 Session 即可 需要额外机制(黑名单)
安全性 Session ID 泄露可冒充 Token 泄露也可冒充
数据量 Cookie 只传 ID,很小 Token 较大(每次都要传)

第四部分:JWT 实战

一、服务端签发 JWT(C 语言伪代码)

cpp 复制代码
// JWT 结构(简化)
typedef struct {
    char header[128];      // Base64 编码的 Header
    char payload[512];     // Base64 编码的 Payload
    char signature[256];   // 签名
} JWT;

// 签发 JWT
char* createToken(int userId, const char* username, const char* secret) {
    // 1. 构造 Header
    const char* header = "{\"alg\":\"HS256\",\"typ\":\"JWT\"}";
    char* header_b64 = base64_encode(header);
    
    // 2. 构造 Payload
    char payload[512];
    time_t now = time(NULL);
    sprintf(payload, "{\"userId\":%d,\"username\":\"%s\",\"iat\":%ld,\"exp\":%ld}",
            userId, username, now, now + 3600);  // 1 小时过期
    char* payload_b64 = base64_encode(payload);
    
    // 3. 计算签名
    char to_sign[1024];
    sprintf(to_sign, "%s.%s", header_b64, payload_b64);
    char* signature = hmac_sha256(to_sign, secret);
    char* signature_b64 = base64_encode(signature);
    
    // 4. 拼接完整 Token
    char* token = malloc(2048);
    sprintf(token, "%s.%s.%s", header_b64, payload_b64, signature_b64);
    
    return token;
}

二、前端使用 JWT

javascript 复制代码
// 登录成功后存储 Token
fetch('/api/login', {
    method: 'POST',
    body: JSON.stringify({ username: 'zhangsan', password: '123' })
})
.then(res => res.json())
.then(data => {
    localStorage.setItem('token', data.token);  // 存到本地
});

// 后续请求带上 Token
fetch('/api/profile', {
    headers: {
        'Authorization': 'Bearer ' + localStorage.getItem('token')
    }
});

三、Access Token + Refresh Token

第五部分:三种方案对比与选择

对比 Cookie Session JWT Token
谁保存 浏览器 服务器 浏览器
谁验证 服务器 服务器 服务器(密钥验证)
自动携带 ✅ 浏览器自动 ✅ Cookie 带 ID ❌ 代码手动加
跨域 受限(Domain) 受限 天然支持
移动端 不方便 不方便 友好
分布式 不方便 需要 Redis 天然支持
注销 删 Cookie 删 Session 需要额外处理
防 CSRF 需 SameSite 需 SameSite 不受 CSRF 影响

选择建议

场景 推荐
传统 Web 网站(前后端不分离) Session + Cookie
RESTful API JWT Token
移动 App JWT Token
微服务/分布式系统 JWT Token
需要立即注销 Session(或 Token + 黑名单)

第六部分:常见攻击与防范

第七部分:面试题

1. Q:Cookie、Session、Token 的区别?

A:Cookie 存储在浏览器端,浏览器自动携带;Session 存储在服务器端,Cookie 只存 session_id;Token 也存储在浏览器端,但代码手动携带。Session 适合传统 Web,Token 适合 API 和分布式系统。

2. Q:JWT 的 Payload 是加密的吗?

A:不是! 只是 Base64 编码,任何人都能解码。不要放密码等敏感信息。JWT 的防篡改靠的是 Signature 签名。

3. Q:Token 过期了怎么办?

A:用 Refresh Token 换取新的 Access Token。两个 Token 都过期才需要重新登录。

4. Q:Cookie 的 HttpOnly 和 Secure 有什么作用?

A:HttpOnly 禁止 JavaScript 读取 Cookie(防 XSS 窃取);Secure 要求 Cookie 只在 HTTPS 中传输(防中间人窃取)。

5. Q:CSRF 攻击是什么?怎么防?

A:攻击者诱导用户点击链接,利用用户已登录的身份发起恶意请求。防御方式:SameSite Cookie、CSRF Token、验证 Referer。JWT 方案天然不受 CSRF 影响(Token 不是浏览器自动携带的)。


总结

一、三种方案对比

方案 核心原理 最适合
Cookie 浏览器自动存储和携带的小数据 记住偏好、跟踪
Session 服务器存储状态,Cookie 只传 ID 传统 Web 登录
JWT Token 自包含加密令牌,客户端主动携带 API、移动端、分布式

二、一句话记忆

Cookie 存浏览器、自动带,Session 存服务器、Cookie 只带 ID,Token 自包含、手动带。Session 适合传统网站,Token 适合 API 和分布式。JWT 的 Payload 只编码不加密,防篡改靠签名。

相关推荐
Irissgwe1 小时前
9、数据链路层
linux·网络·mac·ip·数据链路层·arp协议·以太网帧格式
2501_946786201 小时前
2026漏洞扫描服务:企业防护痛点解决指南
网络·安全·web安全
洛水水2 小时前
图床项目实现:MD5秒传 + 个人文件列表 + 图片分享等功能的完善
服务器·网络
Irissgwe2 小时前
8-1\IP 分片和组装的具体过程
linux·网络·tcp/ip·网络层·分片·组装
闪电悠米2 小时前
黑马点评-秒杀优化-04_lua_and_db_fallback
服务器·开发语言·网络·数据库·缓存·junit·lua
Yang96113 小时前
风场光伏光缆分缆测损,DM-40A 光通信综合测试仪高效运维
网络·能源
努力搬砖的咸鱼3 小时前
容器编排底层原理:Kubernetes 网络模型与 CNI 插件
网络·微服务·云原生·容器·架构·kubernetes
ylscode3 小时前
Chrome桌面安全更新修复数百个漏洞
网络·windows·安全·安全威胁分析
.小小陈.3 小时前
从零构建可用 TCP 服务:从基础 Socket 到自定义协议与序列化
服务器·网络·tcp/ip