CSRF 攻击(Cross-Site Request Forgery)

中心主题:CSRF 攻击(跨站请求伪造)


原理

  1. 攻击建立在浏览器与 Web 服务器的会话(Session/Cookie)之中
  2. 攻击者不需要知道受害者的 Cookie 值
  3. 开发者未对会话设置 TokenReferer 验证,也未使用验证码等二次确认措施
  4. 浏览器在同源会话下自动携带 Cookie 发起请求

危害

  • 用当前登录用户的权限执行任意操作
  • 常见后果:
    • 修改密码
    • 新增管理员账号
    • 修改个人信息
    • 转账 / 支付
    • 删除数据
    • 发帖 / 评论(垃圾信息)
    • 获取 Shell(如果结合文件上传等功能)

攻击流程(典型场景)

  1. 用户 C 正常登录网站 A,浏览器保存了 Cookie/Session
  2. 用户 C 在同一浏览器中访问恶意网站 B(或点击恶意链接、邮件、论坛图片等)
  3. 网站 B 返回恶意页面,包含自动触发的请求(img、form、iframe、XMLHttpRequest 等)
  4. 浏览器在用户不知情的情况下,向网站 A 发起带有 Cookie 的请求
  5. 网站 A 收到请求,认为来自合法用户 C,执行恶意操作

分类

1. 站外 CSRF(最常见)

  • 攻击代码位于第三方网站(B站)
  • 常见触发方式:
    • 恶意链接(GET)
    • 自动提交的隐藏表单(POST)
    • <img src="..."> 标签(GET)
    • JSONP、Flash 等旧方式

2. 站内 CSRF

  • 攻击代码位于目标网站内部(A站)
  • 常见原因:
    • 开发者滥用 $_REQUEST(同时接收 GET 和 POST)
    • 本应只接受 POST 的敏感操作,却也接受了 GET 请求
  • 攻击者可通过站内留言、评论、头像、文章插入恶意链接或图片

检测方法

1. 使用 CSRF 测试工具

  • CSRF Tester / CSRF PoC 生成器
    • 抓取正常请求包
    • 修改参数后重新提交
    • 如果成功执行 → 存在 CSRF

2. 手工检测

  • 抓取一个正常敏感操作的请求包
  • 去掉 Referer 头后重新提交
  • 如果仍成功 → 基本存在 CSRF(未校验 Referer)
  • 构造站外页面,模拟请求,观察是否被执行

防御方法

服务端防护(推荐优先级最高)

  1. 使用 CSRF Token(最有效、最推荐)

    • 每个表单/请求携带唯一、不可预测的 Token
    • Token 存放在隐藏字段、Header 或 URL 中
    • 服务端校验 Token 是否匹配当前会话
  2. 验证 HTTP Referer 头

    • 检查 Referer 是否属于本站域名
    • 缺点:可被伪造 / 浏览器/代理可能不发送 Referer
  3. 自定义 HTTP Header 验证

    • X-CSRF-TokenX-Requested-With: XMLHttpRequest
    • 浏览器同源策略限制跨域自定义头
  4. 严格区分 GET 和 POST

    • 敏感操作(如改密、转账)只接受 POST
    • GET 请求一律不允许修改数据
  5. 使用验证码 / 二次确认

    • 高危操作要求输入验证码或二次密码

客户端防护(辅助)

  • 用户安全意识培训
  • 浏览器插件(如 NoScript、uBlock Origin 拦截可疑请求)
  • 及时更新浏览器,开启 SameSite Cookie 属性

浏览器安全特性

  • SameSite Cookie(推荐)
    • Strict:完全禁止跨站携带
    • Lax:允许顶级导航(GET)携带,阻止 POST 等
    • None:需配合 Secure 属性

快速记忆口诀

CSRF 三要素缺一不可

  1. 用户已登录(有有效 Cookie/Session)
  2. 攻击者诱导用户访问恶意页面/点击链接
  3. 目标网站未做 Token / Referer / SameSite 等防护

最强防御组合
CSRF Token + SameSite=Lax/Strict + POST 限制 + Referer 白名单校验


如需补充:

  • 具体 CSRF PoC 示例代码
  • SameSite 属性详细对比表
  • 某框架(如 Spring、Django、Laravel)的 Token 实现方式
    随时告诉我,我继续完善!