本文作者:IMWeb 刘志龙 原文出处:IMWeb社区 未经同意,禁止转载
忙忙忙,最近事情实在有点多,赶在月底写一下系列4。
前面3个文章简单介绍了xss,后面还会继续对xss进行研究。无奈最近啥都没研究,只好先一个csrf的入门文章过渡一下。
这篇是csrf入门篇,内容比较简单,知道csrf的同学可以直接关掉页面了。
CSRF(Cross Site Request Forgery, 跨站域请求伪造)是一种网络的攻击方式,它在 2007 年曾被列为互联网 20 大安全隐患之一。
攻击者盗用了你的身份,在你不知情的情况下以你的名义发送恶意请求。CSRF能够做的事情包括:以你名义发送邮件,发消息,购买商品,虚拟货币转账,删你文章,微博等等。
看完上面介绍,我自己是没有任何收获。。还是先看个图吧。借用cnblogs某大大一个图
看看上面这个流程,经常是我们平时浏览网站经常会走的流程。简单说来,首先我们在A网站登陆了,假设A网站有csrf漏洞,然后我们不小心浏览到某个恶意网站B,然后我们就被入侵了55555。。。
上面这个流程,估计大家有可能有疑惑的应该只是步骤5或者步骤6。就是说在恶意网站B里面写一段代码,发送一个到A网站域下的请求,一样是会带上A域下的cookie。这个是浏览器的策略。这时候可能有同学冒出跨域之类的一些疑问,后面继续这个。
看完原理,估计本来不了解的同学还是没有搞懂,直接看demo。
假设我们imweb博客有个删除文章的请求有csrf的漏洞。请求http://imweb.io/cgi-bin/del?id=1
是删除id为1的文章,还是个get请求。
这时候我刚好有篇文章id=123
的,有个小伙伴觉得我这个文章写的很烂,决定偷偷删掉它,问题是这个小伙伴没有我的密码,也没有管理员权限,怎么办?
这个小伙伴敏锐的发现这个删除文章的cgi是get请求,而且居然还有csrf漏洞。。于是这个小伙伴想到办法了。写到这里我特地去试了试在imweb评论里评论一个富文本,<img src="http://test.com">
, 居然完整的出来了。。。这里实在有点危险。。这个小伙伴也机智的发现了这一点,于是他在我的文章下面评论了一条<img src="http://imweb.io/cgi-bin/del?id=123"
的评论,然后就等着我上钩了。
然后我收到邮件(imweb博客评论的通知机制)看到有人评论,我就点进去看啦。看了下发现是张挂了的图片,就没在意了。下次我再登博客,尼玛发现我之前辛辛苦苦写的id
是123
的那篇文章呢,莫名其妙就不见啦。。
看到这里大部分同学应该都知道我文章为什么不见了,原因就在于我登陆了,访问了我这篇文章,然后页面开始加载,顺便加载了那个小伙伴的评论,顺便把http://imweb.io/cgi-bin/del?id=123
请求也发了,服务器收到请求,发现还带了我的cookie,于是傻傻的认为是我要删这篇文章,就把它删了。。
整个流程非常的简单,这个小伙伴基本没费事,不过就评论了一下而已,就把我这篇坑爹的文章删了。可见get
是多么的危险,轻松杀人于无形之中。
imweb的管理员听到还有这回事,决定赶紧修补下,删除这么危险的操作还是别随便用get
了,还是改成post
好了。
某天我又发了一篇文章,id
是233
,这个小伙伴又看得很不爽,觉得尼玛这种文章也能发表。于是又像上面一样评论了一个图片,然后他发现,get
接口好像已经不行了啊,文章删不掉。怎么办?
这当然难不倒这个机智的小伙伴,他立马就想到了一个很简单的方法。类似这样的代码,不是一样可以在不知情的情况下轻松post
吗?
<form action="http://imweb.io/cgi-bin/del" method="post">
<input type="text" name="id" value="233" />
</form>
<script> document.forms[0].submit(); </script>
好的,代码写好了,这个小伙伴决定开始入侵了,他把上面这段代码跟之前一样写到我的这个文章的评论里。发现糟糕了,不行,富文本评论哪有那么傻,让你随便插入form表单还搞了个script
。这招不行,小伙伴决定换个方法,他自己写了个页面叫http://csrf.test/
,然后里面就是上面的代码,然后他诱导我说这个网址有好多美女图片。。我赶紧点进去看看,刚好这时imweb的登陆态还没失效。然后进去这个网址我发现我去什么都没有啊,被骗了,没有美女啊。却不知道我的文章又被这个小伙伴偷偷删掉了。
这个原理和上面那个get
没有太多区别,就是搞了个自动提交的表单。这时候有同学可能有疑问,在http://csrf.test
下发imweb.io
域下的请求,这不是跨域了吗,怎么还成功了?
有这个疑问的同学注意这里是表单的post,并不是ajax发的请求。表单是可以随便post的,并不受域的限制。写到这里的时候我有点疑惑了,ajax有同源策略,表单为啥不约束?
感兴趣的同学可以深入去探讨一下上面这个问题,也欢迎评论帮我解惑。因为表单post不受同源的限制,倒是给我们提供了不少跨域方案。
好吧回到正题,整个流程下来,这个小伙伴又成功删了我的文章。但是大家应该发现了,整个入侵的门槛高了很多。所以说,post
不是王道,但在这里比get
毫无疑问要更安全。
说了那么多,我写一篇文章被删一篇,难道我以后就不能写文章啦?
管理员这时候怒了,决定亮出自己三张王牌。
- referrer校验 - 验证码 - token
王牌一,referrer校验,非常简单,基本就验证一下请求referrer,合法的才给予操作。
比如下面那个post
的demo,发现请求来自http://csrf.test
,认为是非法操作,于是我的文章就没有被删了。
但是那个get
的demo,似乎防范不了?理论上referrer
校验也是可以防范get
的,只是这个demo有点特殊,不仅这个删除接口有csrf漏洞,还可以轻松评论任何src
的图片。
造成了referrer
居然是来自imweb.io
。这也是我上面说这个图片评论很危险的原因之一。甚至帮助绕过了referrer
校验。
在项目中这个王牌还是很少被用的,原因是因为referrer
的不稳定,服务端不能保证每次都可以取到referrer
(比如https跳http,还有很多办法可以模拟空referrer
)。
王牌二,验证码,这个就牛逼了,防御的滴水不漏。可惜万事有利必有其弊,你总不能发每个请求都让用户敲一次验证码吧,所以这种一般只在某些特定场景用。
王牌三,token。这个应该是现在比较通用的方案。当然token具体的生成方案就一堆了,这里举个简单的例子。
比如拿用户登录态的cookie做个编码,作为token。每次发请求时带上这个token。这个方案之所以可以原因在于,比如刚刚那个小伙伴post
入侵我的,在http://csrf.test
域是不能读imweb.io
域下的cookie的,所以就算我告诉他编码方案,他因为读不了cookie
的数据也不能入侵成功。写到这里我突然想到了一种有可能入侵imweb的csrf方案。。估计不少同学也想到而且在尝试了。可行性待验证,下篇文章说说测试结果。。
有点晚了,睡觉zzzz