乐闻世界logo
搜索文章和话题

如何防御 CSRF 攻击?

2月19日 17:48

防御 CSRF 攻击需要多层防护策略,以下是几种有效的防御方法:

1. CSRF Token(推荐)

工作原理

  • 服务器生成随机 Token,存储在会话中
  • Token 添加到表单隐藏字段或请求头中
  • 服务器验证请求中的 Token 是否与会话中的匹配

实现示例

javascript
// 前端 <form action="/transfer" method="POST"> <input type="hidden" name="csrf_token" value="{{ csrf_token }}"> <input type="text" name="amount"> <button type="submit">Transfer</button> </form> // 或使用 AJAX fetch('/transfer', { method: 'POST', headers: { 'X-CSRF-Token': csrf_token, 'Content-Type': 'application/json' }, body: JSON.stringify({ amount: 100 }) });

注意事项

  • Token 必须足够随机(至少 128 位)
  • Token 应该有时效性
  • 每个 Token 只能使用一次(可选)
  • 敏感操作必须验证 Token

工作原理

SameSite 属性控制 Cookie 在跨站请求中的发送行为。

属性值

javascript
// Strict:只在同站请求中发送 Cookie Set-Cookie: sessionid=abc123; SameSite=Strict // Lax:允许某些跨站请求(如导航) Set-Cookie: sessionid=abc123; SameSite=Lax // None:允许跨站请求(需要 Secure 属性) Set-Cookie: sessionid=abc123; SameSite=None; Secure

推荐配置

  • 敏感操作使用 SameSite=Strict
  • 一般应用使用 SameSite=Lax
  • 避免 SameSite=None 除非必要

3. 验证 Referer/Origin 头

工作原理

检查请求的来源是否合法。

实现示例

javascript
// 服务器端验证 const allowedOrigins = ['https://example.com', 'https://www.example.com']; function validateOrigin(req) { const origin = req.headers.origin || req.headers.referer; if (!origin) return false; const originUrl = new URL(origin); return allowedOrigins.includes(originUrl.origin); }

注意事项

  • Referer 可能被浏览器禁用或修改
  • Origin 只在跨站请求中存在
  • 不能作为唯一防御手段

工作原理

  • Token 同时存储在 Cookie 和请求参数中
  • 服务器验证两者是否匹配

实现示例

javascript
// 设置 Cookie res.cookie('csrf_token', token, { httpOnly: true, sameSite: 'strict' }); // 表单中包含 Token <input type="hidden" name="csrf_token" value="{{ csrf_token }}"> // 服务器验证 if (req.cookies.csrf_token !== req.body.csrf_token) { throw new Error('CSRF token mismatch'); }

注意事项

  • 需要配合其他防护措施
  • 不适用于所有场景

5. 自定义请求头

工作原理

  • 使用自定义 Header(如 X-Requested-With
  • 简单跨站请求无法添加自定义 Header

实现示例

javascript
fetch('/api/data', { headers: { 'X-Requested-With': 'XMLHttpRequest' } });

注意事项

  • 只适用于 AJAX 请求
  • 需要服务器验证 Header

6. 验证码

工作原理

  • 敏感操作要求用户输入验证码
  • 验证码需要用户主动输入

适用场景

  • 金额较大的转账
  • 删除重要数据
  • 修改关键设置

7. 重新认证

工作原理

  • 敏感操作要求重新输入密码
  • 确保用户意图

实现示例

javascript
// 执行敏感操作前 function performSensitiveAction(callback) { showPasswordPrompt((password) => { verifyPassword(password).then(valid => { if (valid) callback(); }); }); }

综合防御策略

最佳实践

  1. 使用 CSRF Token:主要防御手段
  2. 设置 SameSite=Lax:增强防护
  3. 验证 Origin/Referer:额外验证
  4. 敏感操作双重确认:重要操作
  5. 定期更新 Token:降低风险
  6. 监控异常请求:及时发现问题

框架支持

  • Spring Security:自动生成和验证 CSRF Token
  • Django:内置 CSRF 保护中间件
  • Express:使用 csurf 中间件
  • Laravel:自动添加 CSRF Token

总结

没有单一的防御方法可以完全防止 CSRF 攻击。建议使用多层防护策略,以 CSRF Token 为主,配合 SameSite Cookie、Origin 验证等措施,为敏感操作添加额外的确认机制。

标签:CSRF