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');
}
// 处理正常请求
});
最佳实践组合
对于最高级别的防护,建议组合使用多种方法:
- 主要防护:SameSite=Strict Cookie + CSRF Token
- 额外防护:验证Origin/Referer头
- 防御深度:关键操作要求重新认证
注意事项
- 避免将CSRF Token存储在localStorage中(易受XSS攻击)
- 对于SPA应用,确保Token在页面刷新后仍然有效
- 定期轮换Token(如每次登录后)
- 不要通过GET请求执行状态修改操作
通过合理组合这些防护措施,可以有效地防御CSRF攻击,保护Web应用和用户数据的安全。