
这张图把 HTTP Cookie 讲成了三件事:HTTP 为什么"无状态" 、Cookie 如何给 HTTP "加状态" 、以及 Cookie 的隔离规则和关键属性。我按图的四块区域逐一拆开说明。
1) 左上:为什么说 HTTP 是 Stateless(无状态)
HTTP 协议层面把每次请求都当成"独立事件":
-
浏览器先发
GET /foo -
过一会又发
GET /bar
对服务器来说,这两次请求之间没有"天然绑定关系" 。如果请求里不带任何"身份/上下文",服务器就只能每次都问一句:"你是谁?"
所以图里才写:同一个浏览器来的两个请求,默认也"不相关"。
无状态的好处:协议简单、服务器更容易横向扩展(不必强依赖某台机器的内存状态)。
但坏处:登录态、购物车、偏好设置等"连续交互"需要额外机制维持。
2) 右上:Cookie 如何给 HTTP "加状态"(核心流程)
图右上画的是典型的"首次识别 + 后续自动携带"的闭环:
-
浏览器首次自报身份/触发登录(示意:"Hello, I am user ABC")
-
服务器生成一个 Cookie (通常是一个随机的 session id,比如
sid=...,或某些轻量信息) -
服务器在响应头里发回:
Set-Cookie: ... -
浏览器把 Cookie 存入本地(cookie jar)
-
之后浏览器再请求同站点资源时,会自动在请求头里带上:
Cookie: ... -
服务器收到后 校验 Cookie(比如查 session 表、验证签名、检查过期时间)
-
于是服务器就能说:"我知道你是谁了"
对应到真实 HTTP 头部,大概长这样:
HTTP/1.1 200 OK Set-Cookie: sid=RANDOM_TOKEN; Path=/; HttpOnly; Secure; SameSite=Lax
后续请求:
GET /bar HTTP/1.1 Host: example.com Cookie: sid=RANDOM_TOKEN
关键点:Cookie 最大的"威力"不是它能存多少数据,而是"浏览器会自动携带",从而把"状态"粘到每一次请求上。
3) 左下:Cookie Isolation(隔离)是怎么回事
图左下强调:浏览器不会把所有 Cookie 一股脑发给所有服务器------它按规则隔离:
-
按 Domain 隔离 :
foo.com的 Cookie 不会发给bar.com -
按 Path 进一步收敛 :只在匹配路径前缀时才发送(例如只对
/api生效) -
按 Secure 限制协议 :标了
Secure的 Cookie 只会在 HTTPS 请求里发送
所以你会看到图里不同域(Foo/Bar/Qux/Baz)各自有自己的 cookie 集合,互不乱串------这就是"Cookie 罐子"的隔离逻辑。
4) 右下:Cookie Attributes(属性)逐个解释(图里列了 5 个)
图里的属性都非常关键,我按"解决什么问题"来讲:
✅ Secure
-
含义:Cookie 只能通过 HTTPS 发送(HTTP 明文请求不会带它)
-
目的:防止在明文链路上被抓包窃取会话(session hijacking)
✅ HttpOnly
-
含义:Cookie 不能被 JS 读取 (
document.cookie拿不到) -
目的:主要对抗 XSS 窃取会话(即使页面被注入脚本,也更难直接偷走 session cookie)
✅ SameSite
-
含义:控制 Cookie 在"跨站请求"时是否携带
-
目的:主要对抗 CSRF
-
常见值(简化理解):
-
Strict:最严格,跨站一律不带 -
Lax:折中,很多"顶级导航 GET"允许带(现代浏览器默认趋向 Lax) -
None:允许跨站携带(通常要求同时Secure,否则浏览器可能拒收)
-
这就是图里写的:"控制 cookie 能否随 cross-site 请求发送"。
✅ Domain
-
含义:指定哪些域/子域可以接收此 Cookie
-
例:
Domain=example.com往往意味着a.example.com、b.example.com也能带 -
目的:用于"同一主域下多子系统共享登录态"(但也会扩大攻击面,要谨慎)
✅ Priority
-
含义:当浏览器存储空间/携带空间紧张时,给 Cookie 排优先级(高优先级更不容易被清理)
-
目的:让"关键 Cookie(如会话)"更稳定,不被随意淘汰(不同浏览器实现细节可能略有差异)
图里没画但实际非常常用的还有:
Expires/Max-Age(生命周期)、Path(路径范围)。
5) "Cookies And Sessions":两者到底什么关系?
很多人会把它们当一回事,但更准确的说法是:
-
Cookie 是浏览器端的"携带机制/存储容器"(小纸条)
-
Session 是服务器端的"状态数据"(档案/登录态/购物车等)
最经典的组合是:
Cookie 里只放一个 session id(随机、不可猜),真正的用户状态放在服务器(内存/Redis/数据库) 。
这样既能"有状态",又避免把敏感信息直接塞进 Cookie。详情请阅读:
6) 实战安全建议(非常实用)
如果你在做登录态/鉴权,通常建议:
-
会话 Cookie:
Secure + HttpOnly + SameSite=Lax(或 Strict) -
不要把密码/敏感信息直接放 Cookie(Cookie 会随着请求自动发送,泄露成本低)
-
防 CSRF: SameSite 之外,关键写操作再配合 CSRF Token / 双重提交等
-
防会话劫持: 全站 HTTPS、短有效期、登录后换 session id、异常设备/IP 风险控制
下面我继续把 Cookie 讲到"工程落地层面":有哪些类型、怎么设计会话、怎么和安全机制配合、以及常见坑。
7) Cookie 的两大类型:Session Cookie vs Persistent Cookie
A. Session Cookie(会话 Cookie)
-
没设置
Expires/Max-Age -
浏览器一般在"关闭浏览器/标签策略触发"时清掉(不同浏览器略有差异)
-
适合:纯登录态、短期状态
B. Persistent Cookie(持久 Cookie)
-
设置
Max-Age=...或Expires=... -
适合:记住登录(Remember me)、偏好设置(语言、主题)
实践:真正"记住登录"最好不要把同一个 session 拉很长,而是用 Refresh Token/长期凭证 + 短会话 的方案(下面讲)。
8) Cookie 里到底放什么:三种主流模式
模式 1:只放 Session ID(最推荐)
Cookie 里:sid=random_128bit
-
服务器:
sid -> user_id, roles, expiry, csrf_key ...存在 Redis/DB -
优点:敏感信息不落客户端;可以随时失效;风控好做
-
缺点:服务端要存状态(但这通常是可接受的)
模式 2:Cookie 里放"签名的状态"(类似 JWT,但别混淆)
Cookie 里:state=base64(payload).base64(sig)
-
服务器不存或少存,靠签名校验
-
优点:水平扩展简单
-
缺点:吊销难(除非加黑名单);payload 泄露风险;尺寸变大
模式 3:混合:短会话 + 刷新凭证
-
sid(短期,10~30 分钟滚动续期) -
refresh(长期,7~30 天,仅用于换新 sid;更严格校验设备指纹等) -
优点:安全与体验平衡最好
-
缺点:实现稍复杂
9) 登录态(Session)怎么设计才靠谱(推荐模板)
给一个你几乎可以直接照抄的策略:
登录成功返回
Set-Cookie: sid=...; Path=/; HttpOnly; Secure; SameSite=Lax Set-Cookie: csrf=...; Path=/; Secure; SameSite=Lax
解释
-
sid:HttpOnly(JS 拿不到,防 XSS 偷会话) -
csrf:不设 HttpOnly(前端需要读出来放到请求头里,配合 CSRF 防护) -
两者都
Secure+SameSite=Lax -
写操作(POST/PUT/DELETE)要求带:
X-CSRF-Token: <csrf cookie value>或基于表单的 token
这套是经典的"双 Cookie + header"CSRF 防护套路,兼容性和安全性都不错。
10) SameSite 细讲:什么时候必须用 None?
你遇到下面情况,大概率要 SameSite=None; Secure:
-
你的网站需要在 第三方站点的 iframe 里保持登录态
-
你做 跨站单点登录,登录态要在不同站点间自动带 cookie(很多时候也不行,现代浏览器限制很严)
-
你确实需要第三方 Cookie(广告、统计那类)
但注意:SameSite=None 会显著增加 CSRF 风险,必须配合 CSRF Token、Referer/Origin 校验等。
11) Cookie 隔离与"跨子域共享"的取舍(Domain)
默认更安全
不写 Domain:Cookie 只会发给"设置它的那个精确主机名"。
需要共享登录时
如果你有:
-
api.example.com -
www.example.com -
admin.example.com
你可能设:
Domain=example.com
风险: 任意子域如果被接管/有 XSS/可设置 Cookie,可能影响主域安全策略(比如 cookie 覆盖、会话固定等)。
所以:能不共享就不共享;真要共享,子域治理要非常严。
12) 常见坑合集(踩过一次就懂)
坑 1:把敏感信息直接存 Cookie
比如 user=admin、role=superuser ------ 被改了就完蛋。
即使你"以为"浏览器不会让用户改,用户也能用代理/插件/脚本改。
✅ 解决:敏感信息放服务端(Session),或签名/加密并严格校验。
坑 2:漏了 Secure
上了 HTTPS 还漏 Secure,Cookie 可能在误配置/降级场景走明文。
坑 3:CSRF 只靠"用户不点链接"
CSRF 是"用户不知情的跨站请求",必须用 SameSite + Token/Origin 校验。
坑 4:XSS 以为 HttpOnly 就完事
HttpOnly 只能防"偷 cookie",但 XSS 仍能直接发起带 cookie 的请求做坏事。
✅ 解决:CSP、输出编码、依赖治理、敏感操作二次验证等。
坑 5:Cookie 太大/太多
每次请求都会带 cookie,影响性能,还可能触发浏览器/网关限制(例如头部过大 431)。
✅ 解决:Cookie 只放"标识符",别放大 payload。
13) 给你一个"推荐的 Set-Cookie 组合"(通用 Web 服务)
登录态:
sid=<random>;Path=/;HttpOnly;Secure;SameSite=Lax
CSRF:
csrf=<random>;Path=/;Secure;SameSite=Lax
退出登录:
Set-Cookie: sid=; Max-Age=0; Path=/; ...(同 Path/Domain 必须匹配才能删除)