鉴源论坛 · 观模丨基于应用程序编程接口(API)的自动化测试(下)

作者 | 黄杉 华东师范大学软件工程学院博士

         苏亭 华东师范大学软件工程学院教授

版块 | 鉴源论坛 · 观模

社群 | 添加微信号“TICPShanghai”加入“上海控安51fusa安全社区”

上文“基于应用程序编程接口(API)的自动化测试(上)”中,系统介绍了应用程序编程接口(API)的概念及其在软件开发中的作用与重要性,重点分享自动化API测试的发展历程与测试对象。本文将深入剖析单元测试、模糊测试等当前主流的自动化API测试形式与技术。

04

自动化API测试形式与技术

对API进行自动化测试一般使用单元测试(Unit testing)的测试形式,这也是当下敏捷开发的重要组成部分。随着模糊测试的兴起,针对API的模糊测试(API fuzzing)成为当下流行的API测试技术。下面将从单元测试和模糊测试两部分对自动化API测试形式和技术进行介绍。

4.1 单元测试(Unit Testing)

单元测试(Unit Testing)又称为模块测试,是一种测试形式(或称测试框架),它针对程序模块(软件设计的最小单位)来进行正确性检验的测试工作。程序单元是应用的最小的测试部件。在过程化编程中,单元测试由单个API或者多个API组合完成;对于面向对象编程,单元测试由单个或者多个类的方法以及对象之间的交互操作完成。单元测试主要由开发人员手动编写(如Junit、pytest),也可以通过一些自动测试用例生成技术(如Randoop[6]、GraphFuzz[4])完成。

单元测试的一般流程为:(1)编写或生成单元测试用例,其中包含测试环境初始化、调用被测API完成相应功能、检查调用结果;(2)执行单元测试用例,收集执行结果,统计成功的测试用例和失败的测试用例,失败的测试用例表明API实现中存在错误或缺陷。无论是函数级API还是RESTful API,使用单元测试这种测试形式都十分有效。

鉴源论坛 · 观模丨基于应用程序编程接口(API)的自动化测试(下)_第1张图片

图 1 Junit单元测试示例

如图 1所示,这是一个使用Junit单元测试框架编写的Java单元测试用例。“@Test”表示该函数执行一个单元测试用例,其中首先初始化一个AdderImpl对象,并调用该对象的add方法,传入1和2这两个参数,最终判断add方法的返回结果是否为3。如果结果不为3,则该单元测试失败,表示add方法实现出错,反则成功。

4.2 API模糊测试 (Fuzz Test)

模糊测试(Fuzz test)是一种自动化测试技术,其核心组件模糊器(Fuzzer)可以基于语法规则直接生成测试用例,也可以基于已有测试用例进行编译生成测试用例。由于模糊器可以生成多样的测试用例,这些测试用例相比于开发人员编写的测试更有可能触发程序中的边界条件和更多样的测试场景,因此模糊测试在测试软件鲁棒性和软件漏洞挖掘中非常有效。

针对API的模糊测试流程和一般针对二进制程序的模糊测试流程相同:模糊器从种子库中选取种子进行变异或者直接根据语法规则生成测试用例,执行测试用例,监测执行过程并检查执行结果,当执行过程中出现崩溃或者执行结果与预期不符,则认为找到了潜在的API错误。

4.2.1 针对函数级API的模糊测试

LLVM项目中的Libfuzzer[11]是一款进程内的由覆盖率引导的进化型模糊引擎。它通过读取用户提供的种子(特定的程序输入或者API调用参数),对种子进行变异生成新的测试用例输入并传递给由用户编写的测试驱动,从而实现API模糊测试。

鉴源论坛 · 观模丨基于应用程序编程接口(API)的自动化测试(下)_第2张图片

图 2 Libfuzzer测试驱动示例

图 2是一个Libfuzzer测试驱动示例,Libfuzzer生成的测试输入将通过Data参数传入测试驱动,用户则会将该测试输入在经过适当处理后传递给被测API,从而对API进行测试。值得注意的是,在Libfuzzer的测试驱动中,开发人员同样可以编写条件检查来达到单元测试的效果。

Libfuzzer初步解决了测试输入生成,而对API的模糊测试难点在于如何触发更深层次的API行为。为了更高效地对函数级API进行测试,研究人员们对如何高效地自动化生成测试驱动进行了研究,即如何自动化地构造有效的API调用序列和API执行环境和程序片段。

FUDGE[2]是一个通过对代码切片进行合成来生成模糊测试候选驱动的工具。FUDGE的核心见解是,以有效且有用的方式执行库函数的模糊测试驱动可以通过代码库中的现有代码片段合成。FUDGE的整体流程如图 3所示,在完成模糊测试驱动生成后,FUDGE会将生成的驱动交给开发人员进行评估。

鉴源论坛 · 观模丨基于应用程序编程接口(API)的自动化测试(下)_第3张图片

图 3 FUDGE整体流程

FuzzGen[5] 利用整个系统分析来推断库的接口并专门为该库合成模糊测试驱动。FuzzGen不需要开发人员的参与,并且可以广泛应用于多种编程库。FuzzGen的核心思想是系统中的现有代码在多个方面利用编程库。如图 4所示,它从系统中已有使用库的代码出发,通过对整个系统进行分析,先确定哪些是API,再从控制流和数据流两方面整理出抽象API依赖图(A2DG)。这个过程需要确定每个参数的可能值和类型,并分析参数之间的依赖关系。最后,基于依赖图生成libFuzzer的桩代码,从而进行不需人工干预、能较好地平衡宽度和深度的模糊测试。

鉴源论坛 · 观模丨基于应用程序编程接口(API)的自动化测试(下)_第4张图片

图 4 FuzzGen的核心思想示意图

GraphFuzz[4]则是通过将整个API调用序列表示为一个数据流图,然后在数据流图中进行给定的变异操作进行API调用序列构造。图 5列举了三种GraphFuzz支持的数据流图变异操作:删除、插入和串联。

鉴源论坛 · 观模丨基于应用程序编程接口(API)的自动化测试(下)_第5张图片

图 5 GraphFuzz支持的部分变异操作

除了泛用性的针对函数级API的模糊测试方法的研究工作外,还有特别针对系统调用的模糊测试方法的研究工作,这些研究工作都着力于解决如何构造API调用能够探索更深层次的API使用场景这一挑战。

4.2.2 针对RESTful API的模糊测试

早期Chakrabarti[3]等人提出了黑盒的、基于规范的RESTful API测试方法,其中测试用例需要使用一种基于XML的可扩展测试规范语言进行手工构造。但手工构造测试用例需要较多的人工开销,后来的工作通过从OpenAPI或者Swagger规范中提取RESTful API的接口信息,从而实现了测试用例的自动化生成。

EvoMaster[8]是一个使用进化算法来生成RESTful API测试用例的基于搜索的模糊测试工具,这也是一款完全自动化的黑盒测试工具。它在测试RESTful服务内部更深层次的逻辑方面更有效,因为它可以搜集和使用有关服务目标的更多信息来指导测试用例生成。

RESTler[1]是第一个有状态基于广度优先探索的RESTful API模糊测试器。RESTler 通过分析云服务的 API 规范,生成请求序列并自动调用云服务的API对其测试。RESTler首先会通过读取Swagger接口文档(图 6给出了Swagger接口文档的示例)对API返回结果之间的依赖关系进行推断,然后生成合法的API调用序列。然后,RESTler会根据执行API调用序列过程中服务器返回的状态码来修改原有的API调用序列,使其避免生成无效的API调用序列。

鉴源论坛 · 观模丨基于应用程序编程接口(API)的自动化测试(下)_第6张图片

图 6 Swagger接口文档示例

05

总结

自动化API测试有较长的历史,其自身也在不断演化进步。针对函数级API的自动化测试在泛用方法研究的基础上,目前也出现了一些针对特殊编程语言和特殊API场景的研究,如针对Rust library和深度学习库(PyTorch、TensorFlow)的自动化测试方法研究。针对RESTful API的自动化测试也是继SOAP测试之后出现的web API测试新种类。随着软件工程技术的发展,API也在不断进化,如何根据不同API自身特点制定相对应的自动化测试方案将会是自动化API测试重点关注的核心问题。

参考文献:

[1] Vaggelis Atlidakis, Patrice Godefroid, and Marina Polishchuk. 2019. RESTler: Stateful REST API Fuzzing. In 2019 IEEE/ACM 41st International Conference on Software Engineering (ICSE), 748–758. DOI:https://doi.org/10.1109/ICSE.2019.00083

[2] Domagoj Babić, Stefan Bucur, Yaohui Chen, Franjo Ivančić, Tim King, Markus Kusano, Caroline Lemieux, László Szekeres, and Wei Wang. 2019. FUDGE: fuzz driver generation at scale. In Proceedings of the 2019 27th ACM Joint Meeting on European Software Engineering Conference and Symposium on the Foundations of Software Engineering (ESEC/FSE 2019), Association for Computing Machinery, New York, NY, USA, 975–985. DOI:https://doi.org/10.1145/3338906.3340456

[3] Sujit Kumar Chakrabarti and Prashant Kumar. 2009. Test-the-REST: An Approach to Testing RESTful Web-Services. In 2009 Computation World: Future Computing, Service Computation, Cognitive, Adaptive, Content, Patterns, 302–308. DOI:https://doi.org/10.1109/ComputationWorld.2009.116

[4] Harrison Green and Thanassis Avgerinos. 2022. GraphFuzz: Library API Fuzzing with Lifetime-aware Dataflow Graphs. In 2022 IEEE/ACM 44th International Conference on Software Engineering (ICSE), 1070–1081. DOI:https://doi.org/10.1145/3510003.3510228

[5] Kyriakos Ispoglou, Daniel Austin, Vishwath Mohan, and Mathias Payer. 2020. {FuzzGen}: Automatic Fuzzer Generation. 2271–2287. Retrieved July 5, 2023 from https://www.usenix.org/conference/usenixsecurity20/presentation/ispoglou

[6] Carlos Pacheco, Shuvendu K. Lahiri, Michael D. Ernst, and Thomas Ball. 2007. Feedback-Directed Random Test Generation. In 29th International Conference on Software Engineering (ICSE’07), IEEE, Minneapolis, MN, USA, 75–84. DOI:https://doi.org/10.1109/ICSE.2007.37

[7] 2023. API. Wikipedia. Retrieved August 16, 2023 from https://en.wikipedia.org/w/index.php?title=API&oldid=1170248429

[8] 2023. EvoMaster: A Tool For Automatically Generating System-Level Test Cases. Retrieved August 16, 2023 from https://github.com/EMResearch/EvoMaster

[9] pytest: helps you write better programs — pytest documentation. Retrieved August 16, 2023 from https://docs.pytest.org/en/7.4.x/index.html

[10] JUnit 5. Retrieved August 16, 2023 from https://junit.org/junit5/

[11] libFuzzer – a library for coverage-guided fuzz testing. — LLVM 18.0.0git documentation. Retrieved August 16, 2023 from https://www.llvm.org/docs/LibFuzzer.html

你可能感兴趣的:(鉴源论坛,API)