关于web安全测试在功能测试中的应用
- 一、安全基本概念
- 1.1实施安全评估
- 1.1.1资产等级划分
- 1.1.2威胁分析
- 1.1.3风险分析
- 1.1.4 安全方案
- 1.2 安全原则
- 二、我的安全测试模型
- 三、安全测试在功能测试中的应用
- 3.1 更改url
- 3.2 逻辑缺陷:
- 3.3 破坏流程顺序
- 3.4 接口提示信息
- 3.5页面信息检查
- 3.6cookie替换检查越权操作
- 四、总结和想说的话
写在前面
(蚌埠住了,才发现草稿箱里躺着一篇2020年写的万字长文,我都给忘了有这回事,依稀记得当初觉得没有整理很全面,就搁置了下来,这次梳理一下给发出去好了T_T,哎,拖延症都是因为完美主义啊。)
写这篇文章的起因,是因为我最近在看安全测试方面的书,所以想来记录下一些感想,这几本书是:《白帽子讲web安全》《WEB安全测试》《黑客攻防技术宝典Web实战篇》,里面关于技术方面的东西还没学会,但是我对于安全测试有了大一定的了解和思路。
安全测试其实是一个很大的范围,也需要掌握很多相关的知识和工具,针对于大部分测试人员来说,想要学习安全测试的技术栈,需要下很大的功夫和时间。
但是,安全测试的思路和想法,也一样可以用在我们手工测试和接口测试中,顺着安全测试的思路,在功能测试和接口测试里,通过安全测试的思路,来挖掘系统中的问题。
一、安全基本概念
关于安全测试的基本概念和结构,这里推荐大家看吴翰清的《白帽子讲web安全》,讲的清晰明了,我的安全测试模型也是从这本书中学到的。
1.1实施安全评估
安全评估的流程大概分为四个步骤。
1.1.1资产等级划分
资产等级划分,就是对于我们要测试的系统,确定有哪些资源、数据和信息,这些东西的重要程度做一个预估。
1.1.2威胁分析
这个地方引入了一个STRIDE模型,根据这个模型的六个方面来查找,想想看有哪些威胁。
一般来说黑客对于我们系统的攻击,一般也可以归类于这几个方面。
- Spoofing伪装(冒充他人身份)
- Tsmpering篡改(非法修改数据)
- Reputation抵赖(唯一性)
- InformationDisclosure信息泄露
- Denial of Service拒绝服务(系统可正常访问)
- Elevation of Privilege提升权限(获取未经授权的数据、操作)
这里的stride模型,用于分类不同的攻击手段;在我们头脑风暴和整理的时候,这6个方面都要考虑到。
1.1.3风险分析
这里的风险分析,也有一个模型,那就是:DREAD模型。这个模型用于分析,当我们遇到了一个威胁或者漏洞后,如何确定这个威胁会给系统带来多大的风险。
- damage protential
高:获取完全权限,执行管理员操作 ,非法上传文件。
中:泄漏敏感信息
低:泄漏其他信息 - reproducibillity
高:攻击者随意再次攻击
中:攻击者可以重复攻击,有时间限制
低:攻击者很难重复攻击 - Exploitabillity
高:初学者短期可以掌握攻击
中:熟练地攻击者才可以攻击
低:漏洞利用条件苛刻 - Affected users
高:所有用户,默认配置,关键用户
中:部分用户,非默认配置
低:极少用户,匿名用户 - Discoverability
高:漏洞明显,攻击条件容易
中:需要深入挖掘的漏洞
低:发现漏洞非常困难
当我们发现了一个漏洞后,可以用这个模型来量化漏洞的风险程度,例如我们把高中低分别用:3、2、1的分值来规定,此时我们的漏洞威胁具体有多高,是可以用分数来计算的;从0~15分不等,这样我们遇到安全的bug后,可以根据这个方法来确定优先级。
1.1.4 安全方案
方案用于在我们发现漏洞后,选择修复方案时需要考虑的问题,针对开发同学,在找到漏洞原因后,修复bug的时候,要考虑下面几点事情:
- 能够有效解决问题
- 用户体验好
- 高性能
- 低耦合
- 易于扩展与升级。
1.2 安全原则
关于安全原则,就是在我们设计安全方案时,需要遵守的一些原则。
- Secure By Default原则
这个是指的是,在设计安全方案时,可以考虑使用白名单和黑名单的方式,来进行数据过滤;
例如注册时的密码设置,就可以使用白名单的方式来进行校验,而一些接口校验可以使用黑名单,来过滤一些xss注入脚本。 - 最小权限原则
顾名思义,最小权限指的是我们的系统不要过度授权。例如我们的后台账号只留有admin账号有所有权限,平时使用已经分配部分权限的其他后台账号;
针对系统中的用户权限、后台权限、数据库权限、运营权限分配等等,都要考虑到最小权限原则,一个是防止恶意操作或者是误操作,二是万一账号信息泄露失窃,可以将损失降到最低。 - 纵深防御原则Defense inDepth
这个是指,针对一个负责的系统来说,每个层面的防御措施是不一样的,不能指望一个防御措施可以一劳永逸,例如前端代码、后端代码、服务器、数据库、网络等,这些组成一个系统的环节,每个环节都有着自己的安全防御措施。 - 数据与代码分离原则
数据分离这个概念,一开始在学习编程的时候,都会接触到,就是逻辑代码和数据是分开的,连代码也要使用MVC区分逻辑层、控制层;这样的思想也要运用在我们的系统设计里。
常见的是在前端代码里,例如XSS攻击的根本原因就是通过把用户的输入数据,当做了html代码执行,混淆了数据与代码。举个最简单的xss例子,如果用户输入了一个数据<script>alert("123")</script>
,这个数据写入到了html页面后,被当成了js语句来执行,这就是一个xss攻击漏洞。 - 不可预测性原则
这个还是挺常见的,也是很容易被忽略的一个点。例如我们的用户id、商品id,都是通过递增来生成的,这就使得我们可以推测别人的ID等信息,通过这个id信息很可能就会泄漏更多的信息,攻击脚本也会很容易写。
如果我们采用随机的方式生成用户所使用的ID,就能保护用户的数据,也能防止一些攻击手段,增加攻击的门槛难度。
二、我的安全测试模型
在我做了文章开始提到的那三本书的思维导图后,我尝试把它们融合到一起,因为几本书的知识点、结构都不太一样,我就总结了一个安全思路模型,把这三本书的结构整理到了一起,我同样也可以根据这个模型的思路,来分析安全问题。
看起来复杂,其实是挺简单的,就是我们在遇到一个安全问题、或者案例、技术,通过这个思路(目的-行为-原因-方案),从用例编写到事故处理,都有相应的方案。
- 目的:首先看这个漏洞会达成什么样的效果,参考STRIDE模型,看能利用这个漏洞用来挖掘信息、提升权限、篡改还是拒绝服务。
- 行为:然后看如何实现,是用的什么工具,如何操作的,具体的每一个步骤,用来复盘攻击。
- 原因:接下来分析,这个漏洞是到底为什么发生,对应到系统中,是数据库的问题、还是前端的、后端的、甚至是公司的管理方式有问题,然后根据风险分析的DREAD模型,来评估风险等级。
- 方案:最后的话,就是针对这个漏洞,需要用什么样的解决方案,此时就要根据安全原则的指导来修复这个漏洞。
三、安全测试在功能测试中的应用
这里我要说下,这里的功能测试主要针对那些做手工测试的人员,可以不使用专门的工具,仅根据浏览器上的一些操作,用安全测试的思路来挖掘漏洞。
下面举几个安全相关的例子。
3.1 更改url
3.1.1信息泄露
在浏览器的url地址栏里,显示的是当前页面地址,有些url里带有参数,例如图片里哔哩哔哩的个人空间,后面的数字就是代表个人的一个id,如果修改数字后访问,就会进入到别人的个人空间,当然bilibili的个人空间是公开访问的,所以能进入别人的空间是正常现象。
但,要注意的是,有些页面只能自己访问,如果能通过更改url参数后访问他人的私密数据,那这个行为就属于信息泄漏和越权了;这个漏洞曾经发生过多次,例如某航空网站订单信息查看、某网站管理后台不登录直接进入后台页面,提醒我们测试时要多注意url地址和参数导致的信息泄露。
3.1.2信息篡改
不仅仅有私密数据查看越权行为,也涉及到修改和删除操作,如果在修改和删除页面的url中,关键的信息例如:user_id、passWord等作为请求字段放在url中,而且后端接口没有做限制的时候,那就可能能任意篡改别人的数据,所以在测试时候遇到url带参数的,记得要校验一下。
例如网易邮箱曾经有过一个漏洞,就是在绑定密保手机的时候,url里有uid和手机号字段,如果把uid替换成你想要黑掉的用户uid,手机号换成自己的,此时发送请求后收到验证码回填,就会把你自己的手机绑定为别人账号的密保手机,此时就可以走忘记密码的流程,重设密码,然后就成功登陆别人的邮箱了。
3.2 逻辑缺陷:
这个我认为是在功能测试中比较重要的点,逻辑缺陷一般也都是相当重要的漏洞,关于这些漏洞一般是产品设计缺陷或者代码设计没有考虑到造成的;这就需要我们测试人员有足够的敏锐度,下面举几个逻辑缺陷的例子:
3.2.1密码找回
密码找回漏洞可谓是经久不衰的一个问题,我们要在用户的方便和安全之间有一个平衡点,里面的核心问题就是证明你是你,所以有了密保手机、身份证号、密保问题、邮箱等方式来证明身份,但是如果你的信息泄露、或者是熟人知道你的部分信息,那账号就会有一定的风险。
举一个几年前支付宝找回密码漏洞的例子,支付宝在找回密码时,有一个不用手机验证码的选项,此时可以选择:最近购买的商品、可能认识的人,这个来作为校验,如果是熟人可能会知道答案,陌生人的话靠猜也有一定的几率通过测试。
后来支付宝给出了补丁更新:只有账号人自己的手机可以不用验证码来找回密码,其他手机不能选择这个选项。
3.2.2薅羊毛:
在网上有一群人,他们叫做羊毛党,每当网站上面有漏洞、活动、或者是商家操作失误从而有利可图时,他们就会蜂拥而上,哪怕是几分钱也会吸引他们;比如网站注册新用户有现金奖励,他们就批量注册用户,然后转账提现,本来网站搞这个活动是为了吸引人气,结果大部分资金被羊毛党拿走了。
再有一个薅羊毛的例子就是京东的双叠加优惠漏洞,在京东商品的页面,有促销和领卷(也就是有些商品参加了多个优惠活动),例如你一个商品有满2件以上五折,再加上有满199减100的优惠券,此时叠加后可能出现最后用几块钱甚至0元,买到200块钱定价的东西。
薅羊毛的原因有:逻辑漏洞、代码漏洞、客户操作失误等,所以我们互联网平台在产品设计和代码设计的时候,需要我们多思考,特别是跟商品金钱挂钩的功能,如何防范恶意的操作,例如要在提现、用户真实性等多个方面做限制,与网络羊毛党斗智斗勇。
3.2.3限制性功能:
限制型功能就是指,有些功能可以限制用户的行为、权限;例如我们知道银行的app登录,当输入错误密码超过5次,会将账户锁定24小时,如果我们的系统有类似的功能,就会有恶意限制他人账户的行为发生。有一个例子就是,有一个系统有秒杀活动,其中一个人将其他报名用户的账号全部恶意锁定,结果这个人直接秒杀拍到了商品,就是利用了这个规则恶意竞争。
3.3 破坏流程顺序
在一般的业务流程中,是按顺序来执行的,例如我们下面这个购物流程,要通过下单、支付、物流、确认这个顺序才可以完成一笔交易。
3.3.1下游状态执行上游操作
例如我们的订单在下单的时候有取消操作,而在物流环节没有这个操作;我们可以尝试在物流环节发送取消操作,看是否能直接取消订单。如图所示,我们可以在下单的时候保留当前页面不进行操作,而是复制一个页签,在另一个页签来进行流程操作;此时就可以在订单流转到一个下游状态的时候,返回之前的页面进行上游状态的操作。
3.3.2上游状态执行下游操作
我们如果使用接口的形式,那不仅仅可以在下游状态时执行上游状态的操作,也可以在上游状态时,进行下游状态的操作(这个需要我们对于测试系统的接口有一定了解);例如我们在没有支付的时候,直接运行确认完成接口, 来判断系统对于订单状态是否有限制,如果没有限制的话,可能会直接跳过支付和物流直接完成订单。
下面举例如何使用浏览器实现此操作,首先我们使用火狐浏览器来打开页面,然后按下F12按键调出开发者工具,然后点击网络页签,此时我们就可以监控当前浏览器的所有请求,如果页面请求太多的话,可以在右侧选择类型进行筛选。
然后我们进行业务操作,如果我们要抓取‘完成’操作,首先打开F12开发者工具,进入网络监控栏里,然后在页面进行完成操作。然后就看到我们刚才发送的那个请求,然后选中这条请求,右键调出菜单,选择编辑并重发就能进入到接口编辑页面。
这个时候我们观察并且分析这个接口,发现请求的主体非常的简单,只有token、id和state三个字段,其中token是用户的登录标识,state是我们要更新的状态,我们这个接口执行的是完成操作,所以完成的状态码应该就是3了,id就是我们当前的订单/商品id。
那么我们分析好这个接口之后,只需要获取到另外一个订单的id,通过监控抓包、观察url等方式获取到,然后我们再修改id替换为新订单的id后发送,就等于在订单生成时直接进行完成操作。
这其实已经是接口测试的方式了,只不过我们用了火狐浏览器自带的工具,来完成了本该是用postman等接口测试工具才来做的事情。
3.4 接口提示信息
如图所示,目前这个系统在登录的时候我随便填了一个手机号和验证码,页面提示了这样一个信息,这不就暴露了系统里谁注册了,谁没注册嘛。所以这里存在两个问题,第一个问题是:应该先校验验证码;第二个问题是:不应该提示手机号是否已注册。
我们单从信息的保密性来看,一个平台上手机号号码是否注册这样的信息,不应该让普通用户知道,那我如果有心渗透平台,那么根据平台提示的信息,完全可以通过批量发送接口等手段,获取到当前平台上所有的注册用户。
所以我们在一个系统中的提示信息,也要有安全的考量,目前这个例子我们完全可以换一个稍微模糊一点的提示,例如“您输入的验证码或手机号错误”,这样就不会暴露手机号是否已经注册这样的敏感信息。
3.5页面信息检查
页面信息检查大概有以下几点,第一是看前端页面代码中是否有敏感信息,第二是看页面是否有sql注入和xss注入等漏洞,第三是看接口是否返回了明文敏感信息。关于如何检查前端代码,
3.5.1页面敏感信息。
在一个成熟的开发流程中,会有代码审查阶段,如果遇到前端代码和后端代码中有敏感信息等不规范的代码,一般都会在审查阶段发现并被更改掉;当我们的代码审查不规范时,那么前端开发在代码中不小心写入了敏感信息,就会被发布到系统中。
如果我们要检查前端页面敏感信息的话,要使用浏览器中的开发者工具,按下F12后,在elements栏里,可以看到前端代码,然后我们可以点击检查或者使用ctrl+f查找例如:管理员账号、密码、内网地址等一些关键信息是否存在。
3.5.2xss注入与sql注入:
SQL注入是对于后端代码的注入漏洞,xss注入针对的则是前端代码的注入漏洞,核心原因是没有对于特殊字符进行过滤,使得用户的输入恶意数据,变为了代码逻辑的一部分;现如今随着前端框架和后端框架的技术发展,大部分的注入漏洞已经被框架所拦截,但是我们仍然需要知道注入漏洞的原理,以便维护老框架和发现新框架中未曾发现的漏洞。
sql注入例子:
例如我们的平台有一个商品列表搜索输入框存在注入漏洞,那我们在这里输入一个:'or 1=1 #
然后点击搜索,此时可能会在页面显示出平台所有的商品信息,这就是一个sql注入的漏洞了。
原理就是,我们后端查询数据库时,假如执行的sql语句是:
select * from mall_goods where goods_name = '传递的入参' and goods_type = 1
,
那当我们输入'or 1=1 #
时,这个sql就变成了了:
select * from mall_goods where goods_name = ''or 1=1 # ' and goods_type = 1
`
等价于:
select * from mall_goods where 1=1
`
也就是说#把后面的语句注释掉了,并且查询条件变成了1=1,直接把整个表的数据查了出来。
xss注入例子:
xss注入大致分为:反射型、存储型、dom型,这里不展开说每种之间的区别以及相似之处了,先举一个探寻漏洞的例子。
例如有一个信息展示页面:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>测试</title>
</head>
<body>
<div>
<span >用户姓名:</span>
<span>张三</span>
</div>
</body>
</html>
此时我们的姓名栏是用户输入数据后的回显,如果用户输入恶意的数据会怎么样呢,例如下面的代码,用户输入了一段js语句,此时回显在页面上后,发现页面已经执行了这段js语句。
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>测试</title>
</head>
<body>
<div>
<span >用户姓名:</span>
<span ><script>alert("123")</script></span>
</div>
</body>
</html>
这里就存在一个xss漏洞,js作为一门完整的语言,在页面有一个执行入口时,会发挥非常大的作用。例如js代码可以获取到浏览器的cookie、可以模拟用户执行操作,控制用户浏览器执行ddos攻击等等。
对于这种攻击手段来说,没有一劳永逸的解决方法,例如在xss速查表里,有不同思路的xss攻击代码,例如:通过js便签样式、字符编码、大小写结合、其他标签(src、iframe、Action)的一些属性、通过过滤、嵌套、绕过等手段实现攻击目的。所以xss如果要深入学习的话,细节还是挺多的,所以想要在我们测试的系统中做xss方面的检测,学习成本和性价比我觉得不是很高。
3.5.3接口敏感信息:
检查接口敏感信息的话,同样也需要使用到浏览器自带的开发者工具。首先按下F12,然后在network栏中(火狐浏览器是网络栏),可以看到页面的接口信息,在确定网络监控开关:recording开启状态,然后刷新页面或者执行操作,此时就可以看到接口的相关信息。
此时在preview里查看格式化的返回信息,一般的敏感信息可能会是登录、支付、个人信息页面等地方暴露的可能性大一些,包括用户user_id、明文密码、等等,需要多加注意,特别是密码字段,暴露出来后不管是加密过的还是明文,安全风险都很高。
3.6cookie替换检查越权操作
在3.1更改url的章节里,已经讲了如何仅通过更改url来进行越权操作,这里要换一种方式来更高效的手段来检查是否越权;
首先对于越权的原理要有所了解,越权是因为后台的接口程序没有对于用户身份进行校验,也就是对于当前接口操作的数据,归属的用户、和发起操作的用户的,是否是同一个用户。导致了用户A可以通过接口查看和修改用户B的信息。
一般平台在登录过后都有一个cookie值,标记了当前登录用户的身份,通过这个cookie来确定当前登录的用户在线。
如果我们后端是通过cookie来确定用户状态和权限,那么在这个流程中,有两个需要注意的点。
①:用户的状态和操作是不是连续的。
②:当前cookie用户的数据操作权限。
举一个例子,假如我租了一个套三的一间房子,那么房东会给你两把钥匙,一个是大门的钥匙,一个是房间的钥匙。我们的系统用户就是租户,在这套房子拥有自己的一个房间,我们在房间里的东西属于我们自己,但是别人房间的东西不能看,也不能拿。
cookie就是我们的大门钥匙,有了cookie只是代表我们可以进门了,但是我们要检查一下,别人的房间有锁吗?如果有,我们的钥匙可以打开别人的房间吗?
根据这个思路,我们要使用浏览器自带的接口编辑工具,或者postman等软件,进行接口的越权测试,除了我们的唯一标识cookie不变以外,尝试将接口入参的数据改成其他用户的,看系统能否处理成功。
四、总结和想说的话
在功能测试中,加入安全测试的思路。首先在编写测试用例的时候,考虑STRIDE模型的六个方面:也就是伪装、篡改、抵赖、信息泄露、拒绝服务、提升权限,其中我个人认为篡改、信息泄露、提升权限在功能测试中最有帮助。
测试过程中,除了能在浏览器上操作的点点点,会接触到接口测试工具,对于我们功能测试来说,也是后续接触接口测试和性能测试的一个入口,在我看来,测试的第一核心就是我们的测试思想,所有的测试工具都应该给测试思想服务。
最后我想说,关于测试,我们需要自己总结出一个适合自己的模型,遇到测试任务了,可以直搬出这个模型来,很方便也很全面。平时也多总结和扩展思维,不管是看测试相关的书籍,还是在网上看到其他平台的测试事故,都对我们测试工作有帮助。例如我在文章中举得:支付宝、京东、网易的事故例子,都是宝贵的经验和思路。