5 minutes reading time
本篇文章主要讲解在 go 语言中进行模糊测试的基础知识。通过模糊测试,随机数据会针对您的测试运行,以尝试找出漏洞或导致崩溃的输入。可以通过模糊测试发现的一些漏洞示例包括 SQL 注入、buffer overflow、拒绝服务和 cross-site scripting 攻击。
想要在 go 中使用模糊测试,需要安装 go1.18beta1 以上版本,具体的安装就不过多叙述了。
1 创建项目文件夹
我们创建一个名叫 fuzz-demo
的文件夹,并在其中创建一个名叫 main.go
的文件。
2 输入代码
在 main.go
中输入如下代码:
package main
import "fmt"
func Reverse(s string) string
func main()
Reverse 函数的作用就是对字符串进行反转。
3 运行代码,可以看到如下输出:
4 编写单元测试,我们为 Reverse 函数编写了一个单元测试。如下:
package main
import "testing"
func TestReverse(t *testing.T)
5 将单元测试修改为模糊测试
单元测试有局限性,即每个输入都必须由开发人员添加到测试中。模糊测试的一个好处是它可以为您的代码提供输入,并且可以识别您提出的测试用例没有达到的边缘用例。
模糊测试代码如下:
func FuzzReverse(f *testing.F)
模糊测试 也有一些限制。在您的单元测试中,您可以预测Reverse函数的预期输出,并验证实际输出是否满足这些预期。
例如,在测试用例Reverse("Hello, world")中,单元测试将返回指定为"dlrow ,olleH".
模糊测试时,您无法预测预期输出,因为您无法控制输入。
但是,Reverse您可以在模糊测试中验证函数的一些属性。在这个模糊测试中检查的两个属性是:
1 将字符串反转两次保留原始值
2 反转的字符串将其状态保留为有效的 UTF-8。
注意单元测试和模糊测试之间的语法差异:
该函数以 FuzzXxx 而不是 TestXxx 开头,取testing.F 而不是testing.T 在你期望看到t.Run执行的地方,你看到的是f.Fuzz,它接受一个参数为* testing的fuzz目标函数。T和需要模糊化的类型。单元测试的输入使用f.Add作为种子语料库输入提供。
6 运行测试
使用命令 go test 进行测试以保证种子正确,如果您在该文件中有其他测试,您也可以运行go test -run=FuzzReverse,并且您只想运行模糊测试。
运行 go test -fuzz=Fuzz
进行模糊测试,测试失败,具体失败信息如下:
Failing input written to testdata\fuzz\FuzzReverse\09f84a1d1fc1c0a975a2de415e883bfc189bb7d17eaad24d85b68a17fd81c8f9
To re-run:
go test -run=FuzzReverse/09f84a1d1fc1c0a975a2de415e883bfc189bb7d17eaad24d85b68a17fd81c8f9
FAIL
exit status 1
FAIL github.com/overstarry/funzz-demo 0.950s
模糊测试时发生故障,导致问题的输入被写入将在下次运行的种子语料库文件中go test,即使没有-fuzz标志也是如此。要查看导致失败的输入,请在编辑器中打开 testdata/fuzz/FuzzReverse 目录的语料库文件。
go test fuzz v1
string("扖")
语料库文件的第一行表示编码版本。以下每一行代表构成语料库条目的每种类型的值。由于 fuzz target 只需要 1 个输入,因此版本之后只有 1 个值。
不使用 -fuzz 运行测试,这次测试将会自动使用模糊测试失败的语料.
7 修改函数的错误
接下来对代码进行修复以通过测试,修复后的代码如下:
func Reverse(s string) (string, error)
新的模糊测试代码如下:
package main
import (
"testing"
"unicode/utf8"
)
func FuzzReverse(f *testing.F)
再次运行模糊测试,可以看到所有的测试都通过了。
本篇文章主要介绍在 go 中如何进行模糊测试。完整代码: https://github.com/overstarry/fuzz-demo