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