Cookie 机制详解
一句话概括
Cookie 不是存数据的,是 HTTP 无状态协议的身份补丁——每次请求自动带上,靠 HttpOnly + Secure + SameSite 三道防线保住安全的底线。
核心知识点
1. Cookie 的写入与读取
1
2
3
4
5
6
7
8
9
10
11
12
13
14
// —— 服务端设置(推荐方式)——
// Set-Cookie: sessionId=abc123; HttpOnly; Secure; SameSite=Lax; Max-Age=3600; Path=/
// —— 前端读写(只能操作非 HttpOnly 的)——
document.cookie = 'theme=dark; Max-Age=2592000; Path=/; Secure';
console.log(document.cookie); // "theme=dark; lang=zh" ← 注意:返回字符串,不是对象
// 删除:设为过去时间
document.cookie = 'theme=; Max-Age=0; Path=/';
// 面试题:如何解析 document.cookie 为对象?
const parseCookie = str =>
Object.fromEntries(str.split('; ').map(pair => pair.split('=')));
// { theme: 'dark', lang: 'zh' }
2. HttpOnly — 防御 XSS 窃取 Cookie
1
2
3
4
5
6
7
8
// 加 HttpOnly 的 Cookie,前端通过 document.cookie 拿不到
// Set-Cookie: sessionId=abc; HttpOnly; Secure
// 即使攻击者注入 <script>,也读不到 sessionId
console.log(document.cookie); // 不包含 sessionId
// 但正常请求照样带上:
// GET /api/user → Cookie: sessionId=abc
铁律: 凡是在服务端才用到的 Cookie(session id、csrf token),一律加 HttpOnly。前端需要读的才放 JS 可见区。
3. SameSite — Chrome 80+ 最大行为变化
1
2
3
4
5
6
7
8
9
10
11
12
// Strict: 严格,任何跨站都不带
// 场景:从邮件点链接进银行 → 需要重新登录
Set-Cookie: id=xxx; SameSite=Strict
// Lax: Chrome 默认(80+),允许安全的跨站导航带 Cookie
// ✅ <a> 点击跳转 → 带
// ✅ 顶层 GET 表单提交 → 带
// ❌ <img> / iframe / AJAX 跨站请求 → 不带
Set-Cookie: id=xxx; SameSite=Lax
// None: 完全放开,必须搭配 Secure(即 HTTPS)
Set-Cookie: tracking=xxx; SameSite=None; Secure
面试重点: Chrome 80 将默认值从 None 改为 Lax,很多第三方登录、iframe 内嵌应用突然失效,就是没设 SameSite=None; Secure。
4. Domain 与 Path — 控制可见边界
1
2
3
4
5
6
7
8
9
10
11
// 不设 Domain → 仅当前域名(不含子域名)
// 设在 www.example.com,api.example.com 看不到
Set-Cookie: token=xxx; Path=/admin
// 设 Domain=.example.com → 所有子域名共享
// api.example.com、admin.example.com 都能读到
Set-Cookie: lang=zh; Domain=.example.com
// Path 限定 URL 路径前缀
Set-Cookie: adminToken=xxx; Path=/admin
// 只有 /admin 及子路径生效
5. Cookie vs Storage 选型决策
| Cookie | localStorage | |
|---|---|---|
| 会自动发请求 | ✅ | ❌ |
| HttpOnly 防 XSS | ✅ | ❌ |
| SameSite 防 CSRF | ✅ | ❌ |
| 容量 | 4KB | 5-10MB |
| 性能 | 带了太多会拖慢每个请求 | 不影响网络 |
| 过期控制 | ✅ 原生 | ❌ 需手动封装 |
其实你每天都在用
- 登录态维持:
sessionId放 HttpOnly Cookie,每次请求自动带,服务器就知道你是谁 - 勾选”两周内免登录”:后端设
Max-Age=1209600,两周内自动登录 - 第三方广告追踪:A 网站嵌入的 B 站 iframe 用
SameSite=None的 Cookie 追踪你的浏览行为 - 多语言偏好:
lang=zh-CN存 Cookie,后端直接渲染对应语言的页面,无需前端二次切换 - CSRF 防御:后端下发的 csrf token 存 Cookie(不设 HttpOnly),前端读取后放进请求头
常见误解
❌ 误区:「Cookie 就 4KB,太废物了」 Cookie 的定位从来不是 Storage 而是 Transport——它的核心价值是”每次请求自动带”。把大数据放在 Cookie 里的人不是 Cookie 的问题,是不会用 localStorage。
❌ 误区:「设了 HttpOnly 就安全了」 HttpOnly 只防 XSS 窃取,管不了中间人攻击(需要
Secure),也管不了 CSRF(需要SameSite或 CSRF Token)。三道防线是 AND 关系,不是 OR。❌ 误区:「SameSite=Lax 替代了 CSRF Token」 Lax 解决了跨站 POST/PUT/DELETE 的 CSRF,但 GET 请求的 CSRF 仍可能有问题——比如某些老接口用 GET 做删除操作。CSRF Token 依然是纵深防御的必要组件。
❌ 误区:「前端设 Cookie 和后端设一样」 不一样。
document.cookie无法设置HttpOnly,这意味着前端写入的任何 Cookie 都能被 JS 读取。真正需要保密的(session id)必须由后端Set-Cookie响应头下发。
一句话总结
Cookie 三板斧:HttpOnly 让脚本看不见,Secure 让中间人截不到,SameSite=Lax 让跨站请求带不走——三者缺一不可。