Rust模糊测试库fuzzt的使用,fuzzt提供高效灵活的模糊测试工具以增强代码安全性

Rust模糊测试库fuzzt的使用,fuzzt提供高效灵活的模糊测试工具以增强代码安全性

Fuzzt是一个Rust实现的字符串相似度度量库,提供多种算法来计算字符串之间的相似度。这些算法可以帮助开发者进行模糊测试,增强代码的安全性。

主要功能

Fuzzt实现了以下字符串相似度度量算法:

  • Hamming
  • Levenshtein (距离和归一化版本)
  • Optimal string alignment
  • Damerau-Levenshtein (距离和归一化版本)
  • Jaro和Jaro-Winkler
  • Sørensen-Dice
  • Gestalt pattern matching

归一化版本返回0.0到1.0之间的值,其中1.0表示完全匹配。

新增功能

Fuzzt基于strsim-rs库,并添加了以下新功能:

  1. Gestalt pattern matching:Python difflib SequenceMatcher使用的算法
  2. Top-N matching:从选择集合中检索最佳N个匹配的方法
  3. Feature selection:允许选择仅需要的功能(度量),减少应用程序的内存占用

Top-N Matching

get_top_n方法从选择字符串集合中获取最佳匹配列表。这个方法受到Python fuzzywuzzy包(现在称为thefuzz)中extractBests方法的启发。

以下是get_top_n方法的示例:

extern crate fuzzt;
use fuzzt::{algorithms::NormalizedLevenshtein, get_top_n, processors::NullStringProcessor};

fn main() {
    let matches = get_top_n(
        "apple",
        &["apply", "apples", "ape", "applet", "applesauce"],
        Some(0.8),
        Some(3),
        Some(&NullStringProcessor),
        Some(&NormalizedLevenshtein),
    );
    assert_eq!(matches, ["apples", "applet", "apply"]);
}

功能选择

Fuzzt设计灵活,允许根据需要选择特定功能,有助于减少应用程序的占用空间并优化性能。

库包含以下功能:

  • damerau_levenshtein
  • gestalt
  • hamming
  • jaro
  • levenshtein
  • optimal_string_alignment
  • sorensen_dice

默认情况下,所有功能都包含在内。但可以通过在Cargo.toml中指定所需功能来选择:

[dependencies]
fuzzt = { version = "*", default-features = false, features = ["levenshtein", "jaro"] }

安装

将Fuzzt添加到项目中:

cargo add fuzzt

使用示例

extern crate fuzzt;

use fuzzt::{
    damerau_levenshtein, hamming, jaro, jaro_winkler, levenshtein, normalized_damerau_levenshtein,
    normalized_levenshtein, osa_distance, sequence_matcher, sorensen_dice,
};

fn main() {
    match hamming("hamming", "hammers") {
        Ok(distance) => assert_eq!(3, distance),
        Err(why) => panic!("{:?}", why),
    }

    assert_eq!(levenshtein("kitten", "sitting"), 3);
    assert!((normalized_levenshtein("kitten", "sitting") - 0.571).abs() < 0.001);
    assert_eq!(osa_distance("ac", "cba"), 3);
    assert_eq!(damerau_levenshtein("ac", "cba"), 2);
    assert!((normalized_damerau_levenshtein("levenshtein", "löwenbräu") - 0.272).abs() < 0.001);
    assert_eq!(jaro("Friedrich Nietzsche", "Jean-Paul Sartre"), 0.3918859649122807);
    assert_eq!(
        jaro_winkler("cheeseburger", "cheese fries"),
        0.8666666666666666
    );
    assert_eq!(
        sorensen_dice("web applications", "applications of the web"),
        0.7878787878787878
    );
    assert_eq!(
        sequence_matcher("this is a test", "this is a test!"),
        0.965517241

1 回复

Rust模糊测试库fuzzt使用指南

介绍

fuzzt是一个Rust语言的模糊测试库,它提供了高效且灵活的模糊测试工具,帮助开发者发现代码中的潜在安全问题。fuzzt通过生成大量随机输入来测试程序的边界条件,特别适合用于测试解析器、协议实现和其他输入处理相关的代码。

主要特性

  • 高效的输入生成和变异策略
  • 支持结构化模糊测试
  • 可定制的测试策略
  • 与Rust测试框架良好集成
  • 提供崩溃重现功能

完整示例

下面是一个完整的fuzzt使用示例,展示了从基本使用到结构化测试的全过程:

use fuzzt::{FuzzMutator, FuzzRunner, FuzzStrategy, StructuredFuzz};
use rand::Rng;

// 1. 基本使用示例
fn basic_fuzzing_example() {
    fn test_input_parser(input: &[u8]) {
        // 测试输入解析器
        if input.len() > 5 && input[0] == b'A' && input[1] == b'B' && input[2] == b'C' {
            panic!("Detected vulnerable input pattern");
        }
    }

    let mut runner = FuzzRunner::new(test_input_parser);
    runner.set_max_len(512); // 限制输入最大长度
    
    match runner.fuzz(5000) {
        Some(crash_input) => println!("Crash found with input: {:?}", crash_input),
        None => println!("No crashes detected in basic test"),
    }
}

// 2. 结构化模糊测试示例
#[derive(Clone, Debug)]
struct HttpRequest {
    method: String,
    path: String,
    headers: Vec<(String, String)>,
    body: Vec<u8>,
}

impl StructuredFuzz for HttpRequest {
    fn fuzz(&mut self, mutator: &mut FuzzMutator) {
        mutator.fuzz(&mut self.method);
        mutator.fuzz(&mut self.path);
        mutator.fuzz(&mut self.headers);
        mutator.fuzz(&mut self.body);
    }
}

fn structured_fuzzing_example() {
    fn test_http_handler(request: &HttpRequest) {
        // 测试HTTP请求处理器
        if request.method == "GET" && request.path.contains("../") {
            panic!("Potential path traversal attack detected");
        }
        
        if request.headers.iter().any(|(k, v)| k.len() > 1024 || v.len() > 8192) {
            panic!("Oversized header detected");
        }
    }

    let initial = HttpRequest {
        method: "GET".to_string(),
        path: "/".to_string(),
        headers: vec![("Host".to_string(), "localhost".to_string())],
        body: vec![],
    };

    let mut runner = FuzzRunner::new(test_http_handler)
        .with_structured_input(initial);
    
    runner.fuzz(3000);
}

// 3. 自定义变异策略示例
struct ByteFlipStrategy;

impl FuzzStrategy for ByteFlipStrategy {
    fn mutate(&self, data: &mut Vec<u8>, mutator: &mut FuzzMutator) {
        // 随机翻转字节中的位
        if !data.is_empty() {
            let index = mutator.rng.gen_range(0..data.len());
            let bit = mutator.rng.gen_range(0..8);
            data[index] ^= 1 << bit;
        }
    }
}

fn custom_strategy_example() {
    fn test_buffer_overflow(input: &[u8]) {
        // 测试缓冲区处理
        if input.len() > 128 {
            panic!("Potential buffer overflow detected");
        }
    }

    let mut runner = FuzzRunner::new(test_buffer_overflow)
        .with_strategy(ByteFlipStrategy);
    
    runner.fuzz(2000);
}

// 4. 集成测试示例
#[cfg(test)]
mod integration_tests {
    use super::*;
    
    #[test]
    fn fuzz_json_parser() {
        let mut runner = FuzzRunner::new(|data| {
            // 简单模拟JSON解析器测试
            if data.starts_with(b"{") && data.ends_with(b"}") {
                if data.len() > 1000 {
                    panic!("Oversized JSON input");
                }
                
                // 模拟检查JSON深度
                let depth = data.iter().filter(|&&b| b == b'{' || b == b'}').count();
                if depth > 20 {
                    panic!("Excessive JSON nesting depth");
                }
            }
        });
        
        assert!(runner.fuzz(1000).is_none(), "Found crashing JSON input");
    }
}

fn main() {
    println!("Running basic fuzzing example...");
    basic_fuzzing_example();
    
    println!("\nRunning structured fuzzing example...");
    structured_fuzzing_example();
    
    println!("\nRunning custom strategy example...");
    custom_strategy_example();
    
    println!("\nAll fuzzing examples completed!");
}

最佳实践

  1. 从简单输入开始:初始使用小的、简单的输入样本
  2. 逐步增加复杂性:随着测试进展增加输入大小和复杂度
  3. 关注代码覆盖率:确保模糊测试能覆盖大部分代码路径
  4. 重现崩溃:保存导致崩溃的输入以便调试
  5. 持续运行:将模糊测试集成到CI/CD流程中

这个完整示例展示了fuzzt的主要功能,包括基本使用、结构化测试、自定义变异策略和测试集成。你可以根据实际需求调整和扩展这些示例。

回到顶部