跨域伪造请求如何规避

wen 开源项目 26

跨域伪造请求(CSRF)如何规避:全面防御指南与实战策略

📚 目录导读

  1. 什么是跨域伪造请求(CSRF)?
  2. CSRF攻击的核心原理与危害
  3. 现代Web应用中的CSRF防御策略
  4. 实战:代码级别的CSRF防护实现
  5. 高阶防护:同源策略与CORS配置
  6. 常见误区与Q&A问答
  7. 总结与最佳实践

什么是跨域伪造请求(CSRF)?

跨站请求伪造(Cross-Site Request Forgery,简称CSRF) 是一种利用用户已登录身份,在用户不知情的情况下,向目标网站发起恶意请求的攻击方式,攻击者通过构造恶意页面或链接,诱导用户触发请求,从而执行修改密码、转账、发帖等敏感操作。

跨域伪造请求如何规避

核心特征:

  • 利用用户已认证的Cookie或Session
  • 请求合法但非用户本意
  • 攻击者无法获取响应内容(但可执行状态修改操作)

CSRF攻击的核心原理与危害

攻击流程示例:

  1. 用户登录银行网站,浏览器保存了Session Cookie
  2. 用户未登出银行网站,同时访问了攻击者构造的恶意页面
  3. 恶意页面中包含一个自动提交的表单:<form action="https://bank.example/transfer" method="POST"><input name="amount" value="10000"><input name="to" value="attacker"></form><script>document.forms[0].submit();</script>
  4. 浏览器自动携带银行网站的Cookie发送请求,银行认为这是用户本人操作

危害等级:

危害类型 示例场景
资金损失 转账、支付操作
数据篡改 修改密码、删除内容
权限提升 创建管理员账户
隐私泄露 修改个人资料

现代Web应用中的CSRF防御策略

根据OWASP、微软、Google等主流安全机构的推荐,以下是经过验证的CSRF防御方案:

1 Token验证(最核心方案)

  • 原理:服务器生成唯一Token,嵌入表单或HTTP头,提交时验证
  • 实现方式<input type="hidden" name="csrf_token" value="random_value">
  • 关键点:Token必须绑定用户Session,每次请求刷新或限制有效期

2 SameSite Cookie属性(现代浏览器原生防御)

  • Strict:完全禁止跨站发送Cookie(最严格)
  • Lax:允许GET请求携带Cookie(默认模式,适用于链接跳转)
  • None:必须配合Secure属性,允许跨站发送Cookie
Set-Cookie: sessionid=abc123; SameSite=Lax; Secure

3 Referer/Origin头验证

  • 检查请求头中的RefererOrigin是否来自可信域名
  • 注意:某些浏览器或隐私插件可能不发送Referer头

4 双重Cookie验证

  • 在Cookie中设置随机值,同时在请求体或头中传递相同值
  • 服务器对比Cookie中的值与请求携带的值是否一致

实战:代码级别的CSRF防护实现

1 后端Token生成(Node.js + Express示例)

// 生成CSRF Token
const csrf = require('csurf');
const csrfProtection = csrf({ cookie: true });
app.use(csrfProtection);
app.get('/form', (req, res) => {
  res.render('form', { csrfToken: req.csrfToken() });
});
app.post('/transfer', (req, res) => {
  // 如果Token无效,csurf中间件会自动拒绝请求
  res.send('转账成功');
});

2 前端表单嵌入Token

<form action="/transfer" method="POST">
  <input type="hidden" name="_csrf" value="{{csrfToken}}">
  <input type="text" name="amount" placeholder="金额">
  <button type="submit">提交</button>
</form>

3 前后端分离API的Token处理

对于SPA应用,建议在HTTP头中传递Token:

// 前端请求
fetch('/api/transfer', {
  method: 'POST',
  headers: {
    'X-CSRF-Token': csrfToken,
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({ amount: 1000 })
});
// 后端验证
app.use((req, res, next) => {
  const token = req.headers['x-csrf-token'];
  if (token !== req.session.csrfToken) {
    return res.status(403).send('CSRF验证失败');
  }
  next();
});

高阶防护:同源策略与CORS配置

虽然同源策略(Same-Origin Policy)默认阻止跨域读取响应,但不足以防御CSRF(因为CSRF不需要读取响应),正确的CORS配置可以额外增强防护:

1 严格的CORS配置

// 只允许特定域名
app.use(cors({
  origin: 'https://trusted-site.example',
  credentials: true,  // 允许携带Cookie
  methods: ['GET', 'POST']
}));

2 禁用CORS通配符

永远不要使用Access-Control-Allow-Origin: *配合Access-Control-Allow-Credentials: true,这会导致跨域攻击者直接调用API。

常见误区与Q&A问答

❓ Q1:使用HTTPS就能防御CSRF吗?

答:不能。 HTTPS只能加密传输内容,防止中间人攻击,但CSRF利用的是用户已建立的合法会话,与是否加密无关。

❓ Q2:前端做Token加密就能保证安全吗?

答:不能。 CSRF Token必须由服务器生成并验证,前端只是传递,如果前端自行加密Token,攻击者同样可以获取加密方法。

❓ Q3:API接口不涉及状态修改(仅GET)需要防护吗?

答:需要警惕。 虽然GET请求按照规范不应修改状态,但部分老旧系统可能通过GET执行操作,只要涉及数据修改,都应防护。

❓ Q4:使用JSON API需要做CSRF防护吗?

答:需要。 虽然浏览器默认不允许跨域POST JSON(需预检请求),但攻击者可以通过表单enctypefetch发送,因此仍需Token验证。

❓ Q5:SameSite=Strict会影响功能吗?

答:会。 设置Strict后,从其他站点的链接跳转也不会携带Cookie,可能导致登录状态丢失,建议使用Lax模式,它是安全与功能的平衡点。

❓ Q6:为什么只用Referer验证不够?

答: 因为:

  • 用户可能通过书签或地址栏直接访问(无Referer)
  • 浏览器扩展可能修改Referer
  • HTTPS降级到HTTP时Referer可能被移除

总结与最佳实践

防御CSRF的黄金法则:

优先级 措施 说明
使用CSRF Token 核心防线,必须服务器端随机生成
设置SameSite Cookie 现代浏览器原生防御,建议设为Lax
验证Referer/Origin 辅助验证,不可单独使用
使用自定义请求头 如X-Requested-With,仅限Ajax请求
二次验证 敏感操作增加验证码或密码确认

最终检查清单:

  • [ ] 所有状态修改请求都包含CSRF Token
  • [ ] Token绑定用户Session且有过期时间
  • [ ] Cookie已设置SameSite=Lax(或Strict)
  • [ ] CORS配置未使用通配符且与Credentials不共存
  • [ ] 敏感操作(如转账)增加二次确认
  • [ ] 定期更新依赖库,关注安全公告

通过以上分层的防御策略,即使某一层被突破,其他层仍可有效阻止CSRF攻击。安全不是单一措施,而是多层防御的叠加。

抱歉,评论功能暂时关闭!