总结一下 CSRF 跨站请求伪造

958 阅读3分钟

CSRF 真的不难懂

这几天好好总结了下 CSRF 的原理和产生的原因。

为啥要总结,因为之前老是忘记。。。之前看的时候只是云里雾里,这次写在纸面上算是加深了理解和印象。

啥是 CSRF

通过用户的登录凭证(之前已经登录过网站)在第三方网站发起请求,伪造成是用户自身发起的请求,从而达到目的。

攻击流程

  1. 用户登录网站 a.com,在没有退出登录(保留了登录凭证 Cookie)的情况下打开新标签页去到网站 b.com
  2. 网站 B 内有发到网站 A 的请求(篡改过的)
  3. 诱导用户在网站 B 点击以发出篡改过的请求或者打开网站 B 就直接发送请求
  4. 由于用户已登录,故在网站 B 发送的 A 请求会带上 A 的登录凭证(这是浏览器的设定,锅是浏览器的)
  5. 由于带上了 A 的登录凭证,故被篡改过的请求就被服务器认为是真实用户的请求,从而达到了攻击目的

预设条件

之前在看这块内容的时候,一直没明白为啥这个流程就成立了。这几天仔细研究了才知道那是之前学习的时候忽略一个前提条件,如果在接受这个设定的前提下,那么就很好懂了:

浏览器会自动带上所发请求的 cookie,不管当前这个请求发出方是当前站点还是其他站点。

防范思路

明白了发生的原理,那么防范的方法就呼之欲出了,只要切断这个流程中的任何一步就能够阻止跨站请求伪造的攻击了。

我总结了以下三点:

  • 不通过 cookies 来做登录凭证
  • 判断请求来源
  • 判断是否用户发出的请求

以下是对防范思路的详细说明

不通过 cookies 来做登录凭证

那这里其实问题就转化成用什么来做登录凭证,我们可以使用 token 来达到目的。

一句话总结 token 就是服务端生成的一串随机码,通过这段随机码来达到标识用户的目的。很显然,这个 token 不能存在 cookies 里面,可以放在服务器 session 里面。前端可以放在 sessionstorage。具体步骤是:

  1. 用户登录,服务端校验通过生成 token 并发送给客户端
  2. 前端所有请求都携带 token
  3. 服务端校验请求中的 token 有效性

判断请求来源

攻击一般是在第三方网站发出的请求,所以我们可以通过判断请求来源来过滤掉第三方请求,从而规避攻击。那么问题来了,我们怎么判断请求是来自第三方呢?

在 HTTP 协议中,一般都会有两个 header 来标记来源域名:originreferer。所以服务端可以判断这两个 header 来过滤第三方请求,但注意这个方法不是完美的,在某些浏览器下会不带有这个信息。

而关于这两个 header 的区别和不适用的情况,可能需要另开一篇文章来写,本文不做讨论了。

判断是否用户发出的请求

这个方式其实很简单,就是在页面添加验证码让用户输入,通过校验则可以判断是用户真实的操作。

只是该方法对用户不是很友好,而且也没法防范 get 请求。

写在最后

个人觉得以上方法可以根据不同情况选择使用,毕竟每个方法的实现成本不同。

另外也可以双管齐下,使用多种方案。