『每周譯Go』Go 模糊測試
從 Go 1.18 版本開始,標準工具集開始支持模糊測試。
1
概述

模糊測試(Fuzzing)是一種自動化測試方法,通過不斷地控制程序輸入來發(fā)現(xiàn)程序錯誤。Go 中模糊測試使用覆蓋率引導來智能瀏覽被測試代碼,發(fā)現(xiàn)并向用戶報告錯誤。因為模糊測試可以觸達人們常常忘記的邊界測試用例,所以對查找安全隱患和漏洞特別有價值。
下面是 模糊測試(https://tip.golang.org/doc/fuzz/#glos-fuzz-test) 的一個例子,標注了其中主要組成部分。
示例代碼中展示了整個模糊測試的情況,其中有一個模糊目標。用f.Add在模糊目標之前添加測試種子語料庫,模糊目標的參數(shù)作為模糊參數(shù)被突出顯示。
2
編寫和運行模糊測試

要求
下面是模糊測試必須遵守的規(guī)則:
模糊測試必須是以 FuzzXxx命名的函數(shù),只能接收一個*testing.F的參數(shù),且沒有返回值模糊測試必須在 *_test.go 文件中運行 一個 模糊目標(https://tip.golang.org/doc/fuzz/#glos-fuzz-target) 必須是調(diào)用 (*testing.F).Fuzz 的方法,該方法接收 *testing.T 作為首個參數(shù),緊隨之后的是模糊參數(shù)。該函數(shù)沒有返回值 每個模糊測試中必須有一個模糊目標 所有的 語料庫(https://tip.golang.org/doc/fuzz/#glos-seed-corpus—— 中的條目必須和 模糊參數(shù)(https://tip.golang.org/doc/fuzz/#fuzzing-arguments) 相同類型、順序一致。這一要是適用于調(diào)用 (*testing.F).Add 函數(shù)和模糊測試 testdata/fuzz 目錄下的所有文件 模糊參數(shù)只能是如下類型: string, []byte int, int8, int16, int32/rune, int64 uint, uint8/byte, uint16, uint32, uint64 float32, float64 bool
建議
下面的建議將幫助你從模糊處理中獲得最大收益。
模糊測試應該在支持覆蓋檢測的平臺上運行(目前是 AMD64 和 ARM64),如此語料庫可以在運行過程中進行有意義的增長,并且在模糊測試時可以覆蓋更多代碼 模糊目標應該是快速和確定的,這樣模糊引擎就能有效地工作,新的失敗和代碼覆蓋率就能輕易地重現(xiàn) 由于模糊目標是以非確定性的順序在多個 worker 間并行調(diào)用,所以模糊目標的狀態(tài)不應該在每次調(diào)用結(jié)束后持續(xù)存在,而且模糊目標的行為不應該依賴于全局狀態(tài)
自定義設(shè)置
默認的 go 命令設(shè)置適用于大多數(shù)模糊測試的情況。通常情況下,在命令行上執(zhí)行的模糊測試應該是這樣的
$?go?test?-fuzz={FuzzTestName}
然而,go命令在運行模糊測試時也提供了一些設(shè)置,這些設(shè)置在 cmd/go包文檔(https://pkg.go.dev/cmd/go) 中。
其中幾個:
-fuzztime: 在退出前執(zhí)行模糊目標的總時間或迭代次數(shù),默認為無限期地-fuzzminimizetime: 在每次最小化嘗試中,模糊目標將被執(zhí)行的時間或迭代次數(shù),默認為 60 秒。你可以通過-fuzzminimizetime 0完全禁用最小化設(shè)置-parallel: 同時運行的模糊處理進程的數(shù)量,默認為$GOMAXPROCS。目前,在模糊摸索過程中設(shè)置-cpu沒有作用
語料庫文件格式
語料庫文件是以一種特殊的格式進行編碼的。這對于種子語料庫(https://tip.golang.org/doc/fuzz/#glos-seed-corpus)和生成語料庫(https://tip.golang.org/doc/fuzz/#glos-generated-corpus)是相同的格式。
下面是一個語料庫文件的例子:
go?test?fuzz?v1
[]byte("hello\\xbd\\xb2=\\xbc??")
int64(572293)
第一行是用來通知模糊測試引擎文件的編碼版本。雖然目前沒有計劃未來的編碼格式版本,但設(shè)計上必須支持這種可能性。
下面的每一行都是構(gòu)成語料庫條目的值,如果需要,可以直接復制到 Go 代碼中。
在上面的例子中,我們有一個[]byte,后面是一個int64。這些類型必須與模糊處理的參數(shù)完全類型匹配、順序一致。這些類型的模糊測試目標會是這樣的:
f.Fuzz(func(*testing.T,?[]byte,?int64)?{})
指定自定義種子語料庫的最簡單方法是使用(*testing.F).Add方法。在上面的例子中,可以這樣操作:
f.Add([]byte("hello\\xbd\\xb2=\\xbc??"),?int64(572293))
然而,可能有一些大的二進制文件,你不希望將其作為代碼復制到你的測試中,而是作為單獨的種子語料庫條目保留在 testdata/fuzz/{FuzzTestName} 目錄下。file2fuzz工具可以用來將這些二進制文件轉(zhuǎn)換成以 []byte 編碼的語料庫文件。
如此使用該工具:
$?go?install?golang.org/x/tools/cmd/file2fuzz@latest
$?file2fuzz
3
相關(guān)資源

教程:
關(guān)于用 Go 進行模糊測試的介紹性教程,請參見博文 更多內(nèi)容即將來臨! 文檔:
testing包文檔描述了在編寫模糊測試時使用的testing.F類型cmd/go包文檔描述了與模糊處理相關(guān)的標志技術(shù)細節(jié):
設(shè)計初稿(https://golang.org/s/draft-fuzzing-design) 提案(https://golang.org/issue/44551)
4
詞匯表

語料庫條目(corpus entry): 語料庫中的一條輸入記錄,可以在模糊測試時使用。這可以是一個特殊格式的文件,或者是對(*testing.F).Add的調(diào)用
覆蓋面指導(coverage guidance): 一種使用代碼覆蓋率的擴展來確定哪些語料庫條目值得保留以供將來使用的模糊測試方法
模糊目標(fuzz target): 模糊測試的函數(shù),用來在模糊測試時執(zhí)行語料庫條目和生成對應的值。它通過向(*testing.F).Fuzz傳遞函數(shù)來提供給模糊測試
模糊測試(fuzz test): 測試文件中用于模糊處理的一個函數(shù),其形式為func FuzzXxx(*testing.F)
模糊化(fuzzing): 一種自動測試,它不斷地操縱程序的輸入,以發(fā)現(xiàn)代碼潛在問題,如錯誤或漏洞
模糊參數(shù)(fuzzing arguments): 傳遞給模糊目標的類型,并由mutator進行變異處理
模糊引擎(fuzzing engine): 一個管理模糊處理的工具,包括維護語料庫、調(diào)用突變器、識別新的覆蓋范圍和報告錯誤
生成的語料庫(generated corpus): 一個語料庫,它由模糊引擎在模糊處理過程中長期維護,以跟蹤進展。它被保存在$GOCACHE/fuzz中
突變器( mutator): 一個在模糊處理時使用的工具,在將語料庫條目傳遞給模糊處理目標之前,對其進行隨機處理
包(package): 同一目錄下的源文件的集合,這些文件被編譯在一起。請參閱 Go 語言規(guī)范中的 Packages 部分。
種子語料庫(seed corpus): 用戶為模糊測試提供的語料庫,可用于指導模糊測試引擎。它由模糊測試中f.Add調(diào)用添加的語料庫條目,以及軟件包中testdata/fuzz/{FuzzTestName}目錄下的文件組成
測試文件(test file): 一個格式為 xxx_test.go 的文件,可以包含測試、基準、例子和模糊測試
漏洞(vulnerability): 一種代碼中安全敏感的弱點,可被攻擊者所利用
5
反饋

如果你遇到任何問題或有一個關(guān)于功能的想法,歡迎提交問題(https://github.com/golang/go/issues/new?&labels=fuzz)
關(guān)于該功能的討論和一般反饋,也可以參與 Gophers Slack 的#fuzzing 頻道(https://gophers.slack.com/archives/CH5KV1AKE)

原文地址:https://tip.golang.org/doc/fuzz/
原文作者:Go Team
本文永久鏈接:https:/github.com/gocn/translator/blob/master/2022/w01_Go_Fuzzing.md
譯者:fivezh
校對:zxmfke
想要了解關(guān)于 Go 的更多資訊,還可以通過掃描的方式,進群一起探討哦~
