CSRF攻击该怎么规避?

wen 网络安全 13

本文目录导读:

CSRF攻击该怎么规避?

  1. 核心防御:使用 CSRF Token(最广泛使用)
  2. 现代防御:SameSite Cookie 属性(浏览器原生支持)
  3. 验证 Referer 或 Origin 请求头(辅助防御)
  4. 增加二次验证(针对高风险操作)
  5. 前端辅助:禁止跨站提交(如 Fetch 设置 credentials)
  6. 最佳实践建议

CSRF(跨站请求伪造,Cross-Site Request Forgery)是一种常见的 Web 安全漏洞,攻击者利用用户已登录的身份,诱使用户在不知情的情况下向目标网站发送恶意请求(如修改密码、转账等)。

要有效规避 CSRF 攻击,通常从后端防御为主,前端辅助配合的原则出发,以下是目前业界最主流、最有效的几种规避方法:

核心防御:使用 CSRF Token(最广泛使用)

这是最经典且有效的防御方式。

  • 原理:服务器在渲染页面或返回表单时,生成一个随机的、不可预测的 Token(令牌)并存储在 Session 中,当用户提交请求时,必须携带这个 Token,服务器验证 Token 是否匹配。
  • 为什么能防御:攻击者构造的恶意页面无法获取到存储在用户浏览器中、属于目标网站的 Token(受同源策略限制)。
  • 实现步骤
    1. 用户访问页面时,服务器生成 Token 并嵌入表单的隐藏字段:<input type="hidden" name="_csrf_token" value="随机字符串">
    2. 用户提交请求时,后端比较请求中的 Token 与 Session 中的 Token 是否一致。
  • 注意:Token 不能通过 Cookie 传递(因为攻击者可以伪造 cookie 或利用某些漏洞),必须放在请求体(POST)或自定义请求头中。

现代防御:SameSite Cookie 属性(浏览器原生支持)

这是目前最省力、且非常有效的防御手段,现代浏览器(Chrome 80+, Firefox 60+, Safari 12+)已经原生支持。

  • 原理:在设置 Cookie 时,添加 SameSite 属性,告诉浏览器不要在跨站请求中发送该 Cookie。
  • 三种模式
    • Strict:最严格,任何跨站请求(例如从 evil.combank.com 发请求)都不会携带该 Cookie。缺点:用户从第三方网站点击链接跳转到 bank.com 时,也会丢失登录状态,体验较差。
    • Lax推荐):大部分场景下的最佳平衡,只允许部分“安全”的跨站请求携带 Cookie(如 <a> 链接、<link rel="prerender">、GET 表单提交)。不允许跨站 POST 请求、XMLHttpRequest<img><script> 等标签的请求携带 Cookie,这可以防御绝大多数 CSRF 攻击,又不影响正常的导航。
    • None:关闭 SameSite 保护,但必须同时设置 Secure(仅 HTTPS),否则浏览器会拒绝该 Cookie。

示例代码(Set-Cookie 响应头)

Set-Cookie: sessionid=abc123; SameSite=Lax; Secure; HttpOnly

验证 Referer 或 Origin 请求头(辅助防御)

  • 原理:检查 HTTP 请求头中的 Referer(来源页面地址)或 Origin(来源站点域名)是否合法。
  • 怎么做:后端判断 OriginReferer 的值是否为你的网站域名(如 https://www.yourbank.com)。
  • 为什么是辅助
    • Referer 可能因用户隐私设置、浏览器扩展、HTTPS 降级等原因缺失或不完整。
    • Origin 更可靠,但在某些老版本浏览器或特定请求中可能不存在。
    • 不建议完全依赖这个,但作为“纵深防御”中的一层是很好的。

增加二次验证(针对高风险操作)

对于修改密码、转账、删除账号等高风险操作,强制要求用户进行二次验证。

  • 方式:输入密码、输入短信验证码、使用 TOTP(基于时间的一次性密码,如 Google Authenticator)或扫码。
  • 效果:即使攻击者构造了伪造请求,由于无法提供验证码,攻击无法生效。

前端辅助:禁止跨站提交(如 Fetch 设置 credentials)

现代前端开发中,使用 fetchXMLHttpRequest 时,可以明确设置凭据的发送策略。

  • 对于 fetch:默认情况下,fetch跨域时不会发送 Cookie,除非你显式设置 credentials: 'include',请检查你的前端代码,确保没有在主站之外随意附带 Cookie。

    // 默认安全:跨域不会发 Cookie
    fetch('https://api.yourbank.com/transfer');
    // 显式设置时才发,需要后端配合 CORS(跨域资源共享)
    fetch('https://api.yourbank.com/transfer', {
      credentials: 'include'
    });

最佳实践建议

对于现代 Web 应用,推荐的防御组合是:

  1. 首要方案后端设置 SameSite=Lax,这是最低成本、最基础且覆盖面最广的防御。
  2. 重要补充关键接口(如登录、转账、支付)使用 CSRF Token,因为 SameSite=Lax 无法防御基于 GET 链接的 CSRF(虽然 GET 请求不应产生副作用,但现实中存在)。
  3. 纵深防御:后端验证 Origin
  4. 超级安全:对高风险操作实施二次验证(密码/验证码)。

一个简单的检查清单:

  • [ ] 所有涉及状态变更的 POST/PUT/DELETE 接口,是否验证了 CSRF Token?
  • [ ] 登录 Session 的 Cookie 是否设置了 SameSite=LaxSameSite=Strict
  • [ ] 是否开启了 HttpOnlySecure 属性(防止 XSS 窃取 Cookie)?
  • [ ] 后端是否对 Origin 头进行了白名单校验?

特别注意: 不要禁用 GET 请求的副作用,即使你自认为“不会”,也要确保 GET 请求永远不会导致数据修改,攻击者可以通过 <img><script> 等标签轻易构造 GET 请求。

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