← 中文资源

简体中文版本

跨站请求伪造(CSRF)

CSRF 诱使受害者浏览器向另一个站点发送已认证的状态变更请求。防御需要 SameSite Cookie、CSRF Token 与来源校验。

阅读英文原文

攻击模型

受害者已登录 bank.example 并持有 Cookie。他们访问 evil.example,后者向 bank.example/transfer 提交隐藏表单。浏览器自动附带银行 Cookie,除非银行检查攻击者无法伪造的内容,否则无法区分该请求与合法请求。

防御

import crypto from 'node:crypto';

app.use((req, res, next) => {
  if (!req.session) return next();
  if (!req.session.csrf) req.session.csrf = crypto.randomBytes(32).toString('base64url');
  res.locals.csrfToken = req.session.csrf;
  next();
});

app.post('/transfer', (req, res) => {
  if (req.body.csrf !== req.session.csrf) return res.status(403).send('invalid csrf token');
  // 执行转账
});

会话 Cookie 应设置 SameSite=Lax 或 Strict 以及 Secure。高风险操作要求重新认证。把 Origin 或 Referer 校验作为纵深防御,但不能单独依赖。

适用范围

所有使用 Cookie 认证且会改变状态的接口都需要 CSRF 防护,包括以 POST 实现的登出。与 CORS 相比,CSRF 防护阻止请求被服务端执行,而 CORS 只控制攻击者页面能否读取响应。使用显式 Bearer Token 的 API 不受经典 CSRF 影响,但有自己的令牌存储风险。

陷阱

静态的、泄漏在 URL 中的、或未与会话绑定的 Token 几乎没有保护作用。状态变更的 GET 请求会绕过许多 Token 检查。应在浏览器中提交跨源表单进行测试,而不只是 curl,因为 curl 不执行浏览器的凭据规则。