防御 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
2. SameSite Cookie 属性
工作原理
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 只在跨站请求中存在
- 不能作为唯一防御手段
4. 双重提交 Cookie
工作原理
- 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
实现示例
javascriptfetch('/api/data', { headers: { 'X-Requested-With': 'XMLHttpRequest' } });
注意事项
- 只适用于 AJAX 请求
- 需要服务器验证 Header
6. 验证码
工作原理
- 敏感操作要求用户输入验证码
- 验证码需要用户主动输入
适用场景
- 金额较大的转账
- 删除重要数据
- 修改关键设置
7. 重新认证
工作原理
- 敏感操作要求重新输入密码
- 确保用户意图
实现示例
javascript// 执行敏感操作前 function performSensitiveAction(callback) { showPasswordPrompt((password) => { verifyPassword(password).then(valid => { if (valid) callback(); }); }); }
综合防御策略
最佳实践
- 使用 CSRF Token:主要防御手段
- 设置 SameSite=Lax:增强防护
- 验证 Origin/Referer:额外验证
- 敏感操作双重确认:重要操作
- 定期更新 Token:降低风险
- 监控异常请求:及时发现问题
框架支持
- Spring Security:自动生成和验证 CSRF Token
- Django:内置 CSRF 保护中间件
- Express:使用
csurf中间件 - Laravel:自动添加 CSRF Token
总结
没有单一的防御方法可以完全防止 CSRF 攻击。建议使用多层防护策略,以 CSRF Token 为主,配合 SameSite Cookie、Origin 验证等措施,为敏感操作添加额外的确认机制。