CSRF 攻击简介

CSRF攻击,全称是跨站请求伪造(Cross-site request forgery),是指黑客引诱用户打开黑客的网站,在黑客的网站中,利用用户的登录状态发起的跨站请求。简单来讲,CSRF 攻击就是黑客利用了用户的登录状态,并通过第三方的站点来做一些坏事。

CSRF(跨站域请求伪造)攻击虽然只是一种极为普通的攻击方式,但是它覆盖面极广,而且大部分人防范意识薄弱,导致它流行了10多年,仍然经久不衰。
它核心思想在于,用户在打开A网站的情况下,如果在Tab页面打开了被CSRF攻击过的恶意网站B,那此时在B页面的“唆使”下,用户自身浏览器会发起一个对网站A的HTTP请求。
这么一听好像也没什么厉害的,普普通通,但是CSRF攻击最致命的一点是:这个HTTP请求不是用户的主动意图,而是B网页“唆使”的,如果是一个危害较大的请求操作(比如发邮件?删数据?伪造信息贷款?等等)那就麻烦了

其次,因为在攻击之前用户已经打开了A网站,浏览器会存有A网站下发的Cookie或其他用于身份认证的信息,这次被“唆使”的请求,将会自动带上这些信息,导致A网站后端分不清楚这是否是用户真实的意愿还是“伪请求”。
随着用户被“唆使”时间的延长,这些类似蠕虫的恶意请求会一步一步挖空你的信息,严重的可能引导A网站直接转账。
这也就不难理解为何很多被CSRF攻击到的人明明什么都没做,只是点开了链接,钱就失踪了。
当你打开手机,在搜索栏输入你想搜索的内容,按下回车的那一刻开始,你的上网信息已经汇报给网络管理者(注:属于合法行为,官方只收集你的网址,对你进行上网保护)
但并不是所有人都这么做,更多的情况是攻击者会监控你的一举一动,获取你的个人信息后转卖给某些非法组织或非法盈利机构。但这种类型的网站也很好分辨,细心的人会发现,有些网址开头是http,有些是https。

http是超文本传输协议,简单来说就是用明文的方式传输数据。
https是安全套结字层超文本传输协议,即加密传输数据。

image.png

所以当你在http开头的网站上输入支付密码、身份证号、银行卡等等重要信息的时候,攻击者通过截获明文数据,这些内容将直接泄漏给攻击者。就好比你在银行ATM机存钱的时候,输入卡号和密码的同时被ATM机明文广播。

CSRF 的攻击原理

  • 用户登录了受信任的网站,并在本地生成了 cookie。
  • 在不退出登录的情况下,访问了危险网站。
  • 危险网站会发出一个请求到受信任的网站,受信任的网站不知道请求是用户访问的还是危险网站访问的,由于浏览器会自动带上用户 cookie,所以受信任的网站会根据用户的权限处理危险网站所发出的请求,达到了模拟用户操作的目的。

CSRF 攻击方式

通常当用户打开了黑客的页面后,黑客有三种方式去实施 。
下面以转账功能为例,可以通过 POST 或 Get 来实现转账

1. 自动发起 Get 请求

黑客最容易实施的攻击方式是自动发起 Get 请求,具体攻击方式你可以参考下面这段代码:
image.png
这是黑客页面的 HTML 代码,在这段代码中,黑客将转账的请求接口隐藏在 img 标签内,欺骗浏览器这是一张图片资源。当该页面被加载时,浏览器会自动发起 img 的资源请求,如果服务器没有对该请求做判断的话,那么服务器就会认为该请求是一个转账请求,于是用户账户上的 100 币就被转移到黑客的账户上去了。

2. 自动发起 POST 请求

除了自动发送 Get 请求之外,有些服务器的接口是使用 POST 方法的,所以黑客还需要在他的站点上伪造 POST 请求,当用户打开黑客的站点时,是自动提交 POST 请求,具体的方式你可以参考下面示例代码:
image.png
在这段代码中,我们可以看到黑客在他的页面中构建了一个隐藏的表单,该表单的内容就是网页的转账接口。当用户打开该站点之后,这个表单会被自动执行提交;当表单被提交之后,服务器就会执行转账操作。因此使用构建自动提交表单这种方式,就可以自动实现跨站点 POST 数据提交。

3. 引诱用户点击链接

除了自动发起 Get 和 Post 请求之外,还有一种方式是诱惑用户点击黑客站点上的链接,这种方式通常出现在论坛或者恶意邮件上。黑客会采用很多方式去诱惑用户点击链接,示例代码如下所示:
image.png
这段黑客站点代码,页面上放了一张美女图片,下面放了图片下载地址,而这个下载地址实际上是黑客用来转账的接口,一旦用户点击了这个链接,那么他的币就被转到黑客账户上了。

以上三种就是黑客经常采用的攻击方式。如果当用户登录了网站,以上三种 CSRF 攻击方式中的任何一种发生时,那么服务器都会将金额发送到黑客账户。
到这里,相信你已经知道什么是 CSRF 攻击了。和 XSS 不同的是,CSRF 攻击不需要将恶意代码注入用户的页面,仅仅是利用服务器的漏洞和用户的登录状态来实施攻击

CSRF 的防范

1、对于 GET 的请求,我们不应对数据进行任何修改操作

2、请求时附带验证信息,比如验证码或者 token

3、对于 cookie,我们可以设置 same-site(Lax 或 Strict)来规定浏览器不能在跨域请求中携带 Cookie ,减少 CSRF 攻击

如果是从第三方站点发起的请求,那么需要浏览器禁止发送某些关键 Cookie 数据到服务器;如果是同一个站点发起的请求,那么就需要保证 Cookie 数据正常发送。
而我们要聊的 Cookie 中的 SameSite 属性正是为了解决这个问题的,通过使用 SameSite 可以有效地降低 CSRF 攻击的风险。

那 SameSite 是怎么防止 CSRF 攻击的呢?
在 HTTP 响应头中,通过 set-cookie 字段设置 Cookie 时,可以带上 SameSite 选项,如下:
image.png

  1. SameSite 选项通常有 StrictLax None 三个值。
  2. Strict 最为严格。如果 SameSite 的值是 Strict,那么浏览器会完全禁止第三方 Cookie。简言之,如果你从极客时间的页面中访问 InfoQ 的资源,而 InfoQ 的某些 Cookie 设置了 SameSite = Strict 的话,那么这些 Cookie 是不会被发送到 InfoQ 的服务器上的。只有你从 InfoQ 的站点去请求 InfoQ 的资源时,才会带上这些 Cookie
  3. Lax 相对宽松一点。在跨站点的情况下,从第三方站点的链接打开和从第三方站点提交 Get 方式的表单这两种方式都会携带 Cookie。但如果在第三方站点中使用 Post 方法,或者通过 imgiframe 等标签加载的 URL,这些场景都不会携带 Cookie
  4. 而如果使用 None 的话,在任何情况下都会发送 Cookie 数据。
  5. 对于防范 CSRF 攻击,我们可以针对实际情况将一些关键的 Cookie 设置为 Strict 或者 Lax 模式,这样在跨站点请求时,这些关键的 Cookie 就不会被发送到服务器,从而使得黑客的 CSRF 攻击失效。

4、验证 HTTP Referer 字段,判断请求来源

Referer 指的是页面请求来源。意思是只接受本站的请求,服务器才做响应;如果不是就拦截。
由于 CSRF 攻击大多来自于第三方站点,因此服务器可以禁止来自第三方站点的请求。那么该怎么判断请求是否来自第三方站点呢?
这就需要介绍 HTTP 请求头中的 Referer 和 Origin 属性。
Referer 是 HTTP 请求头中的一个字段,记录了该 HTTP 请求的来源地址。比如我从极客时间的官网打开了 InfoQ 的站点,那么请求头中的 Referer 值是极客时间的 URL,如下图:
image.png
虽然可以通过 Referer 告诉服务器 HTTP 请求的来源,但是有一些场景是不适合将来源 URL 暴露给服务器的,因此浏览器提供给开发者一个选项,可以不用上传 Referer 值,具体可参考Referrer Policy
但在服务器端验证请求头中的 Referer 并不是太可靠,因此标准委员会又制定了Origin 属性,在一些重要的场合,比如通过 XMLHttpRequest、Fecth 发起跨站请求或者通过 Post 方法发送请求时,都会带上 Origin 属性,如下图:
image.png
从上图可以看出,Origin 属性只包含了域名信息,并没有包含具体的 URL 路径,这是 Origin 和 Referer 的一个主要区别。在这里需要补充一点,Origin 的值之所以不包含详细路径信息,是有些站点因为安全考虑,不想把源站点的详细路径暴露给服务器。
因此,服务器的策略是优先判断 Origin,如果请求头中没有包含 Origin 属性,再根据实际情况判断是否使用 Referer 值。