最后一次,搞懂CSRF攻击!
完整阅读本文大约需要5分钟。
开始阅读之前,先上一道面试题:
CSRF攻击和XSS攻击之间,有什么联系?
什么是CSRF攻击
CSRF攻击即Cross-site request forgery,跨站请求伪造,直白来说就是恶意网站伪装成用户,向被害网站发起操作请求。
为了方便理解,做了一张图,攻击流程如下:
-
用户登录受害网站,浏览器把获取的身份凭证保存在本地cookie中; -
用户被诱导打开黑客网站,黑客网站向受害网站服务器发起一个恶意请求,由于cookie的取用规则,这时浏览器会自动带上第一步中的身份凭证; -
受害网站服务端对恶意请求校验,发现有身份凭证,恶意请求被成功受理;
如果黑客的操作是将用户的钱转到自己的账户,那么这时,他已经卷款跑路了。
如何发起CSRF攻击
-
诱导用户跳转到黑客网站,网站的HTML中有一个自动提交的隐藏表单,只要用户打开页面,就会发起转账请求;
<form action="http://bank/transfer" method=POST>
<input type="hidden" name="account" value="user" />
<input type="hidden" name="amount" value="10000" />
<input type="hidden" name="for" value="hacker" />
</form>
<script> document.forms[0].submit(); </script>
-
在受害网站的评论区放置一个a标签,点击跳转时发起伪造请求;
<a href="http://bank/transfer?amount=10000&for=hacker" taget="_blank">
大八卦
<a/>
-
在受害网站的评论区发表伪装的图片,实际是一个恶意请求,浏览过评论区的用户都会被黑客攻击;
![风景图](http://bank/transfer?amount=10000&for=hacker)
怎么预防CSRF攻击
CSRF攻击有两个特点:
-
CSRF攻击的来源通常是黑客网站(外域),因为更好控制; -
CSRF攻击无法获取用户的身份凭证,只能是冒用;
所以可以想到以下几个方法:
检验请求来源
HTTP 请求头中有两个字段会标识请求的来源:origin
和referer
。这两个字段不受前端控制,会诚实地告诉服务器请求来自哪里。
origin是请求来源的域名部分,但是在302重定向、以及IE11上不会显示。
所以还需要referer
辅助,它是一个完整的url路径,但可靠性不如origin
。
SameSite cookie
CSRF攻击能成功,正是所有向受害网站发起的请求,都会被自动带上cookie。
Chrome意识到这个问题后起草了一份协议:向浏览器注入cookie时,开发者可以标注哪些请求才会带上。
被标注为strict的cookie只有本域的请求才能带上。
被标注为lax的cookie在跳转到新页面时可以带上。因为如果全部设置为strict,在百度搜索并打开淘宝,默认是没有登录的,用户体验会很差。
CSRF Token
在本站发起的请求中,加一个攻击者无法获取的token,也可以区别出正常请求和恶意请求。这个token和浏览器自动携带的cookie不一样,是需要前端手动带上的。
但这种方案对服务器压力较大,需要维护一个session对收到的token做校验。
双重cookie
相较于与token,双重cookie不需要服务器做额外扩容。只需要在请求中加一个额外的字段,其值和cookie一致。因为上文提到过,攻击者没法获取到cookie,只是在发起请求时会携带。
在服务端收到请求时,如果没有和cookie值一样的额外字段,就可以认为是来自恶意网站。
其他通用方式
CSRF攻击大多来自第三方网站,但就像上文提到过的链接跳转和图片伪装,本站的请求也可能造成威胁。所以我们还需要对UGC内容做一些过滤。
-
当前用户打开其他用户填写的链接时,需告知风险; -
不直接使用用户上传的图片,先在自己的服务器转存;
结语
回到开头提出的问题:
XSS攻击的核心是注入代码,获取用户信息;CSRF攻击的核心是借助身份凭证,伪装用户发起操作请求。
两者往往是前后出现的:黑客会先通过XSS攻击获取到用户的身份凭证,上传到黑客网站,然后就可以利用它伪装成用户,发起操作请求。