Web安全——CSRF代码审计 – 作者:Snow狼啊

漏洞介绍

跨站请求攻击,简单地说,是攻击者通过一些技术手段欺骗用户的浏览器去访问一个自己曾经认证过的网站并执行一些操作(如发邮件,发消息,甚至财产操作如转账和购买商品)。由于浏览器曾经认证过,所以被访问的网站会认为是真正的用户操作而去执行。这利用了web中用户身份验证的一个漏洞:简单的身份验证只能保证请求发自某个用户的浏览器,却不能保证请求本身是用户自愿发出的

P.S:XSS与CSRF的区别:

XSS:    XSS漏洞——构造payload——发送给受害人——受害人点击打开——攻击者获取受害人的cookie——攻击者使用受害人cookie完成攻击

CSRF:  CSRF漏洞——构造payload——发送给受害人——受害人点击打开——受害人执行代码——受害人完成攻击(不知情)

攻击流程图:

图片1.png

从上图可以看出,要完成一次CSRF攻击,受害者必须依次完成两个步骤:

1.登录受信任网站A,并在本地生成Cookie。

 

2.在不登出A的情况下,访问危险网站B

如果我不满足以上两个条件中的一个,我就不会受到CSRF的攻击。是的,确实如此,但你不能保证以下情况不会发生,毕竟之前说了csrf是在不知情的情况下

1.你不能保证你登录了一个网站后,不再打开一个tab页面并访问另外的网站

2.你不能保证你关闭浏览器了后,你本地的Cookie立刻过期,你上次的会话已经结束

所以 CSRF 是一种较难防御、又危险极大的漏洞

原理(CSRF实例)

 

当我们打开或者登陆某个网站的时候,浏览器与网站所存放的服务器将会产生一个会话(cookies),在这个会话没有结束时,你就可以利用你的权限对网站进行操作。然而,攻击者就是利用这个特性,让受害者触发我们构造的表单或者语句,然后达到攻击者想要达到的目的

我们先解释下:变量 $XssReflex 获取 get 方式传递的变量名为 input 的变量值(值为一个字符串),然后直接通过echo()函数输出,注意这中间并未对用户输入进行任何过滤

建议同学们多花点时间思考一下CSRF攻击和XSS攻击原理上的区别,对比着学习会更加容易理解

我在本地搭建了一个实验环境,模拟了一个网站后台登录

图片2.png

并且密码和用户都是admin

图片3.png

一般来说后台管理员都具有添加用户的功能,所以登录成功之后点击添加用户(这里为了方便演示,并没有让管理员自定义账户名、密码的功能,而是添加默认的账户和密码)

图片4.png这里有个添加用户,我们给他添加下

图片5.png页面空白已经添加,我们现在查看下:

图片6.png这时候如果我们记录下刚刚添加用户的网页地址,是否无论是哪个用户,只要访问这个地址就能添加用户呢?为了验证这个想法,接下来我们点击注销登录(清楚cookie信息)

图片7.png

尝试在浏览器输入之前添加用户的页面地址:www.csrf.cn/csrf/adduser.php,尝试直接添加用户,没成功,它直接跳回之前的登录页面了

为什么呢?因为adduser.php页面需要验证session信息才能执行相应操作。 所以就有人想到:“既然我们自己不能成功访问这个页面,能否在管理员不知道的情况下,欺骗他访问这个页面呢?”。 我们再次使用admin用户登陆,并新建标签页。 这时假设管理员继续访问网站 B

图片8.png

页面B上面存在攻击者事先写好的恶意链接,并诱使我们点击

再查看用户时,发现后台已经不知不觉添加上了用户

图片9.png

多了一个

这就是一次利用CSRF漏洞添加后台的实例, 只要用户(受害者)点击该链接,就完成了一次CSRF攻击,虽然用户可能本身并没有执行该操作的意图

我们现在做个对比:

正常网站:
# Create your views here.
def transfer(request):
    if request.method=='POST':
        username=request.POST.get('username')
        to_username=request.POST.get('to_username')
        monery=request.POST.get('monery')
        print(username,to_username,monery)
return render(request,'transfer.html')
输出:
<body>
<h1>正经网站</h1>
<form action="" method="post">
    <p>账户名:<input type="text" name="username"></p>
    <p>对方账户:<input type="text" name="to_username"></p>
    <p>转账金额:<input type="text" name="monery"></p>
    <input type="submit">
</form>
</body>
不正常的存在Csrf的:
#views:
def transfer(request):
    return render(request,'transfer.html')

图片10.png跳转到了添加用户的页面

漏洞防御

在服务器端防御CSRF攻击主要有四种策略

1.验证HTTP Referer 字段:根据HTTP协议,在HTTP头中有一个字段叫Referer,它记录了该HTTP请求的来源地址。在通常情况下,访问一个安全受限页面的请求必须来自于同一个网站。比如某银行的转账是通过用户访问http://bank.test/test?page=10&userID=101&money=10000页面完成,用户必须先登录bank.test,然后通过点击页面上的按钮来触发转账事件。当用户提交请求时,该转账请求的Referer值就会是转账按钮所在页面的URL(本例中,通常是以bank. test域名开头的地址)。而如果攻击者要对银行网站实施CSRF攻击,他只能在自己的网站构造请求,当用户通过攻击者的网站发送请求到银行时,该请求的Referer是指向攻击者的网站。因此,要防御CSRF攻击,银行网站只需要对于每一个转账请求验证其Referer值,如果是以bank. test开头的域名,则说明该请求是来自银行网站自己的请求,是合法的。如果Referer是其他网站的话,就有可能是CSRF攻击,则拒绝该请求。

2. 在请求地址中添加token并验证:CSRF攻击之所以能够成功,是因为攻击者可以伪造用户的请求,该请求中所有的用户验证信息都存在于Cookie中,因此攻击者可以在不知道这些验证信息的情况下直接利用用户自己的Cookie来通过安全验证。由此可知,抵御CSRF攻击的关键在于:在请求中放入攻击者所不能伪造的信息,并且该信息不存在于Cookie之中。鉴于此,系统开发者可以在HTTP请求中以参数的形式加入一个随机产生的token,并在服务器端建立一个拦截器来验证这个token,如果请求中没有token或者token内容不正确,则认为可能是CSRF攻击而拒绝该请求。

3. 在HTTP头中自定义属性并验证:自定义属性的方法也是使用token并进行验证,和前一种方法不同的是,这里并不是把token以参数的形式置于HTTP请求之中,而是把它放到HTTP头中自定义的属性里。通过XMLHttpRequest这个类,可以一次性给所有该类请求加上csrftoken这个HTTP头属性,并把token值放入其中。这样解决了前一种方法在请求中加入token的不便,同时,通过这个类请求的地址不会被记录到浏览器的地址栏,也不用担心token会通过Referer泄露到其他网站。

4. 添加验证码并验证:在表单中增加一个随机的数字或字母验证码,通过强制用户和应用进行交互,来有效地遏制CSRF攻击。

来源:freebuf.com 2020-03-21 16:24:46 by: Snow狼啊

© 版权声明
THE END
喜欢就支持一下吧
点赞0
分享
评论 抢沙发

请登录后发表评论