# cookie-parser
30 秒速记
cookie-parser是Express的中间件:把请求头里的Cookie字符串解析成req.cookies对象- 传了
secret就额外验签,结果放进req.signedCookies;验签失败的值是false - 签名 ≠ 加密:签名后的
cookie里明文原样可见,只是改了会被发现 - 写
cookie用的是Express的res.cookie(name, val, { signed: true }),和cookie-parser共用同一个secret - 签名只防篡改,不防偷看、不防重放;登录态还是存随机
session id,配httpOnly、secure、sameSite
cookie-parser 干两件事:把 Cookie 请求头解析成对象,以及校验签名 cookie 有没有被改过。 签名的做法是把原值和一段 HMAC 拼在一起,服务端拿 secret 重算一遍比对,对不上就判定被篡改。很多人把这个说成「cookie 加密」,这是最常见的误解:打开浏览器 DevTools 就能看到原值。所以它适合放「可以给用户看、但不能让用户改」的东西,敏感信息要么不放 cookie,要么真加密。
理解「cookie-parser」时,要先明确输入、运行阶段和可观察输出。这里的交互实验会分别执行正常路径与失败路径,并把 Node.js 的关键状态变化和同屏代码对应起来;不能只记命令名称。
工程中还要验证退出码、资源清理和异常输入。属于 security 场景的配置应保持最小可复现,并在开发环境与 CI 中使用相同命令复跑,避免把平台差异或隐式默认值带到线上。
cookie-parser 的源码不长,核心流程可以用几行代码说清:
const express = require('express');
const cookieParser = require('cookie-parser');
const app = express();
app.use(cookieParser('my-secret'));
app.get('/set', (req, res) => {
res.cookie('plain', 'hello'); // 普通 cookie
res.cookie('uid', '42', { signed: true, httpOnly: true }); // 签名 cookie
res.end('ok');
});
app.get('/read', (req, res) => {
console.log(req.cookies); // { plain: 'hello' }
console.log(req.signedCookies); // { uid: '42' },被改过则是 { uid: false }
res.end('ok');
});
app.listen(3000);
浏览器里 uid 的实际值是 s:42.<签名>,s: 前缀表示这是签名 cookie,. 后面是用 secret 对 42 算出的 HMAC-SHA256(base64 编码,去掉末尾 =)。验签时取出 . 前面的原值,用同一个 secret 重算签名并比对,一致就返回原值,否则返回 false。
当前 1.4.x 版本里,验签过的 cookie 会从 req.cookies 挪到 req.signedCookies,所以读签名 cookie 要去 req.signedCookies 拿。另外值以 j: 开头的会被当成 JSON 解析,这是 res.cookie 写入对象时自动加的前缀。
面试官追问
追问 1不装 cookie-parser,req.cookies 是什么?
是 undefined。Express 4 起不再内置 cookie 解析,只能自己读 req.headers.cookie 去解析,或者装这个中间件。写 cookie 的 res.cookie 倒是 Express 自带的。
追问 2用户把 cookie 里的 role=user 改成 role=admin,签了名的话服务端能发现吗?
能。签名是对原值算的 HMAC,改了值签名就对不上,req.signedCookies.role 会变成 false。不过权限这种东西我不会放 cookie,放服务端 session 里查更稳。
追问 3签名 cookie 里能放手机号吗?
不建议。签名不隐藏内容,s:13800000000.xxxx 前半段谁都能读。真要放就用 AES-GCM 加密后再写,或者只放一个随机 id 在服务端查。
追问 4secret 要换,怎么不让所有用户一下子掉登录?
cookieParser 支持传数组,比如 cookieParser(['new', 'old']):用第一个签新 cookie,验签时依次尝试每一个。过渡期结束、旧 cookie 都过期了,再把 old 去掉。
追问 5cookie-parser 和 express-session 一起用要注意什么?
express-session 从 1.5 起自己读写 cookie,不再依赖 cookie-parser。两个都用的话 secret 要保持一致,不然一个签一个验会对不上。
# 文章导读
30 秒速记
cookie-parser是Express官方脚手架内置的中间件,负责解析cookie- 用起来就一行
app.use(cookieParser(secret)),踩坑基本都出在签名和验签机制没搞懂 - 分工:
Express的res.cookie负责签名写入,cookie-parser负责解析和验签,两边共用一个secret - 签名的价值是防篡改,不是加密,这是整篇最想纠正的误解
这篇要讲清楚的是 Express 加 cookie-parser 怎么给 cookie 签名、怎么验签,以及签名到底能保证什么安全。 平时用的时候几乎感觉不到它,出问题一般是这几类:签了名却去 req.cookies 里取不到值,换了 secret 用户全掉线,或者以为签名后别人就看不到内容。只要把「签名是原值加 HMAC」这一点吃透,这些问题都能自己推出来。
cookie-parser是Express的中间件,用来实现cookie的解析,是官方脚手架内置的中间件之一。
它的使用非常简单,但在使用过程中偶尔也会遇到问题。一般都是因为对Express + cookie-parser的签名、验证机制不了解导致的。
本文深入讲解Express + cookie-parser的签名和验证的实现机制,以及cookie签名是如何增强网站的安全性的。
面试官追问
追问 1cookie 签名和 cookie 加密,一句话说区别?
签名是「能看不能改」,原值明文放着,后面附一段校验码;加密是「看都看不懂」,没有密钥还原不出原值。cookie-parser 做的是前者。
追问 2设置了 signed: true,但 req.cookies.nick 读出来是 undefined,为什么?
验签通过的 cookie 被放进了 req.signedCookies,同时从 req.cookies 里删掉了。改成读 req.signedCookies.nick 就行。
追问 3res.cookie(..., { signed: true }) 报错说缺 secret,是哪没配?
res.cookie 签名用的是 req.secret,这个值是 cookieParser(secret) 挂上去的。中间件没传 secret,或者注册顺序在路由后面,req.secret 就是空的。
追问 4前后端分离项目,接口用 token 放在 Authorization 头里,还需要 cookie-parser 吗?
不需要。它只处理 Cookie 头,鉴权完全不走 cookie 的话装了也用不上。如果 refresh token 放在 httpOnly cookie 里,那还是要它来解析。
# 入门例子:cookie设置与解析
30 秒速记
- 写
cookie:res.cookie('nick', 'chyingp')→ 响应头Set-Cookie: nick=chyingp; Path=/ - 读
cookie:cookie-parser解析请求头Cookie,挂到req.cookies - 第一次访问读不到,第二次才有:
cookie是浏览器下次请求才带上来的 - 不传
secret时它基本就等于req.cookies = cookie.parse(req.headers.cookie || '') - 中间件要注册在读
cookie的路由前面,否则req.cookies是undefined
不签名时,cookie-parser 做的事很简单:把请求头里 a=1; b=2 这样的字符串解析成 { a: '1', b: '2' } 挂到 req.cookies。 写 cookie 则是 Express 自己的 res.cookie,它会往响应里加一个 Set-Cookie 头。新手常问为什么刚设置完读不到,因为设置是写在这次响应里的,浏览器要等下一次请求才会把它带回来,所以同一个请求里读不到刚写的值。
先从最简单的例子来看下cookie-parser的使用,下面采用默认配置。
- cookie设置:使用
Express的内置方法
