Nodejs 關於 Cookie的一些問題
Nodejs 關於 Cookie的一些問題
最近正在學習 ndoe.js 的 cookie 相關操作,發現一個問題:
app.configure(function() {
app.use(express.cookieParser('jfvstest'));
app.use(express.cookieSession( {
key: 'test',
secret: 'HelloExpressSESSION'
}));
app.get('/google', function(req, res) {
req.session.google = "google";
req.session.password = "123456";
console.log(req.cookies);
res.send("ok");
res.end();
});
我用瀏覽器套件觀察 cookie value 發現基本上依然是明文:
s%3Aj%3A%7B%22google%22%3A%22google%22%2C%22password%22%3A%22123456%22%7D.T0VjxprKtgC80%2Fuhfcs62mSsoe7sNC2Eo9KpV%2Bt0xr0
書上寫說 secret 的用途是:
Express 需要使用這組 secret 字串去加密 cookie,以防 cookie被破解。
有用 secret 的話,貌似依然是明文? (實際驗證的方式是我寫了另外一個 test.js 用,沒有相關 secret,使用:
console.log(req.cookies)
可以直接得到明文:
{ test: 's:j:{"google":"google","password":"123456"}.rsAPPiLlP6Of0KWqCxdRIxfR2NHKL3ibs+ZSIZq3gn4' }
secret 改變的話,實際影響的只有 rsAPPiLlP6Of0KWqCxdRIxfR2NHKL3ibs+ZSIZq3gn4 這串,可是 會話cookie 會完全明文存在客戶端。
我又做了一個小實驗,我在瀏覽器中修改
s%3Aj%3A%7B%22google%22%3A%22google%22%2C%22password%22%3A%22123456%22%7D.T0VjxprKtgC80%2Fuhfcs62mSsoe7sNC2Eo9KpV%2Bt0xr0
將 google 改成 gosogle,在 console.log(req.cookies)
三次:
{ ming: ‘s:j:{“gosogle”:“google”,“password”:“123456”}.OiVYufTj5DIdmvBy7/f03poRosZ/Vwwf1rYzGCQ1Z7o’ }
{ ming: ‘s:j:{}.jNSi4gEWlIHY0qiHpvD4By+LOak9MErZOoOCAqh/oQM’ }
{ ming: ‘s:j:{}.jNSi4gEWlIHY0qiHpvD4By+LOak9MErZOoOCAqh/oQM’ }
第一次得到的是我修改過的內容,第二次直接變成空值,再用瀏覽器看 cookie 值:
s%3Aj%3A%7B%7D.jNSi4gEWlIHY0qiHpvD4By%2BLOak9MErZOoOCAqh%2FoQM
有別於:
s%3Aj%3A%7B%22google%22%3A%22google%22%2C%22password%22%3A%22123456%22%7D.T0VjxprKtgC80%2Fuhfcs62mSsoe7sNC2Eo9KpV%2Bt0xr0
問題:
- 是哪些原因造成這些總總原因?
- 我想要讓 cookie 內容為加密狀態,除了自己加密 cookie 內容在丟給客戶瀏覽器之外,有沒有更優雅的方式?
- 最後一段修改實驗,第一次讀入的修改數據會是正常的,第二次就會被修改成空 {} 是何原因? 感謝!
Node.js 中关于 Cookie 的一些问题
问题背景
最近在学习 Node.js 的 cookie 相关操作时,遇到了一些困惑。特别是关于如何使用 express.cookieParser
和 express.cookieSession
来加密和保护 session 数据。
示例代码
const express = require('express');
const app = express();
// 使用 cookieParser 和 cookieSession
app.use(express.cookieParser('jfvstest'));
app.use(express.cookieSession({
key: 'test',
secret: 'HelloExpressSESSION'
}));
app.get('/google', function(req, res) {
req.session.google = "google";
req.session.password = "123456";
console.log(req.cookies);
res.send("ok");
res.end();
});
app.listen(3000, () => {
console.log('Server is running on port 3000');
});
问题分析
-
为什么 cookie 仍然是明文?
express.cookieParser
和express.cookieSession
并不直接对 cookie 进行加密,它们主要用于解析和签名 cookie。secret
主要用于签名 cookie,防止篡改。但 cookie 的内容本身并没有被加密,只是经过 Base64 编码。
-
如何让 cookie 内容为加密状态?
- 你可以使用第三方库如
cookie-encrypt
或者cookie-cipher
来加密 cookie 的内容。 - 示例代码如下:
- 你可以使用第三方库如
const express = require('express');
const cookieEncrypt = require('cookie-encrypt');
const app = express();
// 创建一个密钥
const secretKey = 'your-secret-key';
// 使用 cookieParser 解析 cookie
app.use(express.cookieParser(secretKey));
// 自定义中间件来加密 cookie
app.use((req, res, next) => {
// 加密 session 数据
req.session = cookieEncrypt.encrypt(req.session, secretKey);
next();
});
app.get('/google', function(req, res) {
req.session.google = "google";
req.session.password = "123456";
console.log(req.cookies);
res.send("ok");
res.end();
});
app.listen(3000, () => {
console.log('Server is running on port 3000');
});
- 为什么第一次读取到修改后的数据,第二次变成空值?
- 这可能是因为 session 数据没有正确地更新或存储。当你修改 cookie 的内容后,如果没有正确地保存 session,那么下次请求时 session 数据将为空。
- 确保每次修改 session 数据后都调用
req.session.save()
方法来保存更改。
总结
express.cookieParser
和express.cookieSession
只是用于解析和签名 cookie,而不是加密。- 要实现加密,可以使用第三方库如
cookie-encrypt
。 - 确保每次修改 session 数据后调用
req.session.save()
方法来保存更改。
希望这些信息能帮助你更好地理解和解决这些问题。
这个secret是用于防篡改标记session的那个cookie值的
cookie里放的内容就应该不怕客户端看,不想泄漏的话那就放到session里吧。
回答
1. 造成这些现象的原因
首先,express.cookieSession
和 express.cookieParser
在较旧版本的 Express 中用于处理 session 和 cookies。然而,在现代 Node.js 应用程序中,建议使用 express-session
和 cookie-parser
这两个中间件。
- 明文存储:
req.session
存储的是 session 数据,而不是直接存储到客户端的 cookie 中。session 数据是存储在服务器端,并且通过一个 session ID(通常是一个 cookie)来标识这个 session。 - Cookie 加密:
secret
参数用于签名 session ID,以防止篡改。它不会加密 session 数据本身。session 数据仍然需要在客户端可见,以便与服务器通信。
2. 如何实现加密存储
如果你希望加密存储 cookie 的内容,可以使用 cookie
包来手动处理 cookie 的加密。以下是一个示例:
const express = require('express');
const cookieParser = require('cookie-parser');
const crypto = require('crypto');
const app = express();
// 生成密钥
const secretKey = 'your-secret-key';
// 自定义加密函数
function encrypt(data) {
const cipher = crypto.createCipher('aes-256-cbc', secretKey);
let encrypted = cipher.update(JSON.stringify(data), 'utf8', 'hex');
encrypted += cipher.final('hex');
return encrypted;
}
// 自定义解密函数
function decrypt(data) {
const decipher = crypto.createDecipher('aes-256-cbc', secretKey);
let decrypted = decipher.update(data, 'hex', 'utf8');
decrypted += decipher.final('utf8');
return JSON.parse(decrypted);
}
app.use(cookieParser());
app.get('/google', (req, res) => {
const data = { google: 'google', password: '123456' };
const encryptedData = encrypt(data);
// 设置加密后的 cookie
res.cookie('encryptedData', encryptedData, { httpOnly: true });
res.send('ok');
});
app.get('/decrypt', (req, res) => {
const encryptedData = req.cookies.encryptedData;
const decryptedData = decrypt(encryptedData);
console.log(decryptedData); // { google: 'google', password: '123456' }
res.send('decrypted');
});
app.listen(3000, () => {
console.log('Server is running on port 3000');
});
在这个例子中,我们使用 AES-256-CBC 算法对 cookie 数据进行加密和解密。这样可以确保客户端看不到原始数据。
3. 修改实验的现象
在你的实验中,当你修改 cookie 值时,第二次读取会变成 {}
的原因可能是由于 cookie 的签名验证失败导致的。一旦签名验证失败,Express 会认为该 cookie 已经被篡改,因此将其重置为空对象。
总结来说,如果你希望更优雅地处理加密的 cookie,可以考虑使用上面的自定义加密方法。