Web界面的模糊测试。报告笔录





今年年初,Tenzor在伊凡诺沃市举行了一次聚会,在那儿我作了关于界面模糊测试的实验的演示。这是这份报告的笔录。



猴子何时会取代所有质量检查?是否可以放弃手动测试和UI自动测试,而将其替换为模糊测试?对于一个简单的TODO应用程序,完整的状态和转换图会是什么样?一个实现的示例以及这种模糊测试如何进一步发挥作用。



你好!我叫Sergey Dokuchaev。在过去的7年中,我一直在Tenzor进行各种形式的测试。







我们有400多人负责我们产品的质量。其中60个涉及自动化,安全性和性能测试。为了支持成千上万的E2E测试,监视数百页的性能指标并确定工业规模的漏洞,您需要使用在战斗中经过测试和时间测试的工具和方法。







而且,通常,他们在会议上谈论这种情况。但是除此之外,还有许多有趣的事情仍然难以在工业规模上应用。很有意思,让我们谈谈。







在电影《黑客帝国》的其中一个场景中,莫菲斯要求尼奥选择红色或蓝色药丸。托马斯·安德森(Thomas Anderson)是一名程序员,我们记得他所做的选择。如果他是一个臭名昭著的测试员,他会吃光这两个平板电脑来查看系统在非标准条件下的运行情况。



手动测试和自动测试相结合已成为几乎标准。开发人员最清楚其代码的工作方式并编写单元测试,功能测试人员检查新功能或频繁更改的功能,所有回归都用于各种自动测试。



但是,在创建和维护自动测试时,突然没有太多的自动测试,并且进行了大量的手动工作:



  1. 您需要弄清楚要测试什么以及如何进行测试。
  2. 您需要找到页面上的元素,将必要的定位符驱动到页面对象中。
  3. 编写和调试代码。
  4. — . / , , ROI .






幸运的是,测试世界中没有两三块平板电脑。以及整个过程:语义测试,形式方法,模糊测试,基于AI的解决方案。甚至更多的组合。







关于将在打字机上无限长地键入任何猴子都能够提前键入任何给定文本的说法,也停留在测试中。听起来不错,我们可以让一个程序在随机的位置不断点击屏幕,最终我们可以找到所有的错误。







假设我们制作了一个TODO并要对其进行测试。我们采用合适的服务工具,看到猴子在行动:







按照同样的原则,我的猫以某种方式躺在键盘上,以某种方式不可挽回地破坏了演示文稿,不得不再次这样做:







当执行10次操作后,应用程序引发异常时,这很方便。在这里,我们的猴子立即了解到发生了错误,并且从日志中我们至少可以大致了解到错误如何重复发生。如果在随机点击10万次后出现错误并且看起来像是有效的响应,该怎么办?这种方法的唯一显着优点是最大程度的简化-只需按一下按钮就可以完成。







这种方法的反面是形式方法。







这是2003年纽约的照片。时代广场是地球上最明亮,最拥挤的地方之一,只有过往车辆的车头灯照亮。那年,由于级联电厂的关闭,加拿大和美国的数百万人被困在石器时代持续了三天。发生此事件的关键原因之一是软件中的竞赛条件错误。



关键错误系统需要一种特殊的方法。不依赖于直觉和技能,而是依赖于数学的方法被称为形式。并且与测试不同,它们使您可以证明代码中没有错误。与编写应测试的代码相比,创建模型要困难得多。它们的使用更像是在有关微积分的讲座中证明一个定理。







幻灯片显示了以TLA +语言编写的两次握手算法模型的一部分。我认为对每个人来说显而易见的是,在现场检查模具时使用这些工具相当于制造一架波音787来测试玉米植株的空气动力学特性。







即使在传统上容易出错的医疗,航空航天和银行业中,也很少使用这种测试方法。但是,如果以百万美元或人类生命来计算任何错误的代价,这种方法本身是不可替代的。



现在,最经常在安全测试的上下文中查看模糊测试。我们从OWASP指南中获得了一个演示这种方法的典型方案







在这里,我们有一个需要测试的站点,有一个包含测试数据和工具的数据库,我们将使用这些数据库将指定的数据发送到该站点。向量是根据经验获得的普通字符串。这样的字符串最有可能导致漏洞的发现。就像引号一样,许多人会自动替换地址栏中URL中的数字。







在最简单的情况下,我们有一个接受请求的服务和一个发送请求的浏览器。考虑改变用户的出生日期的情况。







用户输入一个新日期,然后单击“保存”按钮。请求以json格式的数据发送到服务器。







如果一切正常,则服务将以百分之二百的代码响应。







以编程方式使用json方便,我们可以教我们的模糊工具在传输的数据中查找和确定日期。并且他将开始为它们替换各种值,例如,它将传送一个不存在的月份。







并且,如果作为响应,我们收到了异常消息,而不是有关无效日期的消息,那么我们将纠正错误。



使API模糊化并不困难。在这里,我们在json中具有传输的参数,在这里,我们发送请求,接收响应并对其进行分析。那GUI呢?



让我们再次看一下虚拟测试示例中的程序。在其中,您可以添加新任务,标记为已完成,删除并查看购物篮。







如果处理分解,我们将看到接口不是单个整体,它还包含单独的元素:







每个控件对我们来说无能为力。我们有一个带有两个按钮,滚轮和一个键盘的鼠标。您可以单击一个元素,将鼠标光标移到该元素上,然后可以在文本字段中输入文本。



如果我们在文本字段中输入一些文本并按Enter,那么我们的页面将从一种状态转到另一种状态:







示意图可以如下所示:







从该状态可以通过向列表添加另一个任务来进入第三种状态:







并且可以删除添加的任务,返回到第一种状态:







或单击题词TODO并保持在第二种状态:







现在让我们尝试实现这种方法的概念验证。







要使用浏览器,我们将使用chromedriver,将通过NetworkX python库使用状态和转换图,并通过yEd进行绘制。







我们启动浏览器,创建一个图实例,其中两个顶点之间可以有许多不同方向的连接。然后我们打开我们的应用程序。







现在我们必须描述应用程序的状态。由于采用了图像压缩算法,我们可以将PNG图像的大小用作状态标识符,并通过__eq__方法将其与其他状态进行比较。通过iterated属性,我们记录所有按钮均已单击,在此状态下已将值输入所有字段,以排除重新处理。







我们编写了一个基本算法,它将绕过整个应用程序。在这里,我们修复了图形中的第一个状态,在循环中,我们单击了此状态中的所有元素并修复了结果状态。接下来,选择下一个未处理状态并重复步骤。







当模糊当前状态时,我们必须每次都从一个新状态返回到该状态。为此,我们使用nx.shortest_path函数,该函数将返回一系列元素,这些元素需要单击才能从基本状态转换为当前状态。

为了等待应用程序对我们动作的响应结束,wait函数使用Network Long Task API,该函数显示JS是否忙于任何工作。



让我们回到我们的应用程序。初始状态如下:







在应用程序进行十次迭代之后,我们将获得以下状态和转换图:







在22次迭代后,如下所示:







如果我们运行脚本几个小时,它将突然报告它已绕过所有可能的状态,并收到下图:







因此,使用一个简单的演示应用程序我们做到了。如果在真实的Web应用程序上设置此脚本,会发生什么。而且会出现混乱:







不仅在后端发生更改,而且在对计时器或事件作出反应时页面本身会不断重绘,当执行相同的操作时,我们可以获得不同的状态。但是即使在这样的应用程序中,您也可以找到我们的脚本无需重大修改即可处理的功能。

让我们进行测试VLSI认证页面







并为此迅速建立了状态和转换的完整图:











太好了!现在,我们可以遍历应用程序的所有状态。纯粹从理论上讲,找出与操作有关的所有错误。但是,您如何教一个程序了解它前面有一个错误?



在测试中,始终将程序的响应与某种称为oracle的标准进行比较。它们可以是技术规范,模型,程序类似物,过去的版本,测试人员的经验,正式要求,测试用例等。我们还可以在我们的工具中使用其中一些预言。







让我们考虑最后一个模式“之前有所不同”。自动测试用于回归测试。



经过10次TODO迭代后,让我们回到图表:







让我们打破负责打开购物车的代码并再次运行10次迭代:







然后比较两个图并找出状态差异:







我们可以总结这种方法:







就目前而言,该技术可用于测试小型应用程序并识别明显或回归错误。为了使该技术能够用于具有不稳定GUI的大型应用程序,需要进行重大改进。

所有源代码和使用过的材料的列表都可以在存储库中找到:https : //github.com/svdokuchaev/venom对于那些想了解模糊测试在测试中的使用的人,我强烈推荐The Fuzzing Book在其中的一部分中,描述了模糊简单html表单的相同方法。






All Articles