当前位置: 首页 > news >正文

【Go语言成长之路】 模糊测试

文章目录

  • 模糊测试
    • 一、前提
    • 二、创建项目
    • 三、添加待测试代码
    • 四、添加单元测试
    • 五、添加模糊测试

模糊测试

​ 本教程介绍了 Go 中模糊测试的基础知识。通过模糊测试,随机数据会针对您的测试运行,以尝试找到漏洞或导致崩溃的输入。可以通过模糊测试发现的漏洞示例包括 SQL 注入、缓冲区溢出、拒绝服务和跨站点脚本攻击。

注:Go语言中模糊测试已经内置,具体可以参考: Go Fuzzing docs, 将来还会添加更多功能。

一、前提

  • Go1.18以及之后。
  • 支持模糊测试的环境。目前,使用覆盖率检测进行模糊测试仅适用于 AMD64 和 ARM64 架构。

二、创建项目

~$ mkdir fuzz
~$ cd fuzz/
~/fuzz$ go mod init example/fuzz
go: creating new go.mod: module example/fuzz

三、添加待测试代码

package mainimport "fmt"// accept a string, loop over it a byte at a time, and return the reversed string at the end.
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)
}

运行代码:

~/fuzz$ go run ./fuzz
original: "The quick brown fox jumped over the lazy dog"
reversed: "god yzal eht revo depmuj xof nworb kciuq ehT"
reversed again: "The quick brown fox jumped over the lazy dog"

四、添加单元测试

为 Reverse 函数编写基本单元测试,在fuzz文件夹内新建一个测试文件reverse_test.go

package mainimport ("testing"
)func TestReverse(t *testing.T) {testcases := []struct {in, want string}{{"Hello, world", "dlrow ,olleH"},{" ", " "},{"!12345", "54321!"},}for _, tc := range testcases {rev := Reverse(tc.in)if rev != tc.want {t.Errorf("Reverse: %q, want %q", rev, tc.want)}}
}

这个简单的测试将断言列出的输入字符串将被正确反转。

之后运行测试代码:

~/fuzz$ go test . -v
=== RUN   TestReverse
--- PASS: TestReverse (0.00s)
PASS
ok      example/fuzz    0.003s

五、添加模糊测试

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

注:单元测试、基准测试和模糊测试可以保留在同一个*_test.go文件中。

​ 编写的模糊测试函数代码如下:

func FuzzReverse(f *testing.F) {testcases := []string{"Hello, world", " ", "!12345"}for _, tc := range testcases {f.Add(tc)  // Use f.Add to provide a seed corpus}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)}})
}

使用模糊测试有如下几个特点:

  • 无法预测结果。因为无法控制模糊测试的输入

  • 可以验证函数的属性,在本例中可以检查的属性有:

    • 将字符串反转两次可以保留原始值
    • 反转的字符串将其状态保留为有效的 UTF-8。

请注意单元测试和模糊测试之间的语法差异:

  • 该函数以 FuzzXxx 而不是TestXxx开头,并采用 *testing.F 而不是 *testing.T
  • 将 t.Run 替换为 f.Fuzz,它采用了一个模糊目标函数,其参数为 *testing.T 和要模糊的类型。使用 f.Add 将单元测试的输入作为种子语料库输入提供。

之后就可以运行模糊测试并查看结果:

~/fuzz$ go test ./fuzz -v
=== RUN   TestReverse
--- PASS: TestReverse (0.00s)
=== RUN   FuzzReverse
=== RUN   FuzzReverse/seed#0
=== RUN   FuzzReverse/seed#1
=== RUN   FuzzReverse/seed#2
--- PASS: FuzzReverse (0.00s)--- PASS: FuzzReverse/seed#0 (0.00s)--- PASS: FuzzReverse/seed#1 (0.00s)--- PASS: FuzzReverse/seed#2 (0.00s)
PASS
ok      example/fuzz    0.003s

如果你只想运行模糊测试,那么可以执行如下命令:

~/fuzz$ go test . -run=FuzzReverse -v # 运行特定的函数
=== RUN   FuzzReverse
=== RUN   FuzzReverse/seed#0
=== RUN   FuzzReverse/seed#1
=== RUN   FuzzReverse/seed#2
--- PASS: FuzzReverse (0.00s)--- PASS: FuzzReverse/seed#0 (0.00s)--- PASS: FuzzReverse/seed#1 (0.00s)--- PASS: FuzzReverse/seed#2 (0.00s)
PASS
ok      example/fuzz    0.003s 
~/fuzz$go test -fuzz=Fuzz . -v # 只运行模糊测试
=== RUN   TestReverse
--- PASS: TestReverse (0.00s)
=== RUN   FuzzReverse
fuzz: elapsed: 0s, gathering baseline coverage: 0/3 completed
fuzz: elapsed: 0s, gathering baseline coverage: 3/3 completed, now fuzzing with 8 workers
fuzz: elapsed: 0s, execs: 253 (10168/sec), new interesting: 2 (total: 5)
--- FAIL: FuzzReverse (0.03s)--- FAIL: FuzzReverse (0.00s)reverse_test.go:36: Reverse produced invalid UTF-8 string "\xa3\xd6"Failing input written to testdata/fuzz/FuzzReverse/14a85158d50021f3To re-run:go test -run=FuzzReverse/14a85158d50021f3
=== NAME  
FAIL
exit status 1
FAIL    example/fuzz    0.029s

​ 另一个有用的标志是 -fuzztime,它限制模糊测试所需的时间, 若没有指定模糊测试的运行时间,那么它将会一直运行下去,直到发生错误。

​ 模糊测试时发生故障,导致问题的输入被写入种子语料库文件,该文件将在下次调用 go test 时运行,即使没有 -fuzz 标志也是如此。要查看导致失败的输入,请在文本编辑器中打开写入 testdata/fuzz/FuzzReverse目录的语料库文件。您的种子语料库文件可能包含不同的字符串,但格式将相同, 类型如下:

go test fuzz v1
string("֣")

​ 语料库文件的第一行表示编码版本。接下来的每一行代表构成语料库条目的每种类型的值。由于模糊目标仅需要 1 个输入,因此版本后只有 1 个值。

​ 再次运行 go test,不带 -fuzz 标志;将使用新的失败种子语料库条目:

~/fuzz$ go test ./fuzz
--- FAIL: FuzzReverse (0.00s)--- FAIL: FuzzReverse/14a85158d50021f3 (0.00s)reverse_test.go:36: Reverse produced invalid UTF-8 string "\xa3\xd6"
FAIL
FAIL    example/fuzz    0.003s
FAIL

若想使用原来失败的语料种子,可以执行如下命令:

~/fuzz$ go test -run=FuzzReverse/28f36ef487f23e6c7a81ebdaa9feffe2f2b02b4cddaa6252e87f69863046a5e0
input: "\x91"
runes: ['�']
input: "�"
runes: ['�']
--- FAIL: FuzzReverse (0.00s)--- FAIL: FuzzReverse/28f36ef487f23e6c7a81ebdaa9feffe2f2b02b4cddaa6252e87f69863046a5e0 (0.00s)reverse_test.go:16: Number of runes: orig=1, rev=1, doubleRev=1reverse_test.go:18: Before: "\x91", after: "�"
FAIL
exit status 1
FAIL    example/fuzz    0.145s

之后就是定位问题并解决了。

遇到错误的几点建议:

  • 诊断错误

    有如下几种方法:

    • 通过VS Code设置调试器进行调查(遇到比较棘手的错误可以使用此方法)

    • 将把有用的调试信息记录到您的终端

      比如说使用t.LogF将错误相关的内容打印出来,或者如果发生错误,或者使用 -v 执行测试,此 t.Logf 行将打印到命令行,这可以帮助您调试此特定问题。

  • 解决错误

相关文章:

【Go语言成长之路】 模糊测试

文章目录 模糊测试一、前提二、创建项目三、添加待测试代码四、添加单元测试五、添加模糊测试 模糊测试 ​ 本教程介绍了 Go 中模糊测试的基础知识。通过模糊测试&#xff0c;随机数据会针对您的测试运行&#xff0c;以尝试找到漏洞或导致崩溃的输入。可以通过模糊测试发现的漏…...

异或运算的高级应用和Briankernighan算法

本篇文章主要回顾一下计算机的位运算&#xff0c;处理一些位运算的巧妙操作。 特别提醒&#xff1a;实现位运算要注意溢出和符号扩展等问题。 先看一个好玩的问题&#xff1a; $Problem1 $ 黑白球概率问题 袋子里一共a个白球&#xff0c;b个黑球&#xff0c;每次从袋子里拿…...

音视频入门基础:WAV专题(9)——FFmpeg源码中计算WAV音频文件每个packet的duration和duration_time的实现

一、引言 从文章《音视频入门基础&#xff1a;WAV专题&#xff08;6&#xff09;——通过FFprobe显示WAV音频文件每个数据包的信息》中我们可以知道&#xff0c;通过FFprobe命令可以显示WAV音频文件每个packet&#xff08;也称为数据包或多媒体包&#xff09;的信息&#xff0…...

AI写的论文查重率高吗?分享6款实测AI论文生成免费网站

在当今学术研究和论文写作领域&#xff0c;AI技术的迅猛发展为研究人员提供了极大的便利。特别是AI论文自动生成助手&#xff0c;它们不仅能够提高写作效率&#xff0c;还能帮助生成高质量的论文内容。以下是六款经过实测且免费的AI论文生成网站推荐&#xff1a; 一、千笔-AIP…...

【专题】2024年8月中国企业跨境、出海、国际化、全球化行业报告汇总PDF合集分享(附原数据表)

原文链接&#xff1a; https://tecdat.cn/?p37584 在全球化浪潮汹涌澎湃的当下&#xff0c;中国企业积极探索海外市场&#xff0c;开启了出海跨境的新征程。本报告合集旨在全面梳理出海跨境全球化行业的发展态势&#xff0c;涵盖多个领域的深度洞察。 从游戏、快消品、医疗器…...

[算法]单调栈解法

目录 739. 每日温度 - 力扣&#xff08;LeetCode&#xff09; 42. 接雨水 - 力扣&#xff08;LeetCode&#xff09; 84. 柱状图中最大的矩形 - 力扣&#xff08;LeetCode&#xff09; 739. 每日温度 - 力扣&#xff08;LeetCode&#xff09; 解法&#xff1a; 通常是一维数…...

构建数据安全防线:MySQL数据备份策略的文档化实践

在数据驱动的商业环境中&#xff0c;数据备份策略是确保数据安全和业务连续性的关键。MySQL&#xff0c;作为广泛使用的数据库管理系统&#xff0c;其数据备份策略的文档化对于规范备份流程、提高恢复效率和满足合规要求至关重要。本文将深入探讨如何在MySQL中实现数据备份的策…...

4. GIS前端工程师岗位职责、技术要求和常见面试题

本系列文章目录&#xff1a; 1. GIS开发工程师岗位职责、技术要求和常见面试题 2. GIS数据工程师岗位职责、技术要求和常见面试题 3. GIS后端工程师岗位职责、技术要求和常见面试题 4. GIS前端工程师岗位职责、技术要求和常见面试题 5. GIS工程师岗位职责、技术要求和常见面试…...

软件测试-Selenium+python自动化测试

目录 会用到谷歌浏览器Chrome测试,需要下载一个Chromedriver(Chrome for Testing availability)对应自己的浏览器版本号选择。 一、元素定位 对html网页中的元素进行定位,同时进行部分操作。 1.1一个简单的模板 from selenium import webdriver from selenium.webdrive…...

SpringBoot与Minio的极速之旅:解锁文件切片上传新境界

目录 一、前言 二、对象存储&#xff08;Object Storage&#xff09;介绍 &#xff08;1&#xff09;对象存储的特点 &#xff08;2&#xff09;Minio 与对象存储 &#xff08;3&#xff09;对象存储其他存储方式的区别 &#xff08;4&#xff09;对象存储的应用场景 三、…...

Java 7.3 - 分布式 id

分布式 ID 介绍 什么是 ID&#xff1f; ID 就是 数据的唯一标识。 什么是分布式 ID&#xff1f; 分布式 ID 是 分布式系统中的 ID&#xff0c;它不存在于现实生活&#xff0c;只存在于分布式系统中。 分库分表&#xff1a; 一个项目&#xff0c;在上线初期使用的是单机 My…...

144. 腾讯云Redis数据库

文章目录 一、Redis 的主要功能特性二、Redis 的典型应用场景三、Redis 的演进过程四、Redis 的架构设计五、Redis 的数据类型及操作命令六、腾讯云数据库 Redis七、总结 Redis 是一种由 C 语言开发的 NoSQL 数据库&#xff0c;以其高性能的键值对存储和多种应用场景而闻名。本…...

基于单片机的自动浇花控制写设计任务书

一、内容要求&#xff1a; 任务 随着社会的进步&#xff0c;人们的生活质量越来越高。在家里养养盆花可以陶冶情操&#xff0c;丰富生活。同时盆花可以通过光合作用吸收二氧化碳&#xff0c;净化室内空气&#xff0c;在有花木的地方空气中阴离子聚集较多&#xff0c;所以空气…...

从零到精通:用C++ STL string优化代码

目录 1:为什么要学习string类 2:标准库中的string类 2.1:string类(了解) 2.2:总结 3:string类的常用接口 3.1:string类对象的常见构造 3.1.1:代码1 3.1.2:代码2 3.2:string类对象的遍历操作 3.2.1:代码1(begin end) 3.2.2:代码2(rbegin rend) 3.3:string类对象的…...

鸿蒙轻内核M核源码分析系列五 时间管理

往期知识点记录&#xff1a; 鸿蒙&#xff08;HarmonyOS&#xff09;应用层开发&#xff08;北向&#xff09;知识点汇总 持续更新中…… 在鸿蒙轻内核源码分析上一篇文章中&#xff0c;我们剖析了中断的源码&#xff0c;简单提到了Tick中断。本文会继续分析Tick和时间相关的源…...

Python Opencv鼠标回调

使用 OpenCV 的 cv2.setMouseCallback() 方法来捕捉鼠标事件&#xff0c;并实现以下功能&#xff1a; 实时在鼠标指针附近显示其位置的像素坐标。通过左键双击&#xff0c;将像素坐标记录到数组中。通过右键点击&#xff0c;取消上一次添加的坐标。 下面是实现代码的示例&…...

Ubuntu环境的MySql下载安装

下载压缩包 此文章下载的mysql版本位5.7.29 sudo wget https://downloads.mysql.com/archives/get/p/23/file/mysql-server_5.7.29-1ubuntu18.04_amd64.deb-bundle.tar解压缩 sudo tar -xvf mysql-server_5.7.29-1ubuntu18.04_amd64.deb-bundle.tar命令解释 -x&#xff1a;…...

Android系统去掉WIFI模块

先说应用场景&#xff0c;有些特定设备&#xff0c;不能连接wifi。需要隐藏的模块&#xff0c;QS面板模块的wifi,还有设置里面的wifi.由于QS属于SystemUI&#xff0c;熟悉SystemUI之后&#xff0c;就可以直接去SystemUi那里找&#xff0c;找到QSTitle 默认配置的地方。 一、…...

代码随想录 -- 二叉树 -- 翻转二叉树

226. 翻转二叉树 - 力扣&#xff08;LeetCode&#xff09; 递归比较简单 class Solution(object):def invertTree(self, root):if rootNone:returnnode rootif node.left or node.right:tempnode.leftnode.leftnode.rightnode.righttempself.invertTree(node.left)self.inve…...

Node.js之文件复制

1.方式一&#xff1a;readFile // 导入fs模块 const fs require("fs") // 导入process模块 const process require("process")// 读取文件内容 let data fs.writeFileSync(./test.txt) // 写入文件内容 fs.writeFileSync(./test1.txt, data) 2.方式二&…...

XML Group端口详解

在XML数据映射过程中&#xff0c;经常需要对数据进行分组聚合操作。例如&#xff0c;当处理包含多个物料明细的XML文件时&#xff0c;可能需要将相同物料号的明细归为一组&#xff0c;或对相同物料号的数量进行求和计算。传统实现方式通常需要编写脚本代码&#xff0c;增加了开…...

第19节 Node.js Express 框架

Express 是一个为Node.js设计的web开发框架&#xff0c;它基于nodejs平台。 Express 简介 Express是一个简洁而灵活的node.js Web应用框架, 提供了一系列强大特性帮助你创建各种Web应用&#xff0c;和丰富的HTTP工具。 使用Express可以快速地搭建一个完整功能的网站。 Expre…...

Cilium动手实验室: 精通之旅---20.Isovalent Enterprise for Cilium: Zero Trust Visibility

Cilium动手实验室: 精通之旅---20.Isovalent Enterprise for Cilium: Zero Trust Visibility 1. 实验室环境1.1 实验室环境1.2 小测试 2. The Endor System2.1 部署应用2.2 检查现有策略 3. Cilium 策略实体3.1 创建 allow-all 网络策略3.2 在 Hubble CLI 中验证网络策略源3.3 …...

ESP32 I2S音频总线学习笔记(四): INMP441采集音频并实时播放

简介 前面两期文章我们介绍了I2S的读取和写入&#xff0c;一个是通过INMP441麦克风模块采集音频&#xff0c;一个是通过PCM5102A模块播放音频&#xff0c;那如果我们将两者结合起来&#xff0c;将麦克风采集到的音频通过PCM5102A播放&#xff0c;是不是就可以做一个扩音器了呢…...

Python爬虫(一):爬虫伪装

一、网站防爬机制概述 在当今互联网环境中&#xff0c;具有一定规模或盈利性质的网站几乎都实施了各种防爬措施。这些措施主要分为两大类&#xff1a; 身份验证机制&#xff1a;直接将未经授权的爬虫阻挡在外反爬技术体系&#xff1a;通过各种技术手段增加爬虫获取数据的难度…...

pikachu靶场通关笔记22-1 SQL注入05-1-insert注入(报错法)

目录 一、SQL注入 二、insert注入 三、报错型注入 四、updatexml函数 五、源码审计 六、insert渗透实战 1、渗透准备 2、获取数据库名database 3、获取表名table 4、获取列名column 5、获取字段 本系列为通过《pikachu靶场通关笔记》的SQL注入关卡(共10关&#xff0…...

代码规范和架构【立芯理论一】(2025.06.08)

1、代码规范的目标 代码简洁精炼、美观&#xff0c;可持续性好高效率高复用&#xff0c;可移植性好高内聚&#xff0c;低耦合没有冗余规范性&#xff0c;代码有规可循&#xff0c;可以看出自己当时的思考过程特殊排版&#xff0c;特殊语法&#xff0c;特殊指令&#xff0c;必须…...

STM32---外部32.768K晶振(LSE)无法起振问题

晶振是否起振主要就检查两个1、晶振与MCU是否兼容&#xff1b;2、晶振的负载电容是否匹配 目录 一、判断晶振与MCU是否兼容 二、判断负载电容是否匹配 1. 晶振负载电容&#xff08;CL&#xff09;与匹配电容&#xff08;CL1、CL2&#xff09;的关系 2. 如何选择 CL1 和 CL…...

Kafka主题运维全指南:从基础配置到故障处理

#作者&#xff1a;张桐瑞 文章目录 主题日常管理1. 修改主题分区。2. 修改主题级别参数。3. 变更副本数。4. 修改主题限速。5.主题分区迁移。6. 常见主题错误处理常见错误1&#xff1a;主题删除失败。常见错误2&#xff1a;__consumer_offsets占用太多的磁盘。 主题日常管理 …...

阿里云Ubuntu 22.04 64位搭建Flask流程(亲测)

cd /home 进入home盘 安装虚拟环境&#xff1a; 1、安装virtualenv pip install virtualenv 2.创建新的虚拟环境&#xff1a; virtualenv myenv 3、激活虚拟环境&#xff08;激活环境可以在当前环境下安装包&#xff09; source myenv/bin/activate 此时&#xff0c;终端…...