跨站请求伪造(CSRF)示例、原理及其防御措施

199 阅读2分钟

文章目录

概述

CSRFCross 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大厂面试官】,一起学习呗🍎🍎🍎

img