CSRF 是什么
CSRF(Cross Site Request Forgery) 跨站请求伪造。也被称为 One Click Attack和Session Riding,通常缩写为 CSRF 或 XSRF。如果从名字你还不不知道它表示什么,你可以这样理解:攻击者(黑客,钓鱼网站)盗用了你的身份,以你的名义发送恶意请求,这些请求包括发送邮件、发送消息、盗取账号、购买商品、银行转账,从而使你的个人隐私泄露和财产损失。
你这可以这么理解 CSRF 攻击:攻击者盗用了你的身份,以你的名义发送恶意请求。CSRF 能够做的事情包括:以你名义发送邮件,发消息,盗取你的账号,甚至于购买商品,虚拟货币转账……造成的问题包括:个人隐私泄露以及财产安全。
CSRF原理
下图简单阐述了 CSRF 的原理:
从上图可以看出,要完成一次 CSRF 攻击,受害者必须依次完成以下两个步骤:
- 登录受信任网站A,并在本地生成 Cookie。
- 在不登出 A 的情况下,访问危险网站 B。
看到这里,你也许会问:”如果我不满足以上两个条件中的一个,我就不会受到 CSRF 攻击”。是的,确实如此,但是你不能保证以下情况不会发生:
- 你不能保证你登录了一个网站之后,不再打开一个 tab 页面并访问其它的网站(黄网)。
- 你不能保证你关闭浏览器之后,你本地的 Cookie 立刻过期,你上次的会话已经结束。
- 上述中所谓的攻击网站,可能就是一个钓鱼网站或者黄色网站。
CSRF 攻击的对象
在讨论如何抵御 CSRF 之前,先要明确 CSRF 攻击的对象,也就是要保护的对象。从以上的例子可知,CSRF 攻击是黑客借助受害者的 cookie 骗取服务器的信任,但是黑客并不能拿到 cookie,也看不到 cookie 的内容。另外,对于服务器返回的结果,由于浏览器同源策略的限制,黑客也无法进行解析。因此,黑客无法从返回的结果中得到任何东西,他所能做的就是给服务器发送请求,以执行请求中所描述的命令,在服务器端直接改变数据的值,而非窃取服务器中的数据。所以,我们要保护的对象是那些可以直接产生数据改变的服务,而对于读取数据的服务,则不需要进行 CSRF 的保护。比如银行系统中转账的请求会直接改变账户的金额,会遭到 CSRF 攻击,需要保护。而查询余额是对金额的读取操作,不会改变数据,CSRF 攻击无法解析服务器返回的结果,无需保护。
CSRF 如何防御
1、验证 HTTP Referer 字段
根据 HTTP 协议,在 HTTP 头部中有一个 Referer 字段,它记录了该 HTTP 请求所在的地址,表示 HTTP 请求从那个页面发出的。
这种方法的好处就是简单易行,只需要在后台添加一个拦截器来检查 Referer 即可。然而这种办法并不是万无一失,Referer 的值是由浏览器提供的,一些低级的浏览器可以通过某种方式篡改 Referer 的值,这就给了攻击者可乘之机;而一些高级浏览器处于安全考虑,可以让用户设置发送 HTTP 请求时不再提供 Referer 值,这样当他们正常访问支付宝网站时,因为没有提供 Referer 值而被误认为 CERF 攻击,拒绝访问。实际应用中通常采用第二种方法来防御 CSRF 攻击。
2、添加 token 验证
CSRF 攻击之所以能够成功,是因为攻击者可以完全伪造用户的请求,该请求中所有的用户验证信息都存在 cookie 中,因此攻击者可以在不知道这些验证信息的情况下直接利用用户自己的 cookie 来通过安全验证。要防止CSRF,关键在于在请求中放入黑客所不能伪造的信息,并且该信息不存在于 cookie 之中。可以在HTTP请求中以参数的形式加入一个随机产生的 token,并在服务器建立一个拦截器来验证这个 token,如果请求中没有 token 或者 token 不正确,则认为可能是 CSRF 攻击而拒绝该请求。
现在业界一致的做法就是使用 Anti CSRF Token 来防御 CSRF。
- 用户访问某个表单页面。
- 服务端生成一个 Token,放在用户的 Session 中,或者浏览器的 Cookie 中。
- 在页面表单附带上 Token 参数。
- 用户提交请求后,服务端验证表单中的 Token 是否与用户 Session(或 Cookies)中的 Token 一致,一致为合法请求,不是则非法请求。
这个 Token 值必须是随机的,不可预测的。由于 Token 的存在,攻击者无法再构造一个带有合法 Token 的请求实施 CSRF 攻击。另外使用 Token 应注意 Token 的保密性,尽量把敏感操作由 GET 改成 POST,以 form 或者 AJAX 形式提交,避免 Token 泄露。
3、验证码
验证码,强制用户必须与应用进行交互,才能完成最终请求。通常情况下,验证码能够很好的遏制 CSRF 攻击。但是出于用户体验考虑,网站不能给所有的操作都加上验证码。因此验证码只能作为一种辅助手段。
4、尽量使用 POST,限制 GET
GET 接口能够直接将请求地址暴露给攻击者,所以要防止 CSRF 一定最好不要用 GET。当然 POST 并不是万无一失,攻击者只需要构造一个 form 表单就可以,但需要在第三方页面做,这样就增加了暴露的可能性。
5、在 HTTP 头部添加自定义属性
这种方法也是使用 token 并验证,但是它是把 token 放在 HTTP 请求头部中。通过使用 AJAX 我们可以在我们的请求头部中添加我们的自定义属性,但是这种方法要求我们将整个站的请求全部改成 AJAX,如果是新站还好,老站的话无疑是需要重写整个站点的,这是很不可取的。
扩展阅读
前端安全系列(二):如何防止CSRF攻击?
CSRF 攻击的应对之道 - IBM
https://www.cnblogs.com/hyddd/archive/2009/04/09/1432744.html https://www.jianshu.com/p/855395f9603b
- 本文作者: Alvin
- 本文链接: https://alvinyw.github.io/2019/12/2/
- 版权声明: 本博客所有文章除特别声明外,均采用 MIT 许可协议。转载请注明出处!