前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Go模糊测试

Go模糊测试

作者头像
美团骑手
发布2022-04-26 08:14:01
3730
发布2022-04-26 08:14:01
举报
文章被收录于专栏:技术进阶技术进阶技术进阶

本篇文章主要讲解在 go 语言中进行模糊测试的基础知识。通过模糊测试,随机数据会针对您的测试运行,以尝试找出漏洞或导致崩溃的输入。可以通过模糊测试发现的一些漏洞示例包括 SQL 注入、buffer overflow、拒绝服务和 cross-site scripting 攻击。

想要在 go 中使用模糊测试,需要安装 go1.18beta1 以上版本,具体的安装就不过多叙述了。

1 创建项目文件夹

我们创建一个名叫 test 的文件夹,并在其中创建一个名叫 main.go 的文件。

2 输入代码

main.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 := "quick quick brown fox jumped over the lazy dog"
    rev := Reverse(input)
    doubleRev := Reverse(rev)
    fmt.Printf("原来: %qn", input)
    fmt.Printf("反转: %qn", rev)
    fmt.Printf("再反转: %qn", doubleRev)
}

Reverse 函数的作用就是对字符串进行反转。

3 运行代码,可以看到如下输出: /img/fuzz/img.png

4 编写单元测试,我们为 Reverse 函数编写了一个单元测试。如下:

package main

import "testing"

func TestReverse(t *testing.T) {
    type args struct {
        s string
    }
    tests := []struct {
        name string
        args args
        want string
    }{
        {"test1", args{"Hello, world"}, "dlrow ,olleH"},
        {"test2", args{" "}, " "},
        {"test3", args{"!12345"}, "54321!"},
    }
    for _, tt := range tests {
        t.Run(tt.name, func(t *testing.T) {
            if got := Reverse(tt.args.s); got != tt.want {
                t.Errorf("Reverse() = %v, want %v", got, tt.want)
            }
        })
    }
}

5 将单元测试修改为模糊测试

单元测试有局限性,即每个输入都必须由开发人员添加到测试中。模糊测试的一个好处是它可以为您的代码提供输入,并且可以识别您提出的测试用例没有达到的边缘用例。

模糊测试代码如下:

func FuzzReverse(f *testing.F) {
testcases := []string{"Hello, world", " ", "!12345"}
for _, tc := range testcases {
f.Add(tc)
}
f.Fuzz(func (t *testing.T, orig string) {
rev := Reverse(orig)
doubleRev := Reverse(rev)
if orig != doubleRev {
t.Errorf("Before: %q, after: %q", orig, doubleRev)
}
if utf8.ValidString(orig) && !utf8.ValidString(rev) {
t.Errorf("Reverse produced invalid UTF-8 string %q", rev)
}
})
}

模糊测试 也有一些限制。在您的单元测试中,您可以预测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作为种子语料库输入提供。

  1. 运行测试

使用命令 go test 进行测试以保证种子正确,如果您在该文件中有其他测试,您也可以运行go test -run=FuzzReverse,并且您只想运行模糊测试。

运行 go test -fuzz=Fuzz 进行模糊测试,测试失败,具体失败信息如下:

Failing input written to testdatafuzzFuzzReverse9f84a1d1fc1c0a975a2de415e883bfc189bb7d17eaad24d85b68a17fd81c8f9
To re-run:
go test -run=FuzzReverse/09f84a1d1fc1c0a975a2de415e883bfc189bb7d17eaad24d85b68a17fd81c8f9

FAIL    github.com/overstarry/funzz-demo        0.950s

模糊测试时发生故障,导致问题的输入被写入将在下次运行的种子语料库文件中 go test,即使没有-fuzz标志也是如此。要查看导致失败的输入,请在编辑器中打开 testdata/test/FuzzReverse 目录的语料库文件。

go test test v1 string("扖") 语料库文件的第一行表示编码版本。以下每一行代表构成语料库条目的每种类型的值。由于 fuzz target 只需要 1 个输入,因此版本之后只有 1 个值。

不使用 -fuzz 运行测试,这次测试将会自动使用模糊测试失败的语料.

7 修改函数的错误

接下来对代码进行修复以通过测试,修复后的代码如下:

func Reverse(s string) (string, error) {
    if !utf8.ValidString(s) {
    return s, errors.New("input is not valid UTF-8")
    }
    r := []rune(s)
    for i, j := 0, len(r)-1; i < len(r)/2; i, j = i+1, j-1 {
    r[i], r[j] = r[j], r[i]
    }
    return string(r), nil
}

新的模糊测试代码如下:

package main

import (
    "testing"
    "unicode/utf8"
)

func FuzzReverse(f *testing.F) {
    testcases := []string {"Hello, world", " ", "!12345"}
    for _, tc := range testcases {
        f.Add(tc)  
    }
    f.Fuzz(func(t *testing.T, orig string) {
        rev, err1 := Reverse(orig)
        if err1 != nil {
            return
        }
        doubleRev, err2 := Reverse(rev)
        if err2 != nil {
            return
        }
        if orig != doubleRev {
            t.Errorf("Before: %q, after: %q", orig, doubleRev)
        }
        if utf8.ValidString(orig) && !utf8.ValidString(rev) {
            t.Errorf("Reverse produced invalid UTF-8 string %q", rev)
        }
    })
}

再次运行模糊测试,可以看到所有的测试都通过了。

小结 本篇文章主要介绍在 go 中如何进行模糊测试。完整代码: https://github.com/overstarry/fuzz-demo

参考 https://zh.wikipedia.org/zh-hans/%E6%A8%A1%E7%B3%8A%E6%B5%8B%E8%AF%95 https://go.dev/doc/fuzz/#requirements

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2022-04-25 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档