CSRF防护的几种实现方式

CSRF(Cross-Site Request Forgery,跨站请求伪造)是一种常见的Web安全威胁,攻击者利用用户已登录的身份,在用户不知情的情况下执行非预期的操作。本文将介绍几种在JavaScript中实现CSRF防护的有效方法。

1. 使用CSRF Token

最广泛采用的CSRF防护机制是CSRF Token模式:

javascript 复制代码
// 服务端生成并返回Token
const generateCSRFToken = () => {
  return crypto.randomBytes(32).toString('hex');
};

// 客户端存储Token(通常放在meta标签中)
const csrfToken = document.querySelector('meta[name="csrf-token"]').content;

// 在所有修改状态的请求中包含Token
fetch('/api/sensitive-action', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    'X-CSRF-Token': csrfToken
  },
  body: JSON.stringify({ data: 'value' })
});

实现要点

  • 每个用户会话使用唯一Token
  • Token应足够随机且不可预测
  • 只对修改状态的请求要求Token验证
  • Token通过HTTP头而非URL传递更安全

2. SameSite Cookie属性

利用现代浏览器的SameSite Cookie特性:

javascript 复制代码
// 服务端设置Cookie时
Set-Cookie: sessionid=xxxx; SameSite=Strict; Secure; HttpOnly

SameSite有三种模式:

  • Strict:完全禁止跨站发送Cookie
  • Lax:允许安全方法(如GET)的跨站请求携带Cookie
  • None:允许跨站发送Cookie(需同时设置Secure)

3. 双重Cookie验证

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

const csrfCookie = getCookie('csrf_token');

// 在请求中同时携带Cookie和自定义头
fetch('/api/action', {
  method: 'POST',
  credentials: 'include', // 确保发送Cookie
  headers: {
    'X-CSRF-Token': csrfCookie
  }
});

4. 自定义请求头

javascript 复制代码
// 所有API请求添加自定义头
fetch('/api/data', {
  method: 'POST',
  headers: {
    'X-Requested-With': 'XMLHttpRequest'
  }
});

原理:浏览器的同源策略限制了自定义头的跨域发送

5. 验证Referer/Origin头

javascript 复制代码
// 服务端验证示例
app.post('/api/action', (req, res) => {
  const origin = req.get('origin') || req.get('referer');
  if (!origin || !origin.includes('yourdomain.com')) {
    return res.status(403).send('Invalid request origin');
  }
  // 处理正常请求
});

最佳实践组合

对于最高级别的防护,建议组合使用多种方法:

  1. 主要防护:SameSite=Strict Cookie + CSRF Token
  2. 额外防护:验证Origin/Referer头
  3. 防御深度:关键操作要求重新认证

注意事项

  • 避免将CSRF Token存储在localStorage中(易受XSS攻击)
  • 对于SPA应用,确保Token在页面刷新后仍然有效
  • 定期轮换Token(如每次登录后)
  • 不要通过GET请求执行状态修改操作

通过合理组合这些防护措施,可以有效地防御CSRF攻击,保护Web应用和用户数据的安全。