Defense Mechanisms
CSRF 攻击成功的关键:
最常用的防护方式,原理是在请求中加入攻击者无法获取的随机 Token。
1. 用户登录时,服务器生成随机 CSRF Token
2. Token 存储在服务器 Session 中
3. 同时返回给前端(不能放在 Cookie 中!)
4. 前端每次请求时,在 Header 或 Body 中携带 Token
5. 服务器验证 Token 是否匹配
• Token 不在 Cookie 中,不会自动携带
• 同源策略阻止攻击者读取其他域的页面内容
• 攻击者无法获取 Token,请求会被拒绝
// 服务端验证
app.post('/transfer', (req, res) => {
const sessionToken = req.session.csrfToken
const requestToken = req.headers['x-csrf-token']
if (!requestToken || requestToken !== sessionToken) {
return res.status(403).json({ error: 'CSRF Token 验证失败' })
}
// 执行转账...
})
// 前端请求
fetch('/transfer', {
method: 'POST',
headers: {
'X-CSRF-Token': csrfToken // 从页面获取
},
body: JSON.stringify({ to: 'xxx', amount: 100 })
})
通过设置 Cookie 的 SameSite 属性,限制跨站请求携带 Cookie。
| 值 | 说明 | 防护效果 |
|---|---|---|
Strict |
完全禁止跨站携带 | 最强,但影响用户体验 |
Lax |
允许 GET 导航请求携带 | 推荐,平衡安全和体验 |
None |
允许跨站携带(需 Secure) | 无防护 |
// 设置 SameSite Cookie
res.cookie('session', sessionId, {
httpOnly: true,
secure: true,
sameSite: 'Lax' // 或 'Strict'
})
检查请求的来源是否合法。
app.post('/transfer', (req, res) => {
const origin = req.headers.origin
const referer = req.headers.referer
const allowedOrigins = ['https://bank.com']
if (!allowedOrigins.includes(origin)) {
return res.status(403).json({ error: '非法来源' })
}
// 执行转账...
})
Referer 可能被浏览器隐私设置屏蔽,不能作为唯一防护手段
对敏感操作要求用户进行二次验证:
当前账户余额: