CSRF攻防

 · 2 mins read

浏览器虽然有同源策略的限制,但是为了增加灵活性,又允许页面加载任意第三方资源,而且通过CORS(跨域资源共享),站点又可以实现跨域获取数据。允许页面加载任意第三方资源给了XSS攻击可乘之机,而CORS又为CSRF攻击创造了条件。

概念

CSRF全称Cross-site request forgery,翻译过来就是跨站请求伪造。通过名称就可以知道,这种攻击就是第三方站点伪造目标站点(被攻击站点)的请求来发起攻击,那么怎么个伪造法呢?

攻击方法

攻击步骤是这样的:

1.用户登录目标站点(被攻击站点)并在浏览器保存了登录信息(如cookie、session等);

2.用户点击黑客的链接或者访问黑客站点;

这么讲未免太抽象,不好理解,下面举例说明。

假设我这个博客网站有登录和钱包功能,而且还有付费内容,用户可以充值到自己的钱包以用于消费。而且还有转账功能,用户可以给好友转账,因此有一个转账接口:

// 接口路径
https://z0nka1.github.io/transfer

// 参数
toUser
howMuch

这时黑客可以利用这个接口,把用户钱包的money转到自己名下:

黑客有三种方法可以达到目的。

方法一

引诱用户点击链接。

比如黑客在这个博客的某篇文章的评论区写道:

<a href="https://z0nka1.github.io/transfer?toUser=hacker&howMuch=1000">高清美女私房写真,速戳</a>

这样,某些抵挡不住诱惑的小伙伴就把自己钱包的money转给黑客了。

方法二

第二种方法是,自动get请求:

黑客在一个站点(比如www.hacker.com)放了这么一段代码:

<img src="https://z0nka1.github.io/transfer?toUser=hacker&howMuch=1000" />

然后用户在浏览器保存着https://z0nka1.github.io/登录状态的情况下访问www.hacker.com,浏览器会把它当做普通的图片资源下载,从而请求https://z0nka1.github.io/transfer?toUser=hacker&howMuch=1000这个路径,这样,用户的钱包的money就被转到黑客名下了。

方法三

第三种方法是,自动post请求:

跟方法二一样,黑客在www.hacker.com(这里只是举例哈)放了一段代码,只不过这次换为:


<!DOCTYPE html>
<html>
<body>
  <form id='hacker-form' action="https://z0nka1.github.io/transfer" method=POST>
    <input type="hidden" name="toUser" value="hacker" />
    <input type="hidden" name="howMuch" value="1000" />
  </form>
  <script> document.getElementById('hacker-form').submit(); </script>
</body>
</html>

当用户访问www.hacker.com这个站点,上面表单就会被自动提交,从而把1000块钱从用户账户钱包转到黑客账户的钱包。

说完了攻击方法,我们再来看看如何防范这种类型的攻击。

如何防范

方法一:sameSite

既然这种攻击需要用到登录信息,那我们就在登录信息上下手。

cookie是一个非常重要的登录信息,cookie有一个属性:sameSite,这个属性有三个值:

1.strict。如果sameSite设置为这个值,就表示这个cookie只能用于该站点,任何第三方站点的任何请求都不能携带该cookie。例如前面举的例子,如果这个博客的登录信息的cookie设置了sameSite=strict,那么第三方站点请求转账接口都不会携带该cookie,这样自然无法实施攻击。

2.lax。这个相对宽松一些,从第三方站点的链接打开和从第三方站点提交 Get 方式的表单这两种方式都会携带cookie。但如果在第三方站点中使用 Post 方法,或者通过 img、iframe 等标签加载的URL,这些场景都不会携带cookie。

3.none。设为这个值时任何情况都会携带该cookie。

方法二:Referer和Origin

HTTP请求头带着Referer和Origin属性,标记一个请求的来源。区别是Referer包含具体URL路径,而Origin只包含域名。这样服务器可以根据这两个值来判断一个请求的来源,从而过滤掉某些站点的请求。

方法三:CSRF token

因为CSRF攻击不像XSS,它不能获取目标站点页面数据,所以可以利用这一点,在服务器端生成一个token,然后返回给页面并植入在页面中。在页面请求服务器的时候就把这个token带上,这样服务器就可以根据这个token来判断是否是可信任的了。

好了,以上就是这篇文章的全部内容了,感谢阅读!