• 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软件测试网及相关内容提供者拥有内容的全部版权,未经明确的书面许可,任何人或单位不得对本网站内容复制、转载或进行镜像,否则将追究法律责任。


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

热门文章

    最新讲堂

      • 推荐阅读
      • 换一换
          •   爱达荷国家实验室(INL)证实,在他们遭受了网络攻击后,"SiegedSec"黑客将窃取的人力资源数据泄露到网上。INL 是美国能源部管理的一个核研究中心,拥有原子能、综合能源和国家安全方面的 5700 名专家。  INL 建筑群占地 890 平方英里(2,310 平方公里),拥有 50 座实验性核反应堆,其中包括历史上第一座能够生产可用电力的反应堆和第一座为核潜艇设计的发电厂。  目前,INL 正在进行下一代核电站、轻水反应堆、控制系统网络安全、先进车辆测试、生物能源、机器人、核废料处理等方面的研究。  本周一,SiegedSec 宣布已获得 INL 数据,包括&qu...
            0 0 872
            分享
          • 【全国】博为峰51Testing企业培训,打造精品内训课程!51企业内训服务   迅速提升企业测试团队综合能力51Testing资深讲师团队走进企业,根据业务及团队实际需求,量身打造专属个性化培训课程,“专药专治”有效提升测试团队战斗力。提升测试团队能力,为软件质量保驾护航。课程体系量身定制,内容多样化,补缺团队技术短板!测试基础类:软件工程、质量和测试基础;需求开发、管理和工程;ISTQB初级(测试工程师)& 高级(测试经理);测试技术(通用课程)测试设计类:软件测试需求分析与系统测试用例设计、ISTQB高级(测试分析师)、ISTQB高级(测试技术分析师)、单元、...
            0 0 1336
            分享
          •   线上流量  什么是录制线上流量回放  为什么需要录制线上流量回放  项目大迭代更新,容易漏测,或者有很多没用评估到的地方。  如果用线上流量做一次回归测试,可以进一步减少 bug 的风险。  大大节省构造测试数据,或者构造测试数据脚本的时间,提高效率。  线上流量回放的限制是什么  · 只回放 GET 请求  因为其他请求的回放,会对用户数据进行操作,有风险,需要排除。  除非构建多套备份数据库,但成本太高,不是很有必要。  · 需要对比回放前后的流量  不然回放就没有意义了,你都不知道回放前后对比的差异是什么。  · 需要去噪音  对比完了,对于一些类似时间戳的值,其实就是噪音,这些不一...
            11 11 855
            分享
          •   大家还记得我们之前讨论过校招和社招之间的关系吗?不记得的小伙伴可以点右边蓝字复习一下:多家企业开启“报复性”校招,大厂还会频繁裁员吗?  当时我们曾说过,今后大厂应该不会再有大批裁员的行为了,论其原因大概是:大厂外包会越来越多。  当前局势  大厂分互联网大厂和金融大厂,目前以互联网大厂为例,几个头部互联网公司一边裁员,一边招聘:  甚至有人断言:大厂裁员新闻以后就看不到了。  消失不见的大厂裁员  最近有网友表示:大厂裁员新闻会越来越少,因为大厂会逐步把非核心业务转为外包,这位网友还表示:以后外包也会很稳定,并逐渐成为趋势。  根据国家人力资源社会和保障部的数据,截至2021年年底,全国...
            0 0 906
            分享
          • 记得去年这个时候,组内浩浩荡荡地做制度更新,做质量提升,还要求每个组输出落地的措施,基本上是顶着市场的压力给出承诺,并且控制市场投诉的比率和数量肉眼可见的下降。虽然辛苦,但也值得。自研和外包测试有一个很大的区别,外包的工作只需要把事情按时做完就行,但是自研的工作会让你想方设法做提升,做优化,按照优化的成果做绩效评估。所以在不同环境就做好相应的处理吧。下面就简单举个例子:一、当前的问题(线上问题分析及以往版本复盘):版本转测的时候没有整体概念,经常是后端管后端的,前端管前端的转测邮件形同虚设,没有转测意见,也没有附上自测结果修改的问题很容易影响以往老功能:参考礼品卡bug频繁,没有进行深入分析,...
            3 3 6791
            分享
      • 51testing软件测试圈微信