文章目录
前言
在安全测试工作中,插件工具的配置管理往往直接影响测试效率与准确性。无论是临时请求头的定制、规则列表的筛选逻辑,还是各类复选框的状态设置,都需要测试人员根据场景反复调整。然而,手动重复配置不仅耗时,更可能因操作疏忽导致测试环境不一致,进而影响结果可信度。尤其在团队协作场景中,如何快速共享配置、复现测试环境,成为提升工作流效率的关键问题。
基于此,我在Burp插件的“保存/恢复”标签页中新增了配置保存与恢复功能。该功能允许测试人员将当前所有配置(包括临时请求头、复选框状态、规则列表等核心信息)导出为JSON文件,也可通过本地文件快速恢复配置,从而实现“一次配置,多次复用”的效果。本文将详细解析该功能的实现逻辑,帮助安全测试人员理解其原理与使用价值。
实现的插件效果如下,文章结尾查看完整代码。
一、功能需求与设计思路
1.1 核心功能需求
根据安全测试场景的实际需求,该功能需实现以下目标:
- 在插件面板“保存/恢复”标签页中,新增UI元素:分割线、“配置状态:”标签、“保存”和“恢复”按钮;
- “保存”按钮:将当前配置中心的所有设置(临时请求头、复选框状态、规则列表等)保存为本地JSON文件;
- “恢复”按钮:读取本地JSON配置文件,将配置还原到插件面板中并生效;
- 配置内容需包含:
- 临时请求头(Base64编码,含换行符);
- 4个复选框状态(“检查未授权”“忽略请求响应码204|304”等);
- 规则列表的逻辑关系(And/Or);
- 配置规则(Base64编码,含规则类型与内容);
- 保存/恢复相关设置(文件类型、导出过滤下拉框选项,“去除重复项”复选框状态)。
1.2 设计思路
为实现上述需求,我们采用“UI布局扩展+工具类封装+配置序列化/反序列化”的方案:
- UI层:通过Swing组件扩展现有面板,添加所需元素并绑定按钮事件;
- 工具类:封装
ConfigUtil
工具类,集中实现配置的保存(序列化)与恢复(反序列化)逻辑; - 数据处理:使用Base64编码处理含特殊字符的文本(如请求头、规则内容),避免JSON序列化异常;通过Gson库实现配置与JSON文件的转换,保证数据格式一致性。
二、代码实现解析
2.1 依赖添加:引入JSON处理库
配置的保存与恢复需要将内存中的配置数据与本地JSON文件互转,因此需引入Google的Gson库(一款高效的JSON处理工具)。在build.gradle.kts
中添加依赖:
dependencies {
implementation("com.google.code.gson:gson:2.13.1")
}
解析:Gson库支持将Java对象(如Map
、自定义类)直接序列化为JSON字符串,也可将JSON字符串反序列化为对象,大幅简化了文件读写逻辑。选择2.13.1版本为当前最新版本。
2.2 UI布局扩展:添加交互元素
为在现有“保存/恢复”标签页中新增元素,需修改面板初始化方法initializeComponents
,添加分割线、标签和按钮。
2.2.1 新增分割线与标签
// 添加分割线
JSeparator separator = new JSeparator(SwingConstants.HORIZONTAL);
separator.setAlignmentX(Component.LEFT_ALIGNMENT);
saveRestoreSettingsPanel.add(separator);
// 添加配置状态标签
JPanel configStatusPanel = new JPanel(new FlowLayout(FlowLayout.LEFT));
configStatusPanel.setAlignmentX(Component.LEFT_ALIGNMENT);
configStatusPanel.add(new JLabel("配置状态:"));
saveRestoreSettingsPanel.add(configStatusPanel);
解析:
- 分割线(
JSeparator
)用于视觉上区分“导出报告”按钮与新增功能区域,提升UI层次感; - “配置状态:”标签(
JLabel
)用于提示后续按钮的功能范围,帮助测试人员快速理解交互目标; - 使用
FlowLayout.LEFT
布局,确保元素左对齐,符合常规UI阅读习惯。
2.2.2 新增“保存”与“恢复”按钮
// 添加保存和恢复按钮
JPanel configButtonPanel = getConfigButtonPanel();
saveRestoreSettingsPanel.add(configButtonPanel);
private JPanel getConfigButtonPanel() {
JPanel configButtonPanel = new JPanel(new FlowLayout(FlowLayout.LEFT));
configButtonPanel.setAlignmentX(Component.LEFT_ALIGNMENT);
JButton saveConfigButton = new JButton("保存");
saveConfigButton.addActionListener(e -> ConfigUtil.saveConfiguration(this, permissionTestPanel, fileTypeComboBox, exportFilterComboBox, removeDuplicatesCheckBox));
JButton restoreConfigButton = new JButton("恢复");
restoreConfigButton.addActionListener(e -> ConfigUtil.restoreConfiguration(this, permissionTestPanel, fileTypeComboBox, exportFilterComboBox, removeDuplicatesCheckBox));
configButtonPanel.add(saveConfigButton);
configButtonPanel.add(restoreConfigButton);
return configButtonPanel;
}
解析:
- 按钮面板(
configButtonPanel
)采用左对齐流式布局,确保“保存”“恢复”按钮紧凑排列; - 按钮点击事件通过
addActionListener
绑定到ConfigUtil
的静态方法,将核心逻辑与UI层解耦,便于后续维护; - 方法参数传递了面板实例(
permissionTestPanel
)、下拉框(fileTypeComboBox
等)和复选框(removeDuplicatesCheckBox
),确保工具类能获取当前所有配置数据。
2.3 核心工具类:ConfigUtil的实现
ConfigUtil
是功能实现的核心,封装了配置的保存(saveConfiguration
)与恢复(restoreConfiguration
)方法,负责数据的采集、编码、序列化与反序列化。
2.3.1 保存配置:saveConfiguration方法
该方法的核心流程为:打开文件选择器→采集当前配置数据→编码与封装→序列化并写入JSON文件。
步骤1:文件选择与校验
JFileChooser fileChooser = new JFileChooser();
fileChooser.setDialogTitle("保存配置文件");
fileChooser.setSelectedFile(new File("PermissionTest_Config.json"));
int userSelection = fileChooser.showSaveDialog(parent);
if (userSelection == JFileChooser.APPROVE_OPTION) {
File fileToSave = fileChooser.getSelectedFile();
String filePath = fileToSave.getAbsolutePath();
// 确保文件有.json扩展名
if (!filePath.endsWith(".json")) {
filePath += ".json";
fileToSave = new File(filePath);
}
// ...后续逻辑
}
解析:
- 使用
JFileChooser
提供可视化文件选择界面,默认文件名设为PermissionTest_Config.json
,便于用户识别; - 强制添加
.json
扩展名,避免因用户输入错误导致文件格式异常,保证后续恢复时能正确解析。
步骤2:配置数据采集与编码
配置数据分为“配置中心”和“保存/恢复”两部分,需分别采集并封装为Map
结构。
(1)配置中心数据采集
// 保存配置中心的设置
Map<String, Object> configCenter = new HashMap<>();
// 临时请求头:Base64编码
String tempHeaders = permissionTestPanel.getConfigPanel().getTempHeaders();
String encodedHeaders = Base64.getEncoder().encodeToString(tempHeaders.getBytes());
configCenter.put("tempHeaders", encodedHeaders);
解析:
- 临时请求头可能包含换行符、特殊字符(如
:
、=
),直接存入JSON可能导致格式错误;使用Base64编码将其转为纯文本,确保序列化时不破坏JSON结构。
// 复选框状态:JSON格式
Map<String, Boolean> checkBoxes = new HashMap<>();
checkBoxes.put("checkUnauthorized", permissionTestPanel.getConfigPanel().isUnauthorizedCheckSelected());
checkBoxes.put("ignore204304", permissionTestPanel.getConfigPanel().isIgnore204304Checked());
checkBoxes.put("avoid304", permissionTestPanel.getConfigPanel().isAvoid304Checked());
checkBoxes.put("useConfigRules", permissionTestPanel.getConfigPanel().isUseConfigRulesChecked());
configCenter.put("checkBoxes", checkBoxes);
解析:
- 4个复选框状态直接以
Boolean
类型存入Map
,反映安全测试中的关键配置(如是否检查未授权、是否忽略特定响应码),确保恢复后测试逻辑与原配置一致。
(2)规则列表数据采集
规则列表包括低权限规则、未授权规则、拦截过滤器规则,需保存逻辑关系(And/Or)与规则内容(类型+内容)。
// 低权限规则面板设置
Map<String, Object> lowPrivilegeRules = new HashMap<>();
lowPrivilegeRules.put("logicRelation", permissionTestPanel.getConfigPanel().getLowPrivilegeRulePanel().getLogicRelation());
// 低权限规则内容Base64编码
StringBuilder lowPrivilegeRulesContent = new StringBuilder();
for (RulePanel.Rule rule : permissionTestPanel.getConfigPanel().getLowPrivilegeRulePanel().getRules()) {
lowPrivilegeRulesContent.append(rule.getType()).append("|").append(rule.getContent()).append("\n");
}
String encodedLowPrivilegeRules = Base64.getEncoder().encodeToString(lowPrivilegeRulesContent.toString().getBytes());
lowPrivilegeRules.put("rules", encodedLowPrivilegeRules);
configCenter.put("lowPrivilegeRules", lowPrivilegeRules);
解析:
- 规则逻辑关系(And/Or)决定了多条规则的生效条件(如“同时满足”或“任一满足”),是安全测试中规则执行的核心逻辑,必须准确保存;
- 规则内容按“类型|内容”格式拼接(如
"URL|/admin/*"
),每条规则占一行(\n
分隔),便于解析; - 同样使用Base64编码规则内容,避免特殊字符(如
|
、换行符)破坏JSON结构。
未授权规则、拦截过滤器规则的采集逻辑与低权限规则一致,此处不再赘述。
(3)保存/恢复设置采集
// 保存/恢复设置
Map<String, Object> saveRestore = new HashMap<>();
saveRestore.put("fileType", fileTypeComboBox.getSelectedItem());
saveRestore.put("exportFilter", exportFilterComboBox.getSelectedItem());
saveRestore.put("removeDuplicates", removeDuplicatesCheckBox.isSelected());
config.put("saveRestore", saveRestore);
解析:
- 保存文件类型、导出过滤选项和“去除重复项”状态,确保恢复后“保存/恢复”标签页的自身配置与原状态一致。
步骤3:序列化与写入文件
// 使用Gson将配置写入文件
Gson gson = new GsonBuilder().setPrettyPrinting().create();
try (FileOutputStream fos = new FileOutputStream(fileToSave)) {
fos.write(gson.toJson(config).getBytes());
}
解析:
GsonBuilder().setPrettyPrinting()
生成格式化的JSON,便于测试人员手动查看或编辑配置文件;- 使用
try-with-resources
语法自动关闭文件流,避免资源泄露。
2.3.2 恢复配置:restoreConfiguration方法
该方法的核心流程为:打开文件选择器→读取JSON文件→解析并反序列化→还原配置到UI组件。
步骤1:文件选择与读取
JFileChooser fileChooser = new JFileChooser();
fileChooser.setDialogTitle("选择配置文件");
int userSelection = fileChooser.showOpenDialog(parent);
if (userSelection == JFileChooser.APPROVE_OPTION) {
File fileToOpen = fileChooser.getSelectedFile();
// 使用Gson读取配置文件
Gson gson = new Gson();
Map<String, Object> config;
try (FileReader reader = new FileReader(fileToOpen)) {
config = gson.fromJson(reader, new TypeToken<Map<String, Object>>(){}.getType());
}
// ...后续逻辑
}
解析:
- 通过
JFileChooser
选择本地JSON文件,使用Gson
将文件内容反序列化为Map<String, Object>
,便于按键提取配置项。
步骤2:配置还原到UI组件
(1)临时请求头还原
// 恢复临时请求头
Object encodedHeadersObj = configCenter.get("tempHeaders");
if (encodedHeadersObj instanceof String encodedHeaders) {
byte[] decodedBytes = Base64.getDecoder().decode(encodedHeaders);
String tempHeaders = new String(decodedBytes);
permissionTestPanel.getConfigPanel().setTempHeaderContent(tempHeaders);
}
解析:
- 读取Base64编码的请求头,解码后通过
setTempHeaderContent
方法设置到UI组件,还原原始请求头(含换行符)。
(2)复选框状态还原
// 恢复复选框状态
Object checkBoxesObj = configCenter.get("checkBoxes");
if (checkBoxesObj instanceof Map) {
Map<String, Object> checkBoxes = convertMap(checkBoxesObj);
Object checkUnauthorizedObj = checkBoxes.get("checkUnauthorized");
if (checkUnauthorizedObj instanceof Boolean) {
permissionTestPanel.getConfigPanel().setUnauthorizedCheck((Boolean) checkUnauthorizedObj);
}
// 其他复选框还原逻辑类似
}
解析:
- 通过
convertMap
方法将Object
转为Map<String, Object>
(避免类型转换异常),按键提取布尔值并设置到对应复选框。
(3)规则列表还原
// 恢复低权限规则
Object lowPrivilegeRulesObj = configCenter.get("lowPrivilegeRules");
if (lowPrivilegeRulesObj instanceof Map) {
Map<String, Object> lowPrivilegeRules = convertMap(lowPrivilegeRulesObj);
// 还原逻辑关系
Object logicRelationObj = lowPrivilegeRules.get("logicRelation");
if (logicRelationObj instanceof String) {
permissionTestPanel.getConfigPanel().getLowPrivilegeRulePanel().setLogicRelation((String) logicRelationObj);
}
// 还原规则内容
Object encodedRulesObj = lowPrivilegeRules.get("rules");
if (encodedRulesObj instanceof String encodedRules) {
byte[] decodedBytes = Base64.getDecoder().decode(encodedRules);
String rulesContent = new String(decodedBytes);
permissionTestPanel.getConfigPanel().getLowPrivilegeRulePanel().loadRules(rulesContent);
}
}
解析:
- 逻辑关系通过
setLogicRelation
方法直接设置到下拉框; - 规则内容解码后调用
loadRules
方法解析(按\n
分割行,按|
分割类型与内容),并添加到规则表格中。
拦截过滤器规则的还原使用loadRulesForConfigRestore
方法,与普通规则的区别是会清空默认规则,确保完全覆盖为配置文件中的内容。
(4)保存/恢复设置还原
// 恢复保存/恢复设置
Object saveRestoreObj = config.get("saveRestore");
if (saveRestoreObj instanceof Map) {
Map<String, Object> saveRestore = convertMap(saveRestoreObj);
Object fileTypeObj = saveRestore.get("fileType");
if (fileTypeObj != null) {
fileTypeComboBox.setSelectedItem(fileTypeObj.toString());
}
// 导出过滤和去除重复项还原逻辑类似
}
解析:
- 下拉框选项通过
setSelectedItem
设置(直接使用字符串匹配); - 复选框状态通过
setSelected
方法还原。
2.3.3 辅助方法:convertMap
private static Map<String, Object> convertMap(Object obj) {
if (obj instanceof Map) {
// 使用Gson将对象重新序列化和反序列化
Gson gson = new Gson();
String json = gson.toJson(obj);
return gson.fromJson(json, new TypeToken<Map<String, Object>>(){}.getType());
}
return new HashMap<>();
}
解析:
- 由于Gson反序列化的
Map
可能包含嵌套的LinkedTreeMap
(Gson内部类型),直接转换为Map<String, Object>
可能出现类型异常; - 通过“序列化→反序列化”的二次处理,确保返回标准的
Map<String, Object>
,避免后续取值时的类型错误。
2.4 相关面板的方法补充
为支持配置的采集与还原,需在现有面板中添加getter/setter方法,暴露配置数据或提供设置入口。
2.4.1 PermissionTestPanel:暴露配置面板
/**
* 获取配置面板
* @return ConfigPanel实例
*/
public ConfigPanel getConfigPanel() {
return configPanel;
}
解析:PermissionTestPanel
是主面板,通过getConfigPanel
方法允许ConfigUtil
访问内部的ConfigPanel
(包含请求头、复选框等配置)。
2.4.2 RulePanel:规则操作方法
/**
* 设置逻辑关系
* @param logicRelation 逻辑关系 ("And" 或 "Or")
*/
public void setLogicRelation(String logicRelation) {
logicComboBox.setSelectedItem(logicRelation);
}
/**
* 从字符串加载规则
* @param rulesContent 规则内容字符串
*/
public void loadRules(String rulesContent) {
// 清空现有规则
clearAllRules();
// 解析规则内容
String[] lines = rulesContent.split("\n");
for (String line : lines) {
if (!line.trim().isEmpty()) {
String[] parts = line.split("\\|", 2);
if (parts.length == 2) {
Rule rule = new Rule(parts[0], parts[1]);
rules.add(rule);
Object[] rowData = {rule.getType(), rule.getContent()};
tableModel.addRow(rowData);
}
}
}
}
解析:
setLogicRelation
用于还原规则逻辑关系;loadRules
解析规则字符串(按\n
和|
分割),清空现有规则后添加新规则到表格,实现规则列表的完全替换。
2.4.3 InterceptFilterPanel:特殊规则还原方法
/**
* 从字符串加载规则(用于配置恢复,完全替换现有规则,包括默认规则)
* @param rulesContent 规则内容字符串
*/
public void loadRulesForConfigRestore(String rulesContent) {
// 清空现有规则(包括默认规则)
rules.clear();
tableModel.setRowCount(0);
ruleContentArea.setText("");
// 解析规则内容(同RulePanel的loadRules)
String[] lines = rulesContent.split("\n");
for (String line : lines) {
if (!line.trim().isEmpty()) {
String[] parts = line.split("\\|", 2);
if (parts.length == 2) {
Rule rule = new Rule(parts[0], parts[1]);
rules.add(rule);
Object[] rowData = {rule.getType(), rule.getContent()};
tableModel.addRow(rowData);
}
}
}
}
解析:拦截过滤器规则默认包含基础规则,恢复时需完全覆盖(而非追加),因此单独实现loadRulesForConfigRestore
方法,确保清空默认规则后再加载配置文件中的内容。
2.4.4 ConfigPanel:复选框状态设置
// 添加设置复选框状态的方法
public void setUnauthorizedCheck(boolean selected) {
unauthorizedCheck.setSelected(selected);
}
public void setIgnore204304Check(boolean selected) {
ignore204304Check.setSelected(selected);
}
public void setAvoid304Check(boolean selected) {
avoid304Check.setSelected(selected);
}
public void setUseConfigRulesCheck(boolean selected) {
useConfigRulesCheck.setSelected(selected);
}
解析:为4个核心复选框添加setter
方法,允许ConfigUtil
直接设置其选中状态,还原配置时无需暴露组件本身,符合封装原则。
三、功能价值与安全测试场景
3.1 提升测试效率
安全测试中,同一类场景(如API未授权测试)往往需要重复使用相同的请求头、规则列表。通过“保存→恢复”功能,测试人员可避免重复配置,将时间集中在核心测试逻辑上。
3.2 保证环境一致性
多人协作时,不同测试人员的本地配置可能存在差异(如规则逻辑、过滤条件),导致测试结果不可复现。通过共享JSON配置文件,团队可使用统一的测试环境,确保结果的可比性。
3.3 适配复杂配置场景
- 临时请求头:安全测试中常需添加自定义
Cookie
、Authorization
等头信息,Base64编码确保特殊字符(如;
、空格)不丢失; - 规则列表:按“类型|内容”格式保存的规则,既便于机器解析,也便于测试人员手动编辑(如通过JSON文件批量修改规则)。
总结
配置保存与恢复功能通过UI扩展、数据编码与序列化技术,为安全测试插件提供了可靠的配置管理能力。其核心价值在于:简化重复操作、保证环境一致性、适配复杂测试场景。
从技术实现来看,ConfigUtil
工具类通过Gson实现JSON转换,通过Base64处理特殊文本,结合面板方法的合理暴露,实现了配置的完整保存与还原。对于安全测试人员而言,无需关注底层实现细节,只需通过“保存”“恢复”按钮即可快速复用配置,显著提升工作效率。
本插件代码开源地址:Gitee代码仓