Go的使用正在迅速增长。它现在是编写云原生软件、容器软件、命令行工具、数据库等的首选语言。Go已经内置了对测试的支持,这已经有一段时间了。它使得使用Go工具编写测试和运行测试变得相对容易。
什么是模糊测试?
Fuzzing,有时也称为模糊测试,是给你的软件提供意外输入的做法。理想情况下,这种测试会导致你的应用程序崩溃,或以意想不到的方式行事。不管发生了什么,你可以从你的代码对它没有被编程接受的数据的反应中学到很多东西,而且你可以添加适当的错误处理。
任何给定的软件程序都由接受来自不同来源的输入或数据的指令组成,然后它处理这些数据并产生适当的输出。随着软件的开发,测试工程师团队会对该软件进行测试,以发现软件中的错误,然后报告和修复。通常情况下,其目的是看软件的行为是否符合预期。测试可以进一步划分为多个领域,如功能测试、集成测试、性能测试等等。每种测试都集中在软件功能的一个特定方面,以发现错误或提高可靠性或性能。
模糊测试将这一测试过程向前推进了一步,试图向软件程序提供 "无效 "或 "随机 "数据。这是故意的,期望程序应该崩溃或表现得出乎意料,以发现程序中的错误,以便开发人员能够修复它们。就像测试一样,手动操作并不可行,所以许多模糊测试工具已经被编写出来以实现这一过程的自动化。
Go中的软件测试
作为一个例子,要在add.go 内测试Add() 函数,你可以通过导入 "测试 "包在add_test.go 内编写测试,并在一个以TestXXX() 开始的函数内添加测试功能。
给出这段代码。
func Add(num1, num2 int) int {
}
在一个名为add_test.go 的文件中,你可能有这样的代码用于测试。
import "testing"
func TestAdd(t *testing.T) {
}
运行测试。
$ go test
增加模糊测试支持
Go团队已经接受了为语言添加模糊测试支持的提议,以进一步推动这项工作。这涉及到增加一个新的testing.F 类型,在_test.go 文件内增加FuzzXXX() 函数,并且用-fuzz 选项来运行这些测试,正在被添加到Go工具中。
在一个名为add_test.go 的文件中。
func FuzzAdd(f *testing.F) {
}
运行该代码。
$ go test -fuzz
在写这篇文章的时候,这个功能是实验性的,但它应该包含在1.18版本中。另外,许多功能如-keepfuzzing 和-race ,目前还不支持。Go团队最近发布了一个关于模糊测试的教程,非常值得一读。
通过安装gotip获得最新功能
如果你很热心,希望在正式发布之前尝试一下这个功能,你可以利用gotip ,它可以让你测试即将到来的Go功能并提供反馈。要安装gotip ,你可以使用下面的命令。安装后,你可以使用gotip 工具来编译和运行程序,而不是通常的go 工具。
$ go install golang.org/dl/gotip@latest
$ gotip download
$ gotip version
go version devel go1.18-f009910 Thu Jan 6 16:22:21 2022 +0000 linux/amd64
$
社区中的模糊处理意见
在软件社区中,Fuzzing经常是一个讨论点,我们发现人们在两端都有意见。有些人认为它是一种有用的技术,可以找到错误,特别是在安全方面。而考虑到摸索所需的资源(CPU/内存),有些人认为这是一种浪费,或者更喜欢其他技术。这一点在Go团队中也是很明显的。我们可以看到Go的联合创始人Rob Pike对模糊测试的用途及其在Go中的实现持怀疑态度。
...虽然fuzzing在寻找某些类别的bug方面很出色,但它在CPU和存储方面非常昂贵,成本/效益比仍不清楚。我担心会浪费能源,并且用testdata的噪音填满git repos...
然而,Go安全团队的另一位成员Filo Sottile似乎对Go增加模糊支持相当乐观,也用一些例子支持它,并希望它成为开发过程的一部分。
我喜欢说,fuzzing在边缘发现bug。这也是我们作为安全团队对它感兴趣的原因:在边缘捕捉到的bug是那些没有进入生产的bug,不会成为漏洞。
我们希望模糊测试成为开发--而不是构建或安全--过程的一部分:对相关代码进行修改......
真实世界的模糊测试
在我看来,模糊测试在发现错误和使系统更安全、更有弹性方面似乎相当有效。举个例子,即使是Linux内核也是用一个叫syzkaller的工具进行模糊测试的,它已经发现了各种bug。
AFL 是另一个流行的模糊器,用于模糊用C/C++编写的程序。
过去也有用于模糊Go程序的选项,其中之一是Filo在其GitHub评论中提到的go-fuzz
go-fuzz的记录提供了相当惊人的证据,证明模糊处理能很好地找到人类没有发现的错误。根据我的经验,只需在CPU上花几分钟时间进行模糊处理,就能在边际上产生极大的效果。
为什么要在Go中添加原生的模糊测试支持
如果要求对Go程序进行模糊处理,并且现有的工具(如go-fuzz )可以做到这一点,那么为什么要在该语言中添加本地模糊处理支持呢?Go的模糊设计草案提供了一些这样做的理由。我们的想法是使这个过程简单化,因为使用上述工具会给开发者增加更多的工作,并且有许多缺失的功能。如果你是模糊测试的新手,我建议你阅读该设计草案文件。
开发人员可以使用go-fuzz或fzgo(建立在go-fuzz之上)等工具来解决一些需求。然而,每个现有的解决方案都比典型的Go测试涉及更多的工作,并且缺少关键的功能。与其他类型的Go测试(如基准测试或单元测试)相比,模糊测试不应该更复杂或功能更不完整。现有的解决方案会增加额外的开销,例如自定义命令行工具。
毛刺工具
Fuzzing是Go语言一长串所需功能中的一个受欢迎的补充。虽然目前是试验性的,但预计在即将发布的版本中会变得强大。这给了我们足够的时间去尝试它并探索它的使用情况。与其把它看作是开销,不如把它看作是一种有效的测试工具,如果使用得当,可以发现隐藏的错误。使用Go的团队应该鼓励它的使用,从开发人员编写小的模糊测试开始,测试团队进一步扩展它,以充分利用其潜力。