Cookie签名后为什么还是能被篡改?
我用 Express 的 cookie-parser 中间件加了签名,但发现用户手动改 Cookie 值后,服务端居然没报错,还能正常解析,这不就等于没签名吗?
我代码是这样写的:
const express = require('express');
const cookieParser = require('cookie-parser');
const app = express();
app.use(cookieParser('my-secret-key')); // 设置签名密钥
app.get('/set', (req, res) => {
res.cookie('token', 'abc123', { signed: true });
res.send('Cookie set');
});
app.get('/get', (req, res) => {
console.log(req.signedCookies.token); // 即使前端改了 token 值,这里有时还能输出?
res.send(req.signedCookies.token || 'none');
});
是不是我哪里理解错了?签名不是应该防止篡改的吗?
签名的实际机制是这样的:设置 signed cookie 时,cookie-parser 会把值和签名拼在一起,格式大概是
abc123.sigHASH,分成两部分用.分隔。当读取时,它会重新计算签名然后比对,如果不一致就直接返回 false,不会抛异常。你的代码里
req.signedCookies.token有时还能输出,可能是因为:1. 你改的是原始值,没改签名部分,或者
2. 你同时改了值和签名(虽然概率很低)
正确用法是必须手动判断返回值:
还有一点要确认——你读的是
req.signedCookies还是req.cookies?后者是原始未签名的值,任何改法都能读到。签名 cookie 必须走signedCookies这个属性。签名防篡改的原理其实就是这样:服务端重新计算签名比对,不一致就当无效处理,不会报错。这是常规做法,不是你的问题,是 cookie-parser 的设计风格比较"温柔"。