本文将介绍CSRF攻击以及防范CSRF的常见方法
一、什么是CSRF攻击
1.1 背景
CSRF(Cross-site request forgery),中文名称:跨站请求伪造。即盗用者盗用你的身份,发送恶意请求。虽然听起来与XSS攻击方式很像,但实际上差别很大。XSS利用的是站点内的信任用户,通过信任用户身份进行恶意攻击,而CSRF则是通过伪装来自受信任用户的请求来利用受信任的网站。
1.2 造成的危害
- 利用受害人身份发送恶意邮件、短信
- 利用受害人身份进行交易转账
- 盗取受害人账号等
1.3 攻击原理
从图中可以知道CSRF的攻击流程:
- 用户登录正常网站A
- 登录成功后,用户根据网站A的响应产生Cookie
- 用户在登录登出网站A的情况下,又打开了一个新网页,去访问危险网站B
- 危险网站被打开后,要求用户浏览器给正常网站A发送http请求
- 由于从用户浏览器访问正常网站A会自动带上Cookie,故正常网站A无法识别到这个请求是用户正常发出的,还是危险网站B要求用户发出的。故正常网站A会执行这次操作。这样就可以模拟用户进行危险操作
1.4 CSRF攻击的特点
- 攻击一般发起在第三方网站,而不是被攻击的网站。被攻击的网站无法防止攻击发生。
- 攻击利用受害者在被攻击网站的登录凭证,冒充受害者提交操作;而不是直接窃取数据。
- 整个过程攻击者并不能获取到受害者的登录凭证,仅仅是“冒用”。
- 跨站请求可以用各种方式:图片URL、超链接、CORS、Form提交等等。部分请求方式可以直接嵌入在第三方论坛、文章中,难以进行追踪。
CSRF通常是跨域的,因为外域通常更容易被攻击者掌控。但是如果本域下有容易被利用的功能,比如可以发图和链接的论坛和评论区,攻击可以直接在本域下进行,而且这种攻击更加危险。
1.5 CSRF攻击是如何避开同源策略的?
可能小伙伴们就很好奇了,CSRF攻击是如何避开同源策略,去访问A站的。
Cookie是根据浏览器访问的域名决定的,若用户已经成功登录了www.tomtest.com,则保存了www.tomtest.com对应的Cookie值,若危险网站B模仿用户,向www.tomtest.com请求,由于请求的域名是一致的,故也会带上之前设好的Cookie
由于script、img、iframe不受同源策略的限制,可以通过者三种方式加载www.tomtest.com的地址,浏览器也会带上Cookie
二、常见的CSRF攻击方式
2.1 GET类型的CSRF攻击
现象:
假设某银行网站A以GET请求来发起转账操作,转账的地址为
http://www.xxx.com/transfer.do?accountNum=l000l&money=10000
参数accountNum表示转账的账户,参数money表示转账金额。
而某大型论坛B上,一个恶意用户上传了一张图片,而图片的地址栏中填的并不是图片的地址,而是前而所说的转账地址:
<img src="http://www.xxx.com/transfer.do?accountNum=l000l&money=10000">
当你登录网站A后,没有及时登出,这时你访问了论坛B,不幸的事情发生了,你会发现你的账号里面少了10000块。
原因:
在成功登录银行A后,你的浏览器端会生成银行A的cookie并存储在浏览器中,而当你访问论坛B的时候,页面上的<img>标签需要浏览器发起一个新的HTTP请求,以获得图片资源,当浏览器发起请求时,请求的却是银行A的转账地址www.xxx.com/transfer.do?accountNum=l000l&money=10000
,并且会带上银行A的cookie信息,结果银行的服务器收到这个请求后,会以为是你发起的一次转账操作,因此你的账号里边便少了10000块
2.2 POST类型的CSRF攻击
现象:
实际上,绝大多数网站都不会通过GET请求的方式来处理做逻辑处理,而是通过POST请求的方式进行。
POST型CSRF攻击,就是利用正常网站的XSS漏洞,通过XSS攻击的方式注入恶意脚本代码,并通过恶意脚本代码模拟用户操作,提交表单给其他网站。
结合上例,假设银行将其转账方式改成POST提交,而论坛B恰好又存在一个XSS漏洞,恶意用户在它的页面上植入如下代码:
<form id="aaa" action="http://www.xxx.com/transfer.do" metdod="POST" display="none">
<input type="text" name="accountNum" value="10001"/>
<input type="text" name="money" value="10000"/>
</form>
<script>
var form = document.forms('aaa');
form.submit();
</script>
如果你此时恰好登录了银行A,且没有登出,当你打开上述页面后,脚本会将表单aaa提交,把accountNum和money参数传递给银行的转账地址http://www.xxx.com/transfer.do
,同样的,银行以为是你发起的一次转账会从你的账户中扣除10000块。
原因:
通过XSS攻击注入恶意脚本,在正常网站B中,向银行网站A发送http请求,由于访问的网站相同,故请求会带上之前已经存好的Cookie,服务器无法识别出者是用户的正常请求还是被操纵发出的请求。
三、CSRF防御方式
3.1 尽量使用POST,限制GET
通过上例可知,GET请求可以避开同源策略,直接请求到服务器,若使用GET请求的通信方式来处理数据,无疑大大降低了网络攻击的难度
3.2 token 验证
CSRF攻击的本质是通过窃取用户的Cookie信息,模拟正常操作。我们可以在用户登录后,服务器专门生成一个用户的Token并返回给用户。用户获取Token后存储在盗用者拿不到的地方,如参数内,每次请求都带上这个Token,服务器校验通过才能正常使用。
1) 在POST请求参数中加入token
用户打开页面并发起登录请求时,服务器判断用户登录成功,给这个用户生成一个Token并返回给用户,该Token通过加密算法对数据进行加密,一般Token都包括随机字符串和时间戳的组合。
用户每次进行POST请求,都要增加一个参数token,并填入服务器传回的token。
服务器接收到请求后,首先验证token是否正确和是否过期,若验证通过则可视为安全请求
2)表单提交时附带token
对于GET请求,Token将附在请求地址之后,这样URL 就变成 http://url?token=tokenvalue。
而对于 POST 请求来说,要在 form 的最后加上:
<input type=”hidden” name=”csrftoken” value=”tokenvalue”/>
这样,就把Token以参数的形式加入请求了。
3.3 做好XSS攻击防范
CSRF攻击也可能通过被感染了XSS攻击恶意代码的网站进行间接攻击,故网站做好XSS攻击防范十分必要。具体防范措施有:
- 设置Cookie HttpOnly为true
- 前后端使用合适的转义库
- 纯前端渲染
- 谨慎使用html内容拼接
具体可见: 前端安全(一)XSS攻击原理及防范
3.4 Referer Check
Referer Check在Web最常见的应用就是“防止图片盗链”。同理,Referer Check也可以被用于检查请求是否来自合法的“源”(Referer值是否是指定页面,或者网站的域),如果都不是,那么就极可能是CSRF攻击。
但是因为服务器并不是什么时候都能取到Referer,所以也无法作为CSRF防御的主要手段。但是用Referer Check来监控CSRF攻击的发生,倒是一种可行的方法。
3.5 验证码
通过强制用户与网站进行交互,才能发出请求。通常验证码能很好遏制CSRF攻击,但是出于用户体验考虑,验证码只能在一些特殊场景下使用,故不能作为一个主要的防范手段
3.6 CSRF防范方式对比
防范方式 | 优势 | 劣势 | 难易度 |
逻辑请求尽量用POST请求 | 有效降低XSS攻击和CSRF攻击的威胁 | 易 | |
token验证(推荐) | 公认最有效的CSRF防御方式,可与其他防御方式共同使用。同时可以通过token控制用户登录时效、单点登录等功能 | 需要前后端共同开发 | 中 |
做好XSS攻击防范 | 有效降低XSS攻击和CSRF攻击的威胁 | 易 | |
Referer Check | 部分情况获取不到Referer值 | 中 | |
验证码 | 强制要求人机互动,能有效防御CSRF攻击 | 只能用在特定场景,如登录、注册、转账等 | 中 |
参考链接:
感谢大佬们的无私分享
CSRF攻击原理及防御:https://zhuanlan.zhihu.com/p/46306239
如何防止CSRF攻击:https://tech.meituan.com/2018/10/11/fe-security-csrf.html