文章目录
概述
CSRF是Cross Site Request Forgery的缩写,中文翻译过来是跨站请求伪造。它欺骗用户在当前已通过身份验证的Web应用程序上执行不需要的操作。在社交软件的帮助下(例如通过电子邮件或聊天发送链接),攻击者可能会欺骗Web应用程序的用户执行攻击者选择的操作。如果受害者是普通用户,则成功的CSRF攻击会迫使用户执行状态更改请求,例如转账,更改其电子邮件地址等。如果受害者是管理帐户,则CSRF可能会破坏整个Web应用程序。
例子
模拟银行转账的CSRF攻击。
大致步骤如下:
- 张三登录银行页面
- 张三转账给李四1000元
- 微信接到一个中奖通知连接(假的)
- 点击连接并在其网站点击“领奖”按钮
- 发现钱被转走了100000元。。。
前提:张三在银行网站一直处于登录状态
这里我搞了个小demo给大家演示下,全部代码在gitee上传送门
1. 张三登录银行页面
2. 张三转账给李四1000元
3. 微信接到一个中奖通知连接(假的)
4. 点击连接并在其网站点击“领奖”按钮
5. 看似点击个“领奖”按钮,实际上操作却是自己银行的钱转给【laker】100000元,裂开了
原理
我们先来看看正常的【张三】转账给【李四】
页面核心源码
<input type="text" name="amount"/>
<input type="text" name="acct"/>
$.get("http://localhost:8080/transfer", {acct: acct, amount: amount},
请求详情如下:
Request URL: http://localhost:8080/transfer?acct=%E6%9D%8E%E5%9B%9B&amount=1000
Request Method: GET
Status Code: 200
Remote Address: [::1]:8080
Referrer Policy: strict-origin-when-cross-origin
Connection: keep-alive
Cookie: JSESSIONID=2F0E89DE8B34BBAE3D4D388889681648
Host: localhost:8080
Referer: http://localhost:8080/
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.66 Safari/537.36
我们再来看看CSRF的【张三】转账给【laker】
页面核心源码
<a href="http://localhost:8080/transfer?acct=laker&amount=100000">恭喜中奖了,点我领奖!</a>
请求详情如下:
Request URL: http://localhost:8080/transfer?acct=laker&amount=100000
Request Method: GET
Status Code: 200
Remote Address: [::1]:8080
Referrer Policy: strict-origin-when-cross-origin
Connection: keep-alive
Cookie: JSESSIONID=2F0E89DE8B34BBAE3D4D388889681648
Host: localhost:8080
Referer: http://localhost:63342/
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.66 Safari/537.36
重点剖析
在这个http://localhost:63342伪造的网站上,当你点击了“领奖”按钮,实际上是发起了http://localhost:8080/transfer?acct=laker&amount=100000请求,并且会自动携带上http://localhost:8080的cookie(如上面的:Cookie: JSESSIONID=2F0E89DE8B34BBAE3D4D388889681648),为什么为自动携带呢?这是浏览器的标准,标准就是这样规定的,常用的单点登录、第三方登录都会用到这个特性。
这就是CSRF攻击的原理,利用cookie的自动携带特性,在其他的网站向你的网站发送请求,如果你的网站中的用户没有退出登录,而发送的请求又是一些敏感的操作请求,比如:转账,那么将会给你的网站的用户带来巨大的损失。
防御
使用token验证
既然CSRF的原理是使用cookie造成的,那不使用cookie就完事了,使用token放在Http hearder中去判断登录状态。
目前架构大部分都是前后端分离的,其使用的就是token验证了。
判断Referer/Origin
可以看到异常的网站其Referer是不同的
SameSite Cookie属性
谷歌提出了same-site cookies概念,same-site cookies 是基于 Chrome 和 Mozilla 开发者花了三年多时间制定的 IETF 标准。它是在原有的Cookie中,新添加了一个SameSite属性,它标识着在非同源的请求中,是否可以带上Cookie,它可以设置为3个值,分别为:
- Strict
- Lax
- None
Cookie中的内容为:
POST /transfer HTTP/1.1
Host: www.a-bank.com
Cookie: JSESSIONID=randomid;SameSite=Strict;
Strict是最严格的,它完全禁止在跨站情况下,发送Cookie。只有在自己的网站内部发送请求,才会带上Cookie。不过这个规则过于严格,会影响用户的体验。比如在一个网站中有一个链接,这个链接连接到了GitHub上,由于SameSite设置为Strict,跳转到GitHub后,GitHub总是未登录状态。
Lax的规则稍稍放宽了些,大部分跨站的请求也不会带上Cookie,但是一些导航的Get请求会带上Cookie,如下:
| 请求类型 | 示例 | Lax情况 |
|---|---|---|
| 链接 | <a href="..."></a> | 发送 Cookie |
| 预加载 | <link rel="prerender" href="..."/> | 发送 Cookie |
| GET 表单 | <form method="GET" action="..."> | 发送 Cookie |
| POST 表单 | <form method="POST" action="..."> | 不发送 |
| iframe | <iframe src="..."></iframe> | 不发送 |
| AJAX | $.get("...") | 不发送 |
| Image | <img src="..."> | 不发送 |
上面的表格就是SameSite设置为Lax的时候,Cookie的发送情况。
None就是关闭SameSite属性,所有的情况下都发送Cookie。不过SameSite设置None,还要同时设置Cookie的Secure属性,否则是不生效的。
以上就是在前端通过Cookie的SameSite属性防御CSRF攻击,不过大家在使用SameSite属性时,要注意浏览器是否支持SameSite属性。
参考:
加群一起抱团取暖,共同进步
🍎QQ群【837324215】
🍎关注我的公众号【Java大厂面试官】,一起学习呗🍎🍎🍎