• 0
  • 0
分享

在《基于Django的电子商务网站设计》这本书中,我不仅介绍了如何利用Django框架搭建电子商务网站,也论述了如何利用python的requests类对所创建的电子商务产品进行接口测试。在书写极乐口测试代码过程中,我遇到的最大的困难就是如何通过测试程序绕过Django的防止CSRF攻击的插件,通过近一个多月的努力我终于解决了这个问题,但是同时也揭露了Django框架的防止CSRF攻击的插件的漏洞。首先我们来看一下什么是CSRF攻击。


1、什么是CSRF攻击?

我们假设一个网站http://www.a.com/login.html的HTML代码如下:

<html>
<head>
</head>
<body>
<h4>用户登录</h4>
<form name="form" action=" /login/">
<p>用户名:<input id="name" type="text" maxlength="50"></p>
<p>密码:< input id="password" type="password" maxlength="50"></p>
<p>验证码:<img src="/images/csr.jpg"></p>
< input id="submit" type="submit" value="提交">
</body>
</html>

大家都知道,采用验证码的目的是为了防止"黑客",利用机器来通过穷举的方法来试图登录系统。检查验证码是否正确用的往往是前端做的判断。这样,"黑客"可以采用自己的网站建立如下页面:

<html>
<head>
</head>
<body>
<h4>用户登录</h4>
<form name="form" action="http://www.a.com/login/">
<p>用户名:<input id="name" type="text" maxlength="50"></p>
<p>密码:< input id="password" type="password" maxlength="50"></p>
< input id="submit" type="submit" value="提交">
</body>
</html>

大家可以看见,在这段代码中验证码没有了,form的action变成了绝对路径http://www.a.com/login/,这样"黑客"就绕过了前端的验证,可以对自己代码进行编写自动化脚本实现用穷举的方法来试图登录系统。这个就是CSRF攻击。


2、Django的CSRF插件是如何解决CSRF攻击的

下面让我们来看一下Django的CSR插件是如何解决CSRF攻击的。Django利用了一个名为django.middleware.csrf.CsrfViewMiddleware的中间件(可以在Django的settings.py中设置)利用CSRF令牌的方式来控制。具体方式生成一个一百个字符的随机字符串作为CSRF令牌,在login表单中产生一个名为csrfmiddlewaretoken的hidden表单,把这个CSRF令牌的值放入这个字段中,然后在提交这个表单的时候产生一个名为csrftoken的cookie,这个cookie的值也是CSRF令牌的值。

<html>
<head>
</head>
<body>
<h4>用户登录</h4>
<form name="form" action="http://www.a.com/login/">
<input type='hidden' name='csrfmiddlewaretoken' value='Pxpy5PDU3i1imqd0XZrK4ct6pZRIknHT48UE60GRrKtmqW7UCPq66pddXp0fzTpx' />
<p>用户名:<input id="name" type="text" maxlength="50"></p>
<p>密码:< input id="password" type="password" maxlength="50"></p>
< input id="submit" type="submit" value="提交">
</body>
</html>

后台检查如果hidden表单的值与csrftoken的cookie的值一致,则返回200返回码,进入登录后的页面,否则返回403返回码,拒绝进入系统。由于这个CSRF令牌是随机生成的一百个字符的字符串,"黑客"是很难猜到这个字符的,所以就达到了CSRF的攻击防护。


3、Django的CSRF插件的漏洞

3.1通过requests类破解

但是这个CSRF插件是有漏洞的,在页面login.html页面载入后,黑客可以通过某种手段(比如正则表达式)获得这个CSRF令牌(即hidden中的一百个字符值),然后构造一个名为csrftoken的cookie,名为刚才过的的CSRF令牌值,这样就有了下面的代码。

import requests
…
#进入登录页面
try:
data = requests.get(self.Login_url)
except Exception as e:
print(e)
text = data.text
csrf_token = str(re.findall(r"name=\'csrfmiddlewaretoken\' value=\'(.+?)\' />",text))
csrf_token = csrf_token[2:-2]
payload ={"username":"cindy","password":"123456","csrfmiddlewaretoken":csrf_token}
cookies = {"csrftoken":csrf_token}
try:
data = requests.post(self.Product_list_url,data=payload,cookies=cookies)
except Exception as e:
print(e)

代码"csrf_token = str(re.findall(r"name=\'csrfmiddlewaretoken\' value=\'(.+?)\' />",text))"是通过re.findall正则方法获得CSRF令牌,存在csrf_token变量中,由于用这个方法获得的值是"["CSRF令牌值"]"格式的,也就是说去前面多了个"["",后面多了个""]",所以后面用语句"csrf_token = csrf_token[2:-2]"过滤出来,然后利用requests的post方法,先构造post参数:"payload ={"username":"cindy","password":"123456","csrfmiddlewaretoken":csrf_token}",这里""csrfmiddlewaretoken":csrf_token"让表单csrfmiddlewaretoken仍旧为csrf_token值。通过cookies = {"csrftoken":csrf_token}构造cookes值,通过cookies=cookies作为post参数传给后台。这样表单csrfmiddlewaretoken的值与cookie的csrftoken值是一致的,所以,登录通过。

后来,我惊奇的发现不用这么麻烦,我们直接把表单csrfmiddlewaretoken的值与cookie的csrftoken值设置相同,即:

csrf_token = csrf_token = "Pxpy5PDU3i1imqd0XZrK4ct6pZRIknHT48UE60GRrKtmqW7UCPq66pddXp0fzTpx"
payload ={"username":"cindy","password":"123456","csrfmiddlewaretoken":csrf_token}
cookies = {"csrftoken":csrf_token}
try:
data = requests.post(self.Product_list_url,data=payload,cookies=cookies)
except Exception as e:
print(e)

3.2通过selenium框架破解

下面的代码是利用selenium做基于GUI的自动化测试代码。

def test_CheckLogin(self):
…
self.driver.find_element_by_id(,"id_username").clear()
self.driver.find_element_by_id("id_username").send_keys(username)
self.driver.find_element_by_id("id_password").clear()
self.driver.find_element_by_id("id_password").send_keys(password)
csrftoken = self.driver.find_element_by_name("csrfmiddlewaretoken").get_attribute("value")
self.driver.add_cookie({"name":"csrftoken","value":csrftoken})
self.driver.find_element_by_class_name("form-signin").submit()
…

代码通过csrftoken = self.driver.find_element_by_name("csrfmiddlewaretoken").get_attribute("value")获取表单csrfmiddlewaretoken的值,通过elf.driver.add_cookie({"name":"csrftoken","value":csrftoken})把这个值放入到名为csrftoken的cookies中。

3.3通过JMeter破解

在JMeter也可以破解,如下图:

通过正则表达式提取器获取login.html中的hidden值。


把获得的值放入名为csrftoken的cookie中


把获得的值仍旧作为csrfmiddlewaretoken表单参数传给后台处理。

3.4通过LoadRunne破解

在LoadRunner中,录制完毕,脚本就直接把csrfmiddlewaretoken表单参数作为名为csrftoken的cookie传给后台,不用做任何代码修改。正是不可思议。

web_add_cookie("csrftoken=D7rghfxcDXMOPlz1txbY5KigHQJasLoW0cilXmpONF87D64JM2eb2qKULO4zGc8Z; DOMAIN=192.168.0.106");
…
web_submit_data("login_action",
"Action=http://192.168.0.106:8000/login_action/",
…
"Name=csrfmiddlewaretoken", "Value=D7rghfxcDXMOPlz1txbY5KigHQJasLoW0cilXmpONF87D64JM2eb2qKULO4zGc8Z", ENDITEM,
"Name=username", "Value={username}", ENDITEM,
"Name=password", "Value={password}", ENDITEM,
LAST);


版权声明:本文出自51Testing原创,51Testing软件测试网及相关内容提供者拥有内容的全部版权,未经明确的书面许可,任何人或单位不得对本网站内容复制、转载或进行镜像,否则将追究法律责任。


  • 【留下美好印记】
    赞赏支持
登录 后发表评论
+ 关注

热门文章

    最新讲堂

      • 推荐阅读
      • 换一换
          •   为了回馈广大用户对51Testing软件测试网的支持,我们准备了一份价值398元的测试实战课程礼包,只需填写下方链接的行业调查问卷即可免费领取~ 链接:http://vote.51testing.com/   随着公司微服务体系服务越来越多,业务增长越来越迅速,版本迭代越来越快,而且对系统的可用性要求越来越高,传统的手工发布系统的方式已经完全无法满足日常运维的需求了,自动化构建发布的需求越来越强烈,但是自动化发布有个基础的环境,自动化测试,鉴于团队规模不大,测试人员的能力参差不齐,自动化测试我们选择了以开发测试一起搭建的方式,通过轻量级的工具postman进行自动化测试。  测试文件共享 ...
            1 1 1867
            分享
          •   智能手机原始设备制造商将设计外包给其他公司的做法非常普遍。 这通常更多的是针对经济型和低端手机的智能手机制造商。 最近的一份报告显示了哪家公司出货量最大。  根据Counterpoint Research的报告,在 2024 年上半年的外包设计出货量中,摩托罗拉位居榜首。 紧随摩托罗拉之后的是中国智能手机品牌小米,其 78% 的手机都是外包设计。 包括 VIVO、华为、HONOR 和 OPPO 集团在内的中国同行也排在同一序列。  在主要厂商中,韩国智能手机 OEM 厂商三星是采用自主设计的Android品牌中占比最高的。 2024 年上半年,三星智能手机出货量中的 ODM 产品占比为 2...
            0 0 170
            分享
          •   前言  随着汽车工业的发展,汽车各系统的控制逐步向自动化和智能化转变,汽车电气系统变得日益复杂。传统的电气系统大多采用点对点的单一通信方式,相互之间少有联系,这样必然会形成庞大的布线系统。  据统计,一辆采用传统布线方法的高档汽车中,其导线长度可达2000米,电气节点可达l5 00个,而且该数字大约每10年就将增加1倍。这进一步加剧了粗大的线束与汽车上有限的可用空间之间的矛盾。无论从材料成本还是工作效率看,传统布线方法都不能适应现代汽车的发展。  另外,为了满足各电子系统的实时性要求,须对汽车公共数据(如发动机转速、车轮转速、节气门踏板位置等信息)实行共享,而每个控制单元对实时性的要求又各...
            0 0 2138
            分享
          •   我们发现了一个bug后,怎样去确定这个bug是应该前台来解决还是后台来解决?  当然我们测试网站的时候,可以通过浏览器的F12来查看传值,那么如果测试的是APP,我们又该怎么来抓取这个数据呢?这里就需要用到一些抓包工具,来协助我们定位问题。  这里我们使用的工具就是Fiddler。  下面我们通过几个案例来具体说明一下如何通过Fiddler来定位是前台的问题还是后台的问题。  案例1  我们在使用手机APP的时候,修改一个联系人信息,修改之后发现在数据库里的信息电话和性别没有修改成功,这个时候我们用Fiddler来抓取数据包看看。  首先先将Fiddler设置成只接收远程客户端的数据,如下...
            13 14 2400
            分享
          • 一、支付分类首先,根据不同维度,我们可以把支付分为不同的种类。如下图所示:其次,一般来讲,线上支付分为两种消费模式。一种是直接支付金额,如淘宝,京东等购物网站,或是360云盘,视频会员等这种会员服务;另一种是充值购买金豆之类的虚拟币,在网站中使用虚拟币进行消费,比如游戏平台、花椒等产品。二、测试方法功能测试:通过将边界值分析、等价类划分、错误推测、因果图等各种测试方法进行结合,整理出尽可能全面的测试案例,对支付功能及其相关功能进行测试,以确保整个支付流程以及涉及到支付流程的其他流程在任何情况下都能正常进行。接口测试:明确整个支付流程所需要调用的接口,分清楚商家和第三方支付平台的接口以及参数和请...
            2 6 2334
            分享
      • 51testing软件测试圈微信