Skip to content

ExpressJS - Cookies

HTTP cookie 是服务器发送给用户网络浏览器的一小段数据。浏览器会存储它们,并在每次后续请求发送到同一服务器时将其传回。Cookie 对于会话管理(如跟踪登录)、个性化(如用户偏好)和用户跟踪等功能至关重要。

要在 Express 中使用 cookie,你需要 cookie-parser 中间件。它会解析传入请求中的 Cookie 头部,并将 req.cookies 对象填充为以 cookie 名称为键的键值对。它还添加了 res.cookie() 方法来设置 cookie。

首先,安装 cookie-parser 作为依赖项:

npm install cookie-parser

接下来,在你的 index.js 中导入并将其作为中间件应用。重要的是,要将其放置在任何需要访问 cookie 的路由之前。

import express from 'express';
import cookieParser from 'cookie-parser';
const app = express();
// 应用 cookie-parser 中间件
// 稍后我们将为签名 cookie 添加一个密钥
app.use(cookieParser());
// ... 你的路由

让我们创建两个路由:一个用于设置 cookie,另一个用于读取它。

// 设置 cookie 的路由
app.get('/set-cookie', (req, res) => {
// 设置一个名为 'userTheme'、值为 'dark' 的 cookie
res.cookie('userTheme', 'dark');
res.send('Cookie 已设置!请检查你的浏览器开发者工具。');
});
// 读取 cookie 的路由
app.get('/get-cookie', (req, res) => {
// 从请求对象中访问 cookie
const theme = req.cookies.userTheme;
if (theme) {
res.send(`你的主题设置为: ${theme}`);
} else {
res.send('未找到主题 cookie。');
}
});
// ... app.listen

运行服务器后,首先访问 http://localhost:3000/set-cookie。然后,访问 http://localhost:3000/get-cookie。你应该会看到确认你主题的消息。你还可以在浏览器的开发者工具中检查存储的 cookie(通常在“应用程序”或“存储”选项卡中)。

仅仅设置一个 cookie 对于生产应用程序来说通常是不够的。你必须安全地配置它们,以防止常见的攻击,如跨站脚本 (XSS) 和跨站请求伪造 (CSRF)。

res.cookie() 方法接受一个选项对象作为其第三个参数。以下是最重要的安全选项:

  • **httpOnly: true**:这至关重要。它阻止客户端 JavaScript (document.cookie) 访问 cookie。这可以缓解攻击者试图窃取 cookie 的 XSS 攻击。
  • **secure: true**:确保 cookie 仅通过 HTTPS 连接发送。在生产环境中,你应始终启用此选项。
  • **sameSite: ‘strict’或’lax’**:防御 CSRF 攻击的强大手段。'strict' 阻止浏览器在任何跨站请求中发送 cookie。'lax' 是一个合理的默认值,允许在顶级导航(例如,点击来自其他网站的链接)时发送 cookie。
  • **maxAge或expires**:设置 cookie 的过期时间。maxAge 是从当前开始的毫秒数,而 expires 是一个特定的 Date 对象。
app.get('/set-secure-cookie', (req, res) => {
const options = {
maxAge: 7 * 24 * 60 * 60 * 1000, // 7 天的毫秒数
httpOnly: true, // 该 cookie 仅能由 Web 服务器访问
secure: process.env.NODE_ENV === 'production', // 仅在 HTTPS 上设置
sameSite: 'lax' // 或 'strict'
};
res.cookie('sessionToken', 'abc123xyz', options);
res.send('安全 cookie 已设置!');
});

Cookie 存储在客户端,可能会被篡改。为了确保 cookie 的值未被更改,你可以使用签名 cookie。如果你向 cookie-parser 提供一个密钥字符串,它就可以实现这一点。

重要提示:你的密钥应该是一个长而随机的字符串,安全地存储为环境变量,而不是硬编码。

// 出于安全考虑,密钥应来自环境变量
const COOKIE_SECRET = process.env.COOKIE_SECRET || 'default-secret';
app.use(cookieParser(COOKIE_SECRET));
// 设置签名 cookie
app.get('/set-signed-cookie', (req, res) => {
res.cookie('userRole', 'admin', { signed: true });
res.send('签名 cookie 已设置。');
});
// 读取签名 cookie
app.get('/get-signed-cookie', (req, res) => {
// 未签名 cookie 在 req.cookies 中
// 签名 cookie 在 req.signedCookies 中
const userRole = req.signedCookies.userRole;
if (userRole) {
res.send(`你的角色是: ${userRole}`);
} else {
// 如果 cookie 被篡改或未设置,就会出现这种情况
res.status(401).send('无效或缺失角色 cookie。');
}
});

要删除一个 cookie,请使用 res.clearCookie()。你必须传入与设置时相同的选项(例如 domain 和 path)。

app.get('/logout', (req, res) => {
res.clearCookie('sessionToken');
res.send('你已退出登录。');
});