前言
在翻 Go 官方文件找底層原理的相關文件的時候翻到了 Fuzzing
這也是新的東西,以前是沒有看過的,看了一下之後覺得蠻重要的
而且公司有產品是專門在做模糊測試的,沒想到程式語言自己有實作
下次主管問要不要別的部門的測試產品直接reject
另外有一些深入自定義的部分需要查一下官網文件會比較清楚,這裡就不放了
什麼是模糊測試
從 Go Fuzzing Overview 我們可以直接了解
Fuzzing is a type of automated testing which continuously manipulates inputs to a program to find bugs. Go fuzzing uses coverage guidance to intelligently walk through the code being fuzzed to find and report failures to the user. Since it can reach edge cases which humans often miss, fuzz testing can be particularly valuable for finding security exploits and vulnerabilities.
大意上來說就是不斷測試你的 input,主要是用來發現會造成 bug 的邊際條件或是安全漏洞(e.g., SQL injection)
Fuzzing 支援條件
OSS-Fuzz
由 OSS-Fuzz 支援 Native Go
OSS-Fuzz 是 Google 開源的模糊測試專案(參考資料[3][4])
OSS-Fuzz 也有支援其他語言進行模糊測試
Go Version
1.18以上版本才支援
Fuzzing Rules
必要規則
- A fuzz test must be a function named like FuzzXxx, which accepts only a *testing.F, and has no return value.
- Fuzz tests must be in *_test.go files to run.
- A fuzz target must be a method call to (*testing.F).Fuzz which accepts a *testing.T as the first parameter, followed by the fuzzing arguments. There is no return value.
- There must be exactly one fuzz target per fuzz test.
- All seed corpus entries must have types which are identical to the fuzzing arguments, in the same order. This is true for calls to (*testing.F).Add and any corpus files in the testdata/fuzz directory of the fuzz test.
- The fuzzing arguments can only be the following types:
string, []byte
int, int8, int16, int32/rune, int64
uint, uint8/byte, uint16, uint32, uint64
float32, float64
bool
建議
- Fuzz targets should be fast and deterministic so the fuzzing engine can work efficiently, and new failures and code coverage can be easily reproduced.
- Since the fuzz target is invoked in parallel across multiple workers and in nondeterministic order, the state of a fuzz target should not persist past the end of each call, and the behavior of a fuzz target should not depend on global state.
Fuzzing 使用方法
- 有兩種模式可以運行模糊測試
There are two modes of running your fuzz test: as a unit test (default go test), or with fuzzing (go test -fuzz=FuzzTestName).
- 由你決定要運行多長時間的模糊測試,有可能會發生沒有測試到任何錯誤,此時模糊測試將會無限的運行。
Note that it is up to you to decide how long to run fuzzing. It is very possible that an execution of fuzzing could run indefinitely if it doesn’t find any errors.
Fuzzing Insight
提供了三種指標可以識別
- elapsed: the amount of time that has elapsed since the process began
- execs: the total number of inputs that have been run against the fuzz target (with an average execs/sec since the last log line)
- new interesting: the total number of “interesting” inputs that have been added to the generated corpus during this fuzzing execution (with the total size of the entire corpus)
可能導致模糊測試失敗的情況
- A panic occurred in the code or the test.
- The fuzz target called t.Fail, either directly or through methods such as t.Error or t.Fatal.
- A non-recoverable error occurred, such as an os.Exit or stack overflow.
- The fuzz target took too long to complete. Currently, the timeout for an execution of a fuzz target is 1 second. This may fail due to a deadlock or infinite loop, or from intended behavior in the code. This is one reason why it is suggested that your fuzz target be fast.
撰寫模糊測試
Run Fuzz Testing Repo:https://github.com/whitefloor/go-fuzz
根據參考資料[2]內有整段模糊測試的測試程式碼,重點有幾個
- 指定運行的測試指令
go test -run=FuzzReverse
- 運行模糊測試指令
go test -fuzz=Fuzz
- 運行指定的 corpus entry,hash code 會在模糊測試失敗的時候告訴你
go test -run=FuzzReverse/15bd0ea6a71e1138505c7d1011410810213bf67d2bdd5ac68d160fddb4d176c7
- 指定模糊測試的持續時間
go test -fuzz=Fuzz -fuzztime 30s
參考資料
-
https://go.dev/security/fuzz/
-
https://go.dev/doc/tutorial/fuzz
-
https://google.github.io/oss-fuzz/
-
https://github.com/google/oss-fuzz