CSRF 真的不难懂
这几天好好总结了下 CSRF 的原理和产生的原因。
为啥要总结,因为之前老是忘记。。。之前看的时候只是云里雾里,这次写在纸面上算是加深了理解和印象。
啥是 CSRF
通过用户的登录凭证(之前已经登录过网站)在第三方网站发起请求,伪造成是用户自身发起的请求,从而达到目的。
攻击流程
- 用户登录网站 a.com,在没有退出登录(保留了登录凭证 Cookie)的情况下打开新标签页去到网站 b.com
- 网站 B 内有发到网站 A 的请求(篡改过的)
- 诱导用户在网站 B 点击以发出篡改过的请求或者打开网站 B 就直接发送请求
- 由于用户已登录,故在网站 B 发送的 A 请求会带上 A 的登录凭证(这是浏览器的设定,锅是浏览器的)
- 由于带上了 A 的登录凭证,故被篡改过的请求就被服务器认为是真实用户的请求,从而达到了攻击目的
预设条件
之前在看这块内容的时候,一直没明白为啥这个流程就成立了。这几天仔细研究了才知道那是之前学习的时候忽略一个前提条件,如果在接受这个设定的前提下,那么就很好懂了:
浏览器会自动带上所发请求的 cookie,不管当前这个请求发出方是当前站点还是其他站点。
防范思路
明白了发生的原理,那么防范的方法就呼之欲出了,只要切断这个流程中的任何一步就能够阻止跨站请求伪造的攻击了。
我总结了以下三点:
- 不通过 cookies 来做登录凭证
- 判断请求来源
- 判断是否用户发出的请求
以下是对防范思路的详细说明
不通过 cookies 来做登录凭证
那这里其实问题就转化成用什么来做登录凭证,我们可以使用 token 来达到目的。
一句话总结 token 就是服务端生成的一串随机码,通过这段随机码来达到标识用户的目的。很显然,这个 token 不能存在 cookies 里面,可以放在服务器 session 里面。前端可以放在 sessionstorage。具体步骤是:
- 用户登录,服务端校验通过生成 token 并发送给客户端
- 前端所有请求都携带 token
- 服务端校验请求中的 token 有效性
判断请求来源
攻击一般是在第三方网站发出的请求,所以我们可以通过判断请求来源来过滤掉第三方请求,从而规避攻击。那么问题来了,我们怎么判断请求是来自第三方呢?
在 HTTP 协议中,一般都会有两个 header 来标记来源域名:origin 和 referer。所以服务端可以判断这两个 header 来过滤第三方请求,但注意这个方法不是完美的,在某些浏览器下会不带有这个信息。
而关于这两个 header 的区别和不适用的情况,可能需要另开一篇文章来写,本文不做讨论了。
判断是否用户发出的请求
这个方式其实很简单,就是在页面添加验证码让用户输入,通过校验则可以判断是用户真实的操作。
只是该方法对用户不是很友好,而且也没法防范 get 请求。
写在最后
个人觉得以上方法可以根据不同情况选择使用,毕竟每个方法的实现成本不同。
另外也可以双管齐下,使用多种方案。