前言
Go 1.18在go工具链里引入了fuzzing模糊测试,可以帮助我们发现Go代码里的漏洞或者可能导致程序崩溃的输入。Go官方团队也在官网发布了fuzzing入门教程,帮助大家快速上手。
本人对Go官方教程在翻译的基础上做了一些表述上的优化,以飨读者。
注意:fuzzing模糊测试和Go已有的单元测试以及性能测试框架是互为补充的,并不是替代关系。
教程内容
这篇教程会介绍Go fuzzing的入门基础知识。fuzzing可以构造随机数据来找出代码里的漏洞或者可能导致程序崩溃的输入。通过fuzzing可以找出的漏洞包括SQL注入、缓冲区溢出、拒绝服务(Denial of Service)攻击和XSS(cross-site scripting)攻击等。
在这个教程里,你会给一个函数写一段fuzz test(模糊测试)程序,然后运行go命令来发现代码里的问题,最后通过调试来修复问题。
本文里涉及的专业术语,可以参考 Go Fuzzing glossary。
接下来会按照如下章节介绍:
准备工作
-
安装Go 1.18 Beta 1或者更新的版本。安装指引可以参考下面的介绍。
-
有一个代码编辑工具。任何文本编辑器都可以。
-
有一个命令行终端。Go可以运行在Linux,Mac上的任何命令行终端,也可以运行在Windows的PowerShell或者cmd之上。
-
有一个支持fuzzing的环境。目前Go fuzzing只支持AMD64和ARM64架构。
安装和使用beta版本
这个教程需要使用Go 1.18 Beta 1或以上版本的泛型功能。使用如下步骤,安装beta版本
-
使用下面的命令安装beta版本
$ go install golang.org/dl/go1.18beta1@latest
-
运行如下命令来下载更新
$ go1.18beta1 download
注意:如果在MAC或者Linux上执行
go1.18beta1
提示command not found
,需要设置bash
或者zsh
对应的profile环境变量文件。bash
设置在~/.bash_profile
文件里,内容为:export GOROOT=/usr/local/opt/go/libexec export GOPATH=$HOME/go export PATH=$PATH:$GOROOT/bin:$GOPATH/bin
GOROOT
和GOPATH
的值可以通过go env
命令查看,设置完后执行source ~/.bash_profile
让设置生效,再执行go1.18beta1
就不报错了。 -
使用beta版本的go命令,不要去使用release版本的go命令
你可以通过直接使用
go1.18beta1
命令或者给go1.18beta1
起一个简单的别名-
直接使用
go1.18beta1
命令$ go1.18beta1 version
-
给
go1.18beta1
命令起一个别名$ alias go=go1.18beta1 $ go version
下面的教程都假设你已经把
go1.18beta1
命令设置了别名go
。 -
为你的代码创建一个目录
首先创建一个目录用于存放你写的代码。
-
打开一个命令行终端,切换到你的
home
目录-
在Linux或者Mac上执行如下命令(Linux或者Mac上只需要执行
cd
就可以进入到home
目录)cd
-
在Windows上执行如下命令
C:\> cd %HOMEPATH%
-
-
在命令行终端,创建一个名为
fuzz
的目录,并进入该目录$ mkdir fuzz $ cd fuzz
-
创建一个go module
运行
go mod init
命令,来给你的项目设置module路径$ go mod init example/fuzz
注意:对于生产代码,你可以根据项目实际情况来指定module路径,如果想了解更多,可以参考Go Module依赖管理。
接下来,我们来使用map写一些简单的代码来做字符串的反转,然后使用fuzzing来做模糊测试。
实现一个函数
在这个章节,你需要实现一个函数来对字符串做反转。
编写代码
-
打开你的文本编辑器,在fuzz目录下创建一个
main.go
源文件。 -
在
main.go
里编写如下代码:// maing.go package main import "fmt" func Reverse(s string) string { b := []byte(s) for i, j := 0, len(b)-1; i < len(b)/2; i, j = i+1, j-1 { b[i], b[j] = b[j], b[i] } return string(b) } func main() { input := "The quick brown fox jumped over the lazy dog" rev := Reverse(input) doubleRev := Reverse(rev) fmt.Printf("original: %q\n", input) fmt.Printf("reversed: %q\n", rev) fmt.Printf("reversed again: %q\n", doubleRev) }
运行代码
在main.go
所在目录执行命令go run .
来运行代码,结果如下:
$ go run . original: "The quick brown fox jumped over the lazy dog" reversed: "god