浅谈CSRF攻击
一、CSRF是什么
CSRF(Cross-Site Request Forgery),中文名称为“跨站请求伪造”,也被称为“one-click attack”或“session riding”,通常缩写为CSRF或XSRF。
二、CSRF可以做什么
CSRF 攻击可以理解为:攻击者盗用了你的身份,以你的名义发送恶意请求。
通过 CSRF,攻击者可以以受害者的身份发送邮件、发消息、盗取账号,甚至购买商品或进行虚拟货币转账,可能导致个人隐私泄露和财产损失。
三、CSRF漏洞现状
CSRF 攻击方式在2000年由国外安全专家提出,但在国内直到2006年才引起关注。2008年,多个国内外大型社区和网站如纽约时报、Metafilter、YouTube、百度HI等先后暴露出 CSRF 漏洞。
目前,许多网站对 CSRF 仍缺乏足够的防护,安全业界称其为“沉睡的巨人”。
四、CSRF的原理
以下图示阐述了 CSRF 攻击的基本思想:
要完成一次 CSRF 攻击,受害者必须满足以下两个条件:
- 登录受信任网站A,并在本地生成Cookie。
- 在不登出A的情况下,访问危险网站B。
如果不满足以上任一条件,你可能不会受到 CSRF 的攻击。但现实中,这样的情况难以避免:
- 你可能在登录网站A后,又打开了另一个网站B。
- 你可能认为关闭浏览器等同于退出登录,但事实上,Cookie 并未立即失效。
接下来,我们通过三个例子进一步说明 CSRF 攻击的具体实现。
示例1:GET 请求导致的 CSRF 攻击
假设银行网站A使用 GET 请求进行转账操作,如:http://www.mybank.com/Transfer.php?toBankId=11&money=1000
。
危险网站B包含如下 HTML 代码:
<img src="http://www.mybank.com/Transfer.php?toBankId=11&money=1000">
如果用户先登录了银行网站A,然后访问了危险网站B,会发现账户少了1000块。这是因为银行网站A使用 GET 请求更新资源,导致浏览器携带银行网站的 Cookie 发出了转账请求。
示例2:POST 请求依然导致 CSRF 攻击
银行改用 POST 请求完成转账操作,表单代码如下:
<form action="Transfer.php" method="POST">
<p>ToBankId: <input type="text" name="toBankId" /></p>
<p>Money: <input type="text" name="money" /></p>
<p><input type="submit" value="Transfer" /></p>
</form>
后台处理代码:
<?php
session_start();
if (isset($_REQUEST['toBankId']) && isset($_REQUEST['money'])) {
buy_stocks($_REQUEST['toBankId'], $_REQUEST['money']);
}
?>
然而,危险网站B仍然可以通过以下代码发起 CSRF 攻击:
<img src="http://www.mybank.com/Transfer.php?toBankId=11&money=1000">
因为 $_REQUEST
可以获取 GET 和 POST 请求的数据,这导致了攻击的成功。
示例3:JS 配合 POST 请求的 CSRF 攻击
银行改用 $_POST
只获取 POST 请求的数据,但危险网站B也做了相应调整:
<html>
<head>
<script type="text/javascript">
function steal() {
document.frames["steal"].document.Submit("transfer");
}
</script>
</head>
<body onload="steal()">
<iframe name="steal" style="display:none;">
<form method="POST" name="transfer" action="http://www.myBank.com/Transfer.php">
<input type="hidden" name="toBankId" value="11">
<input type="hidden" name="money" value="1000">
</form>
</iframe>
</body>
</html>
用户访问此页面后,仍会丢失1000块,因为 JavaScript 可以暗中发送 POST 请求。
总结:CSRF 攻击利用了 WEB 的隐式身份验证机制,即浏览器无法区分请求是否得到用户授权。
五、CSRF的特征
- 攻击通常发起于第三方网站,被攻击的网站难以防止。
- 攻击者利用受害者的登录凭证冒充其身份提交操作,而不是直接窃取数据。
- 攻击者无法获取到受害者的登录凭证,只能冒用。
- CSRF 通常是跨域的,但也可以在本域内发起更为危险的攻击。
六、CSRF的防御
CSRF 防御可以从服务端和客户端着手,但效果更好的方案是服务端防御。常用的防御策略包括:
1、同源检测
通过验证 HTTP 请求头中的 Referer
或 Origin
,确保请求来源于同一域名。这是防御 CSRF 的简单方法,但并非万无一失,尤其在子域名攻击或浏览器漏洞的情况下。
2、CSRF Token 校验
在用户请求时,附加一个攻击者无法获取的 Token,服务器校验 Token 的有效性。具体步骤:
- 生成并输出 CSRF Token 到页面。
- 请求时携带该 Token。
- 服务器校验 Token。
虽然安全性高,但实现较为复杂,需要在每个请求中添加 Token。
3、双重 Cookie 验证
通过 Cookie 和请求参数同时传递一个随机字符串,服务器对比二者是否一致。这种方法简单且易于实施,但在子域名隔离和 XSS 攻击下可能失效。
七、总结
CSRF 的防御策略包括同源检测、CSRF Token 校验和双重 Cookie 验证。结合应用场景选择适合的防御措施,可以有效提升 Web 应用的安全性。