CSRF漏洞如何防御加固

wen 开源项目 26

本文目录导读:

CSRF漏洞如何防御加固

  1. 使用 Anti-CSRF Token(核心防御手段)
  2. 同源检测(Origin / Referer 头校验)
  3. SameSite Cookie 属性(浏览器级防御)
  4. 关键操作二次验证(重要补充)
  5. 其他加固措施
  6. 综合加固建议(最佳实践)
  7. 简单总结表
  8. 最后提醒

使用 Anti-CSRF Token(核心防御手段)

这是最经典且有效的防御方式,适用于所有有状态(需要登录)的请求。

  • 原理:服务器为每个用户会话或每个表单生成一个随机、不可预测的 Token,该 Token 嵌入在表单的隐藏字段或请求头中,服务器在处理请求时验证 Token 是否正确。
  • 实现要点
    • 不可预测性:使用安全的随机数生成器(如 Python 的 secrets.token_hex、Java 的 SecureRandom)。
    • 绑定用户会话:每个用户的 Token 不同,且不能重复使用(或一次性有效)。
    • 关键操作必检:对修改密码、转账、删除、发布等所有 POST/PUT/DELETE 等有状态变化的请求强制校验。
    • 防护:攻击者无法获取用户页面中的 Token,因此无法构造有效请求。
  • 注意
    • Token 不能通过 Cookie 传递(因为 Cookie 会自动带在请求中,等于没防)。
    • Token 应在服务端生成并存储于 Session 或专用 Token 存储中。

同源检测(Origin / Referer 头校验)

适用于无法方便使用 Token 的场景,或作为辅助手段。

  • 原理:利用 HTTP 头中的 OriginReferer 字段判断请求来源是否合法。
  • 推荐方案优先校验 Origin
    • Origin 头包含协议、域名和端口,且通常不会被篡改。
    • Origin 存在,则校验其是否在白名单(你信任的域名)中。
  • 备用方案:检查 Referer 头。
    • Referer 可能被隐私设置屏蔽(如 <meta name="referrer" content="no-referrer">),且可能被浏览器降级处理,当 Referer 缺失时,不应直接拒绝,可降级为其他校验。
  • 适用场景:适用于无法植入 Token 的 RESTful API 或嵌入式应用。

SameSite Cookie 属性(浏览器级防御)

现代浏览器(Chrome, Firefox, Safari 主流版本)支持此属性,是防御 CSRF 的强力辅助手段

  • 原理:设置 Cookie 的 SameSite 属性,控制 Cookie 在跨站请求中是否发送。
  • 三个值
    • Strict:最严格,任何跨站请求(包括从其他网站点击链接跳转过来)都不带此 Cookie,用户体验可能受影响(如从第三方网站点链接到自己的网站,登录状态丢失)。
    • Lax(推荐默认值):允许部分安全的跨站请求携带 Cookie,如链接跳转、GET 请求触发的导航,但 POST、AJAX 等跨站请求不会携带,能防御大部分 CSRF 攻击。
    • None:不限制,需要配合 Secure 属性(仅 HTTPS)使用,不推荐用于敏感操作,除非你同时使用了其他强机制。
  • 设置方式Set-Cookie: sessionId=abc123; SameSite=Lax; Secure

关键操作二次验证(重要补充)

对于高风险操作(如修改密码、绑定手机、大额转账),即使有了以上防御,也应该增加二次确认机制。

  • 常见做法
    • 密码验证:要求用户输入当前密码。
    • 验证码:输入图形验证码、短信/邮箱验证码。
    • 生物识别:指纹、面部识别等。
  • 效果:即使 CSRF 成功发起请求,攻击者也无法通过第二步验证。

其他加固措施

  • 使用自定义请求头:对于前后端分离的 AJAX 请求,要求客户端在请求头中附带一个自定义头(如 X-Requested-With: XMLHttpRequest 或自定义 X-CSRF-Token),服务器检查该头是否存在且有效,因为跨域请求无法自定义普通请求头(除了标准头),否则会触发 CORS 预检请求。
  • 不依赖 GET 请求做状态修改:严格遵循 RESTful 规范,所有修改状态的操作必须使用 POST、PUT、DELETE 方法,GET 请求永远应该是幂等的(只读)。
  • 定期更新 Token:在用户登录、退出、或一段时间后刷新 Token,降低 Token 泄露风险。
  • 检查 Content-Type:可检查请求的 Content-Type 是否为期望值(如 application/json),而 CSRF 攻击常用的表单提交 Content-Typeapplication/x-www-form-urlencoded

综合加固建议(最佳实践)

  1. 强制使用 HTTPS:防止中间人窃取或篡改 Token 和 Cookie。
  2. Web 框架内置功能:尽量使用框架(如 Spring Security、Django、CSRF Protection for Express/Rails)自带的 CSRF 防护机制,通常已经处理好了常见的坑。
  3. 分层防御:不要依赖单一手段,建议组合:
    • 核心:Anti-CSRF Token(所有有状态修改请求)。
    • 补充:SameSite Cookie(设为 Lax)。
    • 兜底:关键操作加二次验证(密码或验证码)。
  4. 统一网关层处理:如果公司使用 API 网关(如 Nginx/Kong/Apache APISIX),可以在网关层统一注入 CSRF Token 或校验 Origin,避免每个业务服务自己实现。
  5. 异常监控:记录 CSRF 校验失败的日志(包括来源 IP、Referer、时间),用于发现潜在攻击或配置错误。

简单总结表

防御手段 原理 优点 缺点 推荐度
Anti-CSRF Token 验证请求携带的随机 Token 最通用、可靠 需要前后端配合,增加工作量 ⭐⭐⭐⭐⭐
同源检测 校验 Origin/Referer 轻量,防伪能力尚可 可能缺失或伪造(较难) ⭐⭐⭐⭐
SameSite Cookie 浏览器禁止跨站带 Cookie 浏览器级防御,无需修改业务 依赖浏览器版本,不兼容旧版 ⭐⭐⭐⭐⭐
二次验证 额外验证(密码/验证码) 防御力极强 用户体验降低 ⭐⭐⭐⭐
自定义请求头 检查特定头是否存在 简单,适合 AJAX 需要后端配合 ⭐⭐⭐

最后提醒

  • 不要禁用浏览器的 SameSite 属性,除非你有明确的兼容性需求。
  • 不要在 GET 请求中做敏感操作
  • 永远不要只依赖 Referer 头,因为它可能被客户端或中间件篡改或省略。

如有具体的框架或技术栈(如 Spring Boot, Django, Node.js Express, Vue.js + axios 等),可以进一步询问,我可以提供更具体的代码级实现示例。

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