前端项目如何防止 CSRF 攻击及 Token 验证的具体实现代码?

文章导读
前端防 CSRF 最稳妥的方案是结合 SameSite Cookie 策略与自定义 Token 验证。需注意,核心安全逻辑依赖后端实现,纯前端无法独立完成防护,适用于大多数前后端分离或传统会话制项目。
📋 目录
  1. 核心原理
  2. 后端完整实现(Express 示例)
  3. 本地开发配置注意
  4. 前端读取与发送
  5. 验证防护是否生效
  6. 常见坑与风险
A A

前端防 CSRF 最稳妥的方案是结合 SameSite Cookie 策略与自定义 Token 验证。需注意,核心安全逻辑依赖后端实现,纯前端无法独立完成防护,适用于大多数前后端分离或传统会话制项目。

先说结论:单纯依赖前端校验不可靠,必须后端验证 Token 且 Cookie 设置 SameSite 属性

  • 先判断:确认业务是否使用 Cookie 自动携带身份凭证,这是 CSRF 攻击的基础
  • 优先做:后端生成随机 Token 并存入 Session 或加密 Cookie,前端请求时带入
  • 再验证:通过构造无 Token 请求测试后端是否拒绝,确保防护生效

核心原理

CSRF 攻击的核心在于浏览器会自动携带目标域名的 Cookie。攻击者诱导用户点击链接或提交表单时,浏览器会附带用户的登录态,后端若只验证 Cookie 而不检查请求来源或额外凭证,就会误以为是用户本人操作。

Token 验证的原理是攻击者无法获取这个动态生成的 Token(受同源策略保护),因此无法构造合法的请求。SameSite 属性则是从浏览器层面限制 Cookie 的跨站发送。

后端完整实现(Express 示例)

以下是一个包含 Token 生成、Cookie 设置及验证中间件的完整示例。注意需引入 crypto 模块。

const express = require('express');
const crypto = require('crypto');
const cookieParser = require('cookie-parser');
const session = require('express-session');

const app = express();

// 1. 中间件配置
app.use(cookieParser());
app.use(session({
  secret: 'your-secret-key',
  resave: false,
  saveUninitialized: true,
  cookie: {
    secure: true, // HTTPS 环境下必须为 true,本地 HTTP 开发可设为 false
    sameSite: 'strict' // 本地开发或跨子域建议先用 'lax' 测试
  }
}));

// 2. 生成 Token 中间件
app.use((req, res, next) => {
  if (!req.session.csrfToken) {
    req.session.csrfToken = crypto.randomBytes(32).toString('hex');
  }
  // 将 Token 写入 Cookie 供前端读取(非 HttpOnly)
  res.cookie('csrfToken', req.session.csrfToken, {
    sameSite: 'strict',
    secure: true
  });
  next();
});

// 3. 验证 Token 中间件
const csrfProtection = (req, res, next) => {
  const token = req.headers['x-csrf-token'];
  if (!token || token !== req.session.csrfToken) {
    return res.status(403).send('Invalid CSRF token');
  }
  next();
};

// 4. 受保护的路由
app.post('/api/transfer', csrfProtection, (req, res) => {
  res.json({ success: true });
});

本地开发配置注意

在本地开发环境(localhost)通常没有 HTTPS,此时 Cookie 的 Secure 属性需设置为 false,否则浏览器不会发送 Cookie。同时,SameSite=Strict 在某些跨子域或重定向场景下可能导致 Cookie 携带失败,开发阶段可暂时使用 Lax,生产环境建议回归 Strict

前端项目如何防止 CSRF 攻击及 Token 验证的具体实现代码?

前端读取与发送

前端从 Cookie 读取 Token,在所有修改数据的请求(POST/PUT/DELETE)头中携带。

// 读取 Cookie 中的 Token
function getCookie(name) {
  const value = `; ${document.cookie}`;
  const parts = value.split(`; ${name}=`);
  if (parts.length === 2) return parts.pop().split(';').shift();
}

// 发送请求
const token = getCookie('csrfToken');
fetch('/api/update', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    'X-CSRF-Token': token
  },
  body: JSON.stringify(data)
});

验证防护是否生效

  1. 打开浏览器开发者工具,进入 Network 面板。
  2. 正常发起一个修改数据的请求,确认请求头中包含 X-CSRF-Token 且状态码为 200。
  3. 在控制台手动构造一个不带 Token 的 fetch 请求,或使用 curl 模拟跨站请求,确认后端返回 403 Forbidden。
  4. 检查 Cookie 详情,确认 SameSite 字段已生效(显示为 Strict 或 Lax)。

常见坑与风险

1. Token 存储与 XSS 风险

若前端需通过 JS 读取 Token,Cookie 不可设置 HttpOnly,但需配合 CSP 防范 XSS。不要将 Token 仅存放在 localStorage 中而不配合 HttpOnly Cookie,这容易受到 XSS 攻击导致 Token 泄露。

2. 忽略 CORS 预检

前端项目如何防止 CSRF 攻击及 Token 验证的具体实现代码?

如果前后端跨域,自定义 Header 会触发 OPTIONS 预检请求。确保后端 CORS 配置允许 X-CSRF-Token 头。

3. SameSite 策略过于严格

第三方登录回调场景下,Strict SameSite 可能阻断 Cookie 携带。此时需评估使用 Lax 或针对特定路径放宽策略。

4. 单页应用路由跳转

在 SPA 中,页面不刷新可能导致 Token 未更新。确保 Token 获取逻辑在应用初始化或每次请求前执行。