跨站请求伪造(Cross - Site Request Forgery,简称 CSRF)是一种常见的 Web 安全漏洞,攻击者通过诱导用户在已登录的受信任网站上执行非预期的操作。攻击者利用用户在浏览器中的会话信息,在用户不知情的情况下向目标网站发送恶意请求,由于浏览器会自动携带该网站的 cookie 等认证信息,服务器会将这些请求视为合法用户的操作,从而导致安全问题。
假设用户 Alice 已经登录了她的网上银行账户。攻击者 Bob 诱导 Alice 访问一个恶意网站,该网站包含一个隐藏的表单,表单的 action 指向 Alice 银行账户的转账接口。当 Alice 访问这个恶意网站时,浏览器会自动携带银行网站的 cookie 信息发送转账请求,银行服务器会认为这是 Alice 的合法操作,从而完成转账。
CSRF 令牌是一种常用的防止 CSRF 攻击的方法。服务器在生成页面时会为每个用户会话生成一个唯一的 CSRF 令牌,并将其包含在页面的表单或请求头中。当用户提交请求时,服务器会验证请求中携带的 CSRF 令牌是否与服务器端存储的令牌一致。如果不一致,则拒绝该请求。
以下是一个使用 Express 框架和 csurf
中间件实现 CSRF 防护的示例:
const express = require('express');
const session = require('express-session');
const csrf = require('csurf');
const bodyParser = require('body-parser');
const app = express();
// 配置会话
app.use(session({
secret: 'your-secret-key',
resave: false,
saveUninitialized: true
}));
// 解析表单数据
app.use(bodyParser.urlencoded({ extended: false }));
// 启用 CSRF 保护
const csrfProtection = csrf({ cookie: true });
// 获取表单页面
app.get('/form', csrfProtection, (req, res) => {
// 将 CSRF 令牌传递给表单页面
res.send(`
<form action="/submit" method="post">
<input type="hidden" name="_csrf" value="${req.csrfToken()}">
<input type="text" name="message" placeholder="Enter a message">
<input type="submit" value="Submit">
</form>
`);
});
// 处理表单提交
app.post('/submit', csrfProtection, (req, res) => {
const message = req.body.message;
res.send(`You submitted: ${message}`);
});
const port = 3000;
app.listen(port, () => {
console.log(`Server is running on port ${port}`);
});
express - session
中间件来管理用户会话,为每个用户分配一个唯一的会话 ID。body - parser
中间件来解析表单数据。csurf
中间件启用 CSRF 保护。csrfProtection
是一个中间件函数,用于生成和验证 CSRF 令牌。/form
路由中,使用 csrfProtection
中间件生成 CSRF 令牌,并将其包含在表单的隐藏字段中。/submit
路由中,同样使用 csrfProtection
中间件来验证请求中携带的 CSRF 令牌。如果令牌验证通过,则处理表单数据;否则,会抛出 CSRF 错误。防护方法 | 原理 | 优点 | 缺点 |
---|---|---|---|
CSRF 令牌 | 服务器生成唯一令牌,包含在表单或请求头中,请求时验证 | 实现相对简单,能有效防止 CSRF 攻击 | 需要在每个表单或请求中包含令牌,增加开发复杂度 |
通过在 Node.js 应用中使用 CSRF 令牌,我们可以有效地防止跨站请求伪造攻击,保护用户的信息安全。在实际开发中,建议始终启用 CSRF 保护,确保应用的安全性。