模糊测试
上一篇 / 下一篇 2007-08-30 10:58:56 / 个人分类:模糊测试
Elliotte Harold(elharo@metalab.unc.edu), 副教授, Polytechnic 大学
0H9XB0wq:PM
@0
2006 年 11 月 02 日
0J`_8F'M"BR$x/tm|0模糊测试(Fuzz testing )是一项对代码质量有着深远影响的简单技术。在本文中,Elliotte Rusty Harold 故意将随机的坏数据插入应用程序,以观察发生的结果。他也解释了如何使用如校验和、XML 数据存储及代码验证等防护性编码技术,来加固您的程序以抵制随机数据。他以一个练习进行总结,在练习中他以一个代码破坏者的角度进行思考 —— 这是一种用于防护代码的至关重要的技术。51Testing软件测试网FF)Z2no(M
多年来,我惊叹于有如此大量能够使 Microsoft Word 崩溃的坏文件。少数字节错位,会使整个应用程序毁于一旦。在旧式的、无内存保护的操作系统中,整个计算机通常就这样宕掉了。Word 为什么不能意识到它接收到了坏的数据,并发出一条错误信息呢?为什么它会仅仅因为少数字节被损坏就破坏自己的栈、堆呢?当然,Word 并不是惟一一个面对畸形文件时表现得如此糟糕的程序。
y:~ fl;O"a*O6D&ZI051Testing软件测试网V$O+^9F(XT+M9]3B AL.M本文介绍了一种试图避免这种灾难的技术。在模糊测试中,用随机坏数据(也称做fuzz)攻击一个程序,然后等着观察哪里遭到了破坏。模糊测试的技巧在于,它是不符合逻辑的:自动模糊测试不去猜测哪个数据会导致破坏(就像人工测试员那样),而是将尽可能多的杂乱数据投入程序中。由这个测试验证过的失败模式通常对程序员来说是个彻底的震憾,因为任何按逻辑思考的人都不会想到这种失败。
[%c b&BA0-]4a8|5vn:D0模糊测试是一项简单的技术,但它却能揭示出程序中的重要 bug。它能够验证出现实世界中的错误模式并在您的软件发货前对潜在的应当被堵塞的攻击渠道进行提示。51Testing软件测试网GXb$F([d
cr.A-| Go0模糊测试如何运行
~ekpgeL0!Wt:Z0Vw*A8SMvLe0模糊测试的实现是一个非常简单的过程:
$du-]K#s7L0- 准备一份插入程序中的正确的文件。
- 用随机数据替换该文件的某些部分。
- 用程序打开文件。
- 观察破坏了什么。
`3~ Ky/P"j*[N0可以用任意多种方式改变该随机数据。例如,可以将整个文件打乱,而不是仅替换其中的一部分,也可以将该文件限制为 ASCII 文本或非零字节。不管用什么方式进行分割,关键是将大量随机数据放入应用程序并观察出故障的是什么。
Nx9i ^-TT$B0
|
可以手动进行初始化测试,但要想达到最佳的效果则确实需要采用自动化模糊测试。在这种情况下,当面临破坏输入时首先需要为应用程序定义适当的错误行为。(如果当输入数据被破坏时,您发现程序正常运行,且未定义发生的事件,那么这就是第一个 bug。)随后将随机数据传递到程序中直到找到了一个文件,该文件不会触发适当的错误对话框、消息、异常,等等。存储并记录该文件,这样就能在稍后重现该问题。如此重复。
J hF`$m*l'I051Testing软件测试网~jO Z)a尽管模糊测试通常需要一些手动编码,但还有一些工具能提供帮助。例如,清单 1 显示了一个简单的 Java™ 类,该类随机更改文件的特定长度。我常愿意在开始的几个字节后面启动模糊测试,因为程序似乎更可能注意到早期的错误而不是后面的错误。(您的目的是想找到程序未检测到的错误,而不是寻找已经检测到的。)
P5^h,^?(V"`0`'t/IDq0清单 1. 用随机数据替换文件部分的类
-x6YT.g8B-O0
import java.io.*; import java.security.SecureRandom; import java.util.Random; public class Fuzzer { private Random random = new SecureRandom(); private int count = 1; public File fuzz(File in, int start, int length) throws IOException { byte[] data = new byte[(int) in.length()]; DataInputStream din = new DataInputStream(new FileInputStream(in)); din.readFully(data); fuzz(data, start, length); String name = "fuzz_" + count + "_" + in.getName(); File fout = new File(name); FileOutputStream ōut = new FileOutputStream(fout); out.write(data); out.close(); din.close(); count++; return fout; } // Modifies byte array in place public void fuzz(byte[] in, int start, int length) { byte[] fuzz = new byte[length]; random.nextBytes(fuzz); System.arraycopy(fuzz, 0, in, start, fuzz.length); } } |
Pp%H\$Dv0
|
模糊测试文件很简单。将其传至应用程序通常不那么困难。如 Applescrīpt 或 Perl 脚本语言通常是编写模糊测试的最佳选择。对于 GUI 程序,最困难的部分是辨认出应用程序是否检测出正确的故障模式。有时,最简单的方法是让一个人坐在程序前将每一个测试通过或失败的结果都标记下来。一定要将所有生成的随机测试用例单独地命名并保存下来,这样就能够重现这个过程中检测到的任何故障。
F8UZu0i6c051Testing软件测试网kR8`+QXr+U+x防护性编码51Testing软件测试网w,O/J%nX#c5`V-x2T
51Testing软件测试网,Y8wdvM@rbJ-d可靠的编码遵循了这样的基本原则:绝不会让程序中插入未经过一致性及合理性验证的外部数据。
!XR/eq(f6UY5w051Testing软件测试网EbEpOq如果从文件中读入一个数字并期望其为正数,那么,在使用其进行进一步处理前对其先验证一下。如果期望字符串只包含 ASCII 字母,请确定它确实是这样。如果认为文件包含一个四字节的整数倍的数据,请验证一下。一定不要假设任何外部提供的数据中的字符都会如您所料。
~&Bx1F o)w OU \ ^"dGQ051Testing软件测试网;\2S'ah$x w+|i2`U&v