本文是“开源安全软件工程实践分析”结对练习的第二部分,聚焦于OWASP ZAP主动扫描模块的精读与代码质量评估。我们将从顺序图与类图复原、代码标注、静态分析工具使用、人工代码审查到结对协作反思,完整呈现一次深度的代码级逆向工程实践。

一、精读模块选择

项目 内容
项目名称 OWASP ZAP (Zed Attack Proxy)
精读模块 主动扫描插件模块(zap-extensions/ascanrules
代码规模 约3200行(核心检测规则)
模块路径 zap-extensions/addOns/ascanrules/src/main/java/org/zaproxy/zap/extension/ascanrules/

选择理由

考量维度 说明
逻辑复杂 包含SQL注入、XSS、命令注入等多种漏洞检测算法
安全关键 直接体现Web漏洞检测的核心算法,是扫描器的“心脏”
设计典型 涉及策略模式、工厂模式、模板方法模式等多种设计模式
代码规模适中 约3200行,符合作业要求

二、任务1:详细设计复原

2.1 顺序图(主动扫描命令注入检测流程)

场景描述

该场景展示ZAP如何对目标URL的一个参数进行命令注入漏洞检测,从接收扫描任务到上报漏洞的完整处理流程。

顺序图(文本表示)

text

用户 → ActiveScanPanel : 1. 点击“主动扫描”
ActiveScanPanel → ScanController : 2. 添加扫描任务
ScanController → ActiveScanner : 3. 提交扫描任务
ActiveScanner → PluginFactory : 4. 获取插件实例
PluginFactory --> ActiveScanner : 5. 返回插件列表
ActiveScanner → CommandInjectionScanRule : 6. 遍历参数执行扫描
CommandInjectionScanRule → CommandInjectionScanRule : 7. 构造攻击请求
CommandInjectionScanRule → HttpSender : 8. 发送HTTP请求
HttpSender --> CommandInjectionScanRule : 9. 返回响应
CommandInjectionScanRule → CommandInjectionScanRule : 10. 匹配漏洞特征
CommandInjectionScanRule --> AbstractPlugin : 11. 上报告警(发现漏洞)
AbstractPlugin --> ActiveScanPanel : 12. 显示扫描结果

顺序图

顺序图解释
要素 说明
输入 用户指定的目标URL、扫描策略配置
输出 漏洞告警(漏洞类型、风险等级、证据URL)
核心决策点 ① 参数是否需要测试 ② Payload是否触发漏洞 ③ 误报过滤

2.2 详细类图

类图

核心类清单
类名 类型 职责
Extension 接口 定义ZAP扩展插件的基本契约
Plugin 接口 定义扫描插件的核心方法
ActiveScanExtension 实现类 管理主动扫描扩展的生命周期
AbstractPlugin 抽象类 提供扫描插件的通用功能(HTTP发送、告警上报)
ScanController 管理扫描队列和并发控制
HttpSender 封装HTTP请求发送逻辑
Alert.Builder 建造者类 构建标准化的漏洞告警对象
CommandInjectionScanRule 实现类 命令注入检测的具体实现
CrossSiteScriptingScanRule 实现类 XSS检测的具体实现
类关系说明
关系 参与类 说明
实现 ActiveScanExtension → Extension 扩展实现接口
实现 AbstractPlugin → Plugin 抽象插件实现接口
继承 CommandInjectionScanRule → AbstractPlugin 具体规则继承抽象插件
关联 ActiveScanExtension → ScanController 1:1持有关系
组合 ScanController → ActiveScanner 1:1..*管理关系
依赖 AbstractPlugin → HttpSender 使用关系
使用 AbstractPlugin → Alert.Builder 建造者模式
设计模式识别
模式 应用位置 说明
策略模式 AbstractPlugin + 子类 不同漏洞检测算法作为可互换策略
工厂模式 PluginFactory 动态创建检测插件实例
模板方法模式 AbstractPlugin.scan() 定义扫描骨架,子类实现具体逻辑
建造者模式 Alert.Builder 构建复杂告警对象
单例模式 ScanController 全局唯一扫描调度器

三、任务2:代码标注

函数1:命令注入检测核心逻辑

属性 内容
所属类 CommandInjectionScanRule
主要功能 执行基于反馈的命令注入检测
应用流程 scan()遍历参数时调用
核心思路 根据OS类型选择Payload(;ls&dir),使用无害化命令
复杂度 O(N×M),N为参数数,M为Payload数

java

private void testCommandInjection(HttpMessage msg, String param, String payload) {
    String attack = getPayload(payload, osType);      // 1. 构造攻击载荷
    HttpMessage newMsg = getNewMsg(msg, param, attack); // 2. 发送请求
    if (match(newMsg, getEvidence())) {                // 3. 匹配响应
        newAlert(newMsg).raise();                       // 4. 上报漏洞
    }
}

设计权衡:使用字符串匹配而非语义分析,效率高但可能误报。ZAP选择“宁可错杀,不可放过”的保守策略。


函数2:HTML上下文分析器

属性 内容
所属类 HtmlContextAnalyser
主要功能 定位字符串在HTML中的DOM上下文
应用流程 XSS检测发现反射点后调用
核心思路 Jericho解析DOM树,判断在<script>还是属性值中
复杂度 O(D),D为文档深度

java

public HtmlContext getHtmlContext(String html, int matchStart, int matchEnd) {
    HtmlElement enclosing = jerichoSource.getElementByStart(matchStart);
    if (enclosing.getName().equals("script")) {
        return HtmlContext.SCRIPT_BLOCK;
    }
    // ...
}

潜在缺陷:非标准HTML可能导致解析错误,影响Payload注入。


函数3:SQL注入布尔盲注判定

属性 内容
所属类 SqlInjectionPocBuilder
主要功能 通过响应差异判断SQL注入
应用流程 错误回显禁用时的兜底方案
核心思路 1=11=2对比,差分分析
复杂度 O(1)但网络开销大

java

public boolean isVulnerable(BooleanBlindInjection injection) {
    HttpMessage trueMsg = send(injection.getTruePayload());   // 真值请求
    HttpMessage falseMsg = send(injection.getFalsePayload()); // 假值请求
    return trueMsg.getResponseLength() != falseMsg.getResponseLength();
}

核心难点:CSRF Token等动态内容会干扰长度比较,需要相似度算法过滤。


函数4:抽象插件的HTTP发送器

属性 内容
所属类 AbstractPlugin
主要功能 封装HTTP请求发送,统一异常处理
应用流程 所有子类插件频繁调用
核心思路 模板方法模式 + 容错设计
复杂度 I/O阻塞操作

java

protected HttpMessage sendAndReceive(HttpMessage msg, boolean followRedirect) {
    HttpSender sender = getParent().getHttpSender();
    try {
        sender.sendAndReceive(msg, followRedirect);
    } catch (HttpMalformedHeaderException e) {
        LOG.warn("Malformed header", e);  // 异常不中断扫描
    }
    return msg;
}

性能优化HttpSender内部线程池管理连接,避免DDoS目标服务器。


函数5:告警构建与上报

属性 内容
所属类 AbstractPlugin / Alert
主要功能 创建标准化漏洞告警
应用流程 确认漏洞后生成报告数据
核心思路 建造者模式 + 证据固化
复杂度 O(1)对象创建

java

public AlertBuilder newAlert(HttpMessage msg) {
    return new AlertBuilder()
        .setName(this.getName())
        .setRisk(this.getRisk())
        .setConfidence(Confidence.MEDIUM)
        .setMessage(msg)
        .setParam(msg.getParams().get(0).getName());
}

设计亮点:链式调用让审计人员一眼看出风险等级和置信度如何设定。

四、任务3:代码质量分析与审查

4.1 SpotBugs静态扫描

扫描结果摘要
指标 数值
总问题数 42
高严重等级 3个
中严重等级 15个
低严重等级 24个
告警1:NP_NULL_ON_SOME_PATH
属性 内容
严重等级
位置 XxeScanRule.java:232
问题 getCallbackService()可能返回null,未检查直接调用
修复 增加空值检查

java

// 修复前
getCallbackService().registerHandler(handler);

// 修复后
CallbackService service = getCallbackService();
if (service != null) {
    service.registerHandler(handler);
}
告警2:DM_DEFAULT_ENCODING
属性 内容
严重等级
位置 HttpHeader.java:156
问题 String.getBytes()依赖系统默认编码
修复 显式指定UTF-8

java

// 修复前
byte[] data = str.getBytes();

// 修复后
byte[] data = str.getBytes(StandardCharsets.UTF_8);
告警3:RCN_REDUNDANT_NULLCHECK
属性 内容
严重等级
位置 ActiveScan.java:440
问题 变量已被断言非空,再次检查
修复 删除冗余检查

4.2 人工审查

维度一:异常处理

实例1:吞没异常

java

// 位置:AbstractPlugin.java:305
try {
    sendAndReceive(msg);
} catch (SocketException e) {
    LOG.warn("Connection reset");  // 异常被吞没
}
  • 问题:网络抖动时直接放弃,无重试机制

  • 建议:引入指数退避重试策略

实例2:敏感信息泄露

  • 位置SqlInjectionScanRule.java:120

  • 问题:SQL异常堆栈写入告警描述

  • 建议:脱敏处理,仅保留错误类型


维度二:安全编码

实例1:无害化载荷设计(优点)

  • 位置CommandInjectionScanRule.java

  • 优点:使用echo ZAPsleep 5,而非rm -rf

  • 评价:遵循安全测试的“不破坏”原则

实例2:潜在的日志注入

  • 位置Alert.java:88

  • 问题:URL参数直接拼接到日志

  • 建议:使用log.info("Param: {}", param)占位符


维度三:性能效率

实例1:正则表达式未预编译

java

// 位置:CrossSiteScriptingScanRule.java
// 问题:循环内定义Pattern
Pattern pattern = Pattern.compile("(<script.*?</script>)");
  • 建议:提取为static final常量

实例2:响应体重复转换

  • 位置PassiveScanThread.java

  • 问题:多次调用msg.getResponseBody().toString()

  • 建议:缓存到局部变量

五、任务4:结对过程记录

5.1 分工描述

子任务 Driver Navigator
UML类图绘制 张雯雯 杨雯惠
顺序图梳理 张雯雯 杨雯惠
代码标注 杨雯惠 张雯雯
SpotBugs扫描 张雯雯 杨雯惠
人工审查 杨雯惠 张雯雯

角色切换时机:遇到设计模式分歧时互换角色,由Navigator操作工具,Driver查阅文档验证。

AI辅助:将AI作为“第三方领航员”,提问晦涩代码含义,由另一人验证回答正确性。


5.2 协作感受

1+1 > 2实证

案例一:张雯雯分析XxeScanRule时认为逻辑正确,杨雯惠指出getCallbackService()可能返回null——直接定位SpotBugs高优先级告警。

案例二:张雯雯标注“解析HTML”后,杨雯惠追问“如何解析”,引导发现Jericho库DOM树机制,复杂度从O(n)修正为O(D)。

协作障碍与解决
障碍 解决方案
对策略模式的界定分歧 查阅《Head First设计模式》+源码验证
工具环境不一致 统一使用IntelliJ IDEA + SpotBugs

5.3 量化评估

甘特图

协作能力雷达图
维度 张雯雯 杨雯惠
代码规范 8 7
设计能力 7 9
沟通主动性 9 8
问题预见性 6 9
知识传递 8 7

雷达图显示能力互补:张雯雯沟通主动性强,杨雯惠设计能力和问题预见性突出。


六、总结与反思

核心发现

维度 发现
架构设计 策略模式+工厂模式实现插件化,扩展性强
安全编码 使用无害化Payload,遵循“不破坏”原则
代码缺陷 存在空指针风险、默认编码依赖等可修复问题
协作效果 能力互补实现1+1>2,前期设计投入减少后期返工

工具使用体验

SpotBugs能够有效发现潜在缺陷(如空指针、编码问题),但存在少量误报,需人工验证。建议与实际代码审查结合使用。


报告完成日期:2026年3月31日
结对成员:张雯雯、杨雯惠

 

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐