无需登录 数据私有 本地保存

CSRF防护概念演示 - Token验证流程

13
0
0
0

CSRF 防护概念演示

深入理解跨站请求伪造(CSRF)攻击原理与 Token 验证防护机制

CSRF 防护:
用户操作区(银行转账) 🔒 受保护
已登录用户: zhangsan@bank.com
--
Token 已嵌入表单,随请求自动提交
¥
Token 验证流程
① 用户认证
用户登录,服务器创建 Session
② 生成 Token
服务器生成随机 CSRF Token,存入 Session
③ 嵌入表单
Token 作为隐藏字段嵌入页面表单
④ 用户提交
Token 随请求一同发送到服务器
⑤ 验证 Token
服务器比对请求 Token 与 Session Token
⑥ 处理结果
匹配成功则执行操作,否则拒绝
攻击者视角(恶意站点)
用户访问了恶意网站,该网站尝试伪造转账请求

恶意网站中的隐藏表单代码:

<form action="https://bank.com/transfer" method="POST"> <input type="hidden" name="recipient" value="hacker_account"/> <input type="hidden" name="amount" value="99999"/> <!-- ⚠️ 没有 CSRF Token 字段! --> </form> <script> document.forms[0].submit(); // 自动提交 </script>
请求日志 / 验证记录
[初始化] 演示环境已就绪,CSRF Token 已生成
[系统] 用户 zhangsan@bank.com 已登录,Session 有效
常见问题与知识点(FAQ)

CSRF(Cross-Site Request Forgery,跨站请求伪造)是一种 Web 安全攻击,攻击者诱导已登录用户在不知情的情况下向目标网站发送恶意请求。

工作原理:用户登录了银行网站 A,浏览器中保有有效的 Session Cookie。此时用户又访问了恶意网站 B,网站 B 包含一个自动提交的表单,该表单指向银行网站 A 的转账接口。由于浏览器会自动携带 Cookie,银行网站 A 无法区分请求是用户自愿发起还是被伪造的,从而执行了恶意操作。

关键点:CSRF 利用的是浏览器自动携带 Cookie 的机制,以及服务器仅依赖 Cookie 验证身份的缺陷。

CSRF Token 防护的核心思想是:在请求中加入一个攻击者无法获取的随机值

具体流程:
  1. 服务器生成一个随机 Token,存储在用户 Session 中
  2. Token 被嵌入到表单的隐藏字段(或请求头)中
  3. 用户提交请求时,Token 随请求一同发送
  4. 服务器收到请求后,比对请求中的 Token 与 Session 中的 Token
  5. 匹配成功 → 请求合法,执行操作;不匹配/缺失 → 拒绝请求
为什么攻击者无法获取?同源策略阻止了恶意网站读取目标网站的页面内容,因此攻击者无法获取到嵌入在页面中的 Token 值。

特征CSRFXSS
攻击目标利用用户已登录身份执行操作窃取用户数据或劫持会话
攻击位置在第三方网站发起在目标网站注入脚本
依赖浏览器自动携带 Cookie输入验证不严格
防护方式CSRF Token、SameSite Cookie输入过滤、CSP、HttpOnly
影响范围仅能执行特定操作可完全控制用户会话
重要:如果站点存在 XSS 漏洞,CSRF Token 防护可能被绕过,因为攻击者可以通过 XSS 读取页面中的 Token。因此两种防护都需要重视。

SameSite 是 Cookie 的一个属性,用于控制 Cookie 是否随跨站请求发送。

三种模式:
  • Strict:完全禁止跨站发送 Cookie,最严格,但可能影响用户体验(如从邮件链接跳转时需要重新登录)
  • Lax(推荐):允许顶级导航(GET 请求)携带 Cookie,但不允许跨站 POST 请求携带。这是 Chrome 的默认值
  • None:允许所有跨站请求携带 Cookie,必须配合 Secure 属性使用
最佳实践:将 Session Cookie 设置为 SameSite=Lax; Secure; HttpOnly,结合 CSRF Token 使用,形成纵深防御。

存储位置:
  • 服务器端:Token 存储在用户 Session 中(服务端存储)
  • 客户端:Token 作为隐藏字段嵌入表单,或通过 meta 标签、JavaScript 变量传递给前端
  • 传递方式:可通过 POST 请求体(隐藏字段)或自定义请求头(如 X-CSRF-Token)发送
更新策略:
  • 每次请求更新:最安全但可能影响用户体验(如后退按钮)
  • 每次 Session 更新:用户登录时生成新 Token,整个会话期间保持不变
  • 定时过期:Token 设置有效期(如30分钟),过期后自动刷新
一般推荐每次 Session 生成一个 Token即可满足大多数场景,高安全性场景可每次请求更新。

检查 RefererOrigin 请求头确实可以防御部分 CSRF 攻击,但存在局限性:

局限性:
  • Referer 可能被隐藏:某些浏览器设置、代理或隐私插件会移除 Referer 头,导致合法请求被误拒
  • HTTPS→HTTP 降级:从 HTTPS 页面跳转到 HTTP 页面时,Referer 不会被发送
  • Origin 头并非总是存在:某些旧版浏览器或特定请求类型可能不发送 Origin 头
  • 可能被伪造:在某些老旧浏览器中,Referer 头可能被篡改
结论:Referer/Origin 检查可作为辅助防护手段,但不能替代 CSRF Token。推荐使用 Token 为主、Origin 检查为辅的纵深防御策略。

对于前后端分离的 SPA 应用和 RESTful API,CSRF 防护策略有所不同:

推荐方案:
  • 双重提交 Cookie 模式:服务器设置一个随机 Cookie(非 HttpOnly),前端读取该 Cookie 值并通过请求头(如 X-CSRF-Token)发送,服务器比对两者
  • 自定义请求头:使用 JavaScript 添加自定义请求头(如 X-Requested-With: XMLHttpRequest),利用跨域请求无法携带自定义头的特性
  • Bearer Token 认证:使用 JWT 等 Token 通过 Authorization 头传递,而非依赖 Cookie
关键点:如果 API 完全使用 Authorization: Bearer <token> 头进行认证,且不使用 Cookie,则天然免疫 CSRF(因为跨域请求不会自动携带 Authorization 头)。

原生移动应用(iOS/Android)通常不需要 CSRF 防护,因为:

  • 原生应用不使用浏览器 Cookie 机制,没有自动携带凭证的特性
  • 每次请求需要手动添加认证信息(Token、签名等)
  • 攻击者无法从第三方应用发起请求并自动携带用户凭证
但需要注意:
  • 如果移动端使用 WebView 加载网页,WebView 中的页面仍可能受 CSRF 影响
  • 混合应用(Hybrid App)中运行在 WebView 的部分需要防护
  • 移动端 API 应使用 Token 认证(如 JWT),天然免疫 CSRF

多层次纵深防御策略:
  1. 使用 CSRF Token:每个状态改变请求(POST/PUT/DELETE)必须携带有效 Token
  2. 设置 SameSite Cookie:Session Cookie 设置为 SameSite=LaxStrict
  3. 验证 Origin/Referer:作为辅助检查手段
  4. 使用自定义请求头:API 请求要求携带自定义头
  5. 关键操作二次确认:转账、修改密码等操作要求输入密码或验证码
  6. 合理设置 Cookie 属性:Secure; HttpOnly; SameSite
  7. 避免 GET 请求修改数据:所有数据修改操作使用 POST/PUT/DELETE
记住:没有单一完美的防护方案,纵深防御是最佳策略。

测试步骤:
  1. 登录目标网站,执行一个敏感操作(如修改密码)
  2. 使用 Burp Suite 或浏览器开发者工具抓取该请求
  3. 检查请求中是否包含 CSRF Token 或随机参数
  4. 尝试移除 Token 后重放请求,观察是否成功
  5. 尝试使用不同用户的 Token,观察是否被接受
  6. 构造一个独立的 HTML 页面模拟攻击,测试是否可跨域提交
自动化工具:OWASP ZAP、Burp Suite Professional 等工具可自动检测 CSRF 漏洞。
注意:测试前请确保获得授权,仅在合法范围内进行安全测试。