├── .DS_Store
├── .idea
├── .gitignore
├── API-Highlighter.iml
├── compiler.xml
├── jarRepositories.xml
├── libraries
│ ├── Maven__net_portswigger_burp_extensions_montoya_api_2024_7.xml
│ ├── Maven__org_projectlombok_lombok_1_18_30.xml
│ └── Maven__org_yaml_snakeyaml_2_0.xml
├── misc.xml
├── modules.xml
├── uiDesigner.xml
└── vcs.xml
├── API-Highlighter.iml
├── README.md
├── assets
├── .DS_Store
├── image-20250131143303914.png
├── image-20250131143734141.png
├── image-20250131150531983.png
├── image-20250131151601732.png
├── image-20250131151831909.png
├── image-20250131152150163.png
├── image-20250131152224779.png
├── image-20250131152949132.png
├── image-20250131153024127.png
├── image-20250131153251402.png
├── image-20250131153522783.png
├── image-20250131153624442.png
├── image-20250131153719159.png
├── image-20250131153838072.png
├── image-20250131153912482.png
├── image-20250131155246057.png
├── image-20250131155558419.png
├── image-20250131155745214.png
├── image-20250131160031773.png
├── image-20250131201354108.png
├── image-20250131201535978.png
├── image-20250131203231727.png
├── image-20250131203259330.png
├── image-20250131204156562.png
├── image-20250131204216952.png
├── image-20250131204256345.png
├── image-20250203170903647.png
├── image-20250203214020393.png
├── image-20250203214446338.png
├── image-20250203214514020.png
├── image-20250203230445654.png
├── image-20250203230544618.png
├── image-20250203230640616.png
├── image-20250203230657728.png
├── image-20250203230720331.png
├── image-20250203231321030.png
├── image-20250203231338677.png
├── image-20250203231607512.png
├── image-20250203231625954.png
├── image-20250203232232994.png
└── image-20250204203345613.png
├── pom.xml
└── src
├── .DS_Store
└── main
├── .DS_Store
└── java
├── burp
└── api
│ └── montoya
│ └── core
│ └── ToolType.java
└── com
└── chave
├── Main.java
├── config
├── APIConfig.java
├── Color.java
├── SensitiveInfoConfig.java
└── UserConfig.java
├── editor
├── RequestEditor.java
└── ResponseEditor.java
├── handler
└── APIHighLighterHandler.java
├── pojo
├── APIItem.java
├── MatchMod.java
└── RuleItem.java
├── service
├── APIMatchService.java
└── SensitiveInfoMatchService.java
├── ui
├── HighlighterMainUI.java
├── MainUI.java
└── SensitiveInfoMainUI.java
└── utils
└── Util.java
/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Chave0v0/API-Highlighter/8e42cf13e4ccf336a5f9673a54c8222c176cbab2/.DS_Store
--------------------------------------------------------------------------------
/.idea/.gitignore:
--------------------------------------------------------------------------------
1 | # Default ignored files
2 | /shelf/
3 | /workspace.xml
4 | # Datasource local storage ignored files
5 | /dataSources/
6 | /dataSources.local.xml
7 | # Editor-based HTTP Client requests
8 | /httpRequests/
9 |
--------------------------------------------------------------------------------
/.idea/API-Highlighter.iml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/.idea/compiler.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/.idea/jarRepositories.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/.idea/libraries/Maven__net_portswigger_burp_extensions_montoya_api_2024_7.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/.idea/libraries/Maven__org_projectlombok_lombok_1_18_30.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/.idea/libraries/Maven__org_yaml_snakeyaml_2_0.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/.idea/misc.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/.idea/modules.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/.idea/uiDesigner.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | -
6 |
7 |
8 | -
9 |
10 |
11 | -
12 |
13 |
14 | -
15 |
16 |
17 | -
18 |
19 |
20 |
21 |
22 |
23 | -
24 |
25 |
26 |
27 |
28 |
29 | -
30 |
31 |
32 |
33 |
34 |
35 | -
36 |
37 |
38 |
39 |
40 |
41 | -
42 |
43 |
44 |
45 |
46 | -
47 |
48 |
49 |
50 |
51 | -
52 |
53 |
54 |
55 |
56 | -
57 |
58 |
59 |
60 |
61 | -
62 |
63 |
64 |
65 |
66 | -
67 |
68 |
69 |
70 |
71 | -
72 |
73 |
74 | -
75 |
76 |
77 |
78 |
79 | -
80 |
81 |
82 |
83 |
84 | -
85 |
86 |
87 |
88 |
89 | -
90 |
91 |
92 |
93 |
94 | -
95 |
96 |
97 |
98 |
99 | -
100 |
101 |
102 | -
103 |
104 |
105 | -
106 |
107 |
108 | -
109 |
110 |
111 | -
112 |
113 |
114 |
115 |
116 | -
117 |
118 |
119 | -
120 |
121 |
122 |
123 |
124 |
125 |
126 |
127 |
128 |
--------------------------------------------------------------------------------
/.idea/vcs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/API-Highlighter.iml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # API Highlighter
2 | API Highlighter 是一个用于 BurpSuite 的插件,旨在帮助用户在拦截到的流量中高亮显示和处理特定的 API 请求。该插件最初用 Python 编写,现重构为 Java 版本。
3 |
4 | ## 项目背景
5 |
6 | 随着新版 API 的引入,许多原先的历史 API 即将废弃,为了提供更好的支持和兼容性,重构插件逐渐推上日程。
7 |
8 | 在最初的 Python 版本中,由于依赖包较多且配置复杂,导致用户在安装和使用过程中遇到了一定的困难。为了简化插件的安装过程、提高执行性能并减少依赖问题,我们决定开发 Java 版本的 API Highlighter。
9 |
10 | Java 版本不仅更好地与 BurpSuite 环境集成,而且通过减少第三方依赖,降低了安装门槛。希望通过这一改进,为用户提供更为流畅和高效的使用体验。
11 |
12 | 原项目:https://github.com/Flechzao/API-Highlighter
13 |
14 | ## 功能
15 |
16 | ### API 高亮
17 |
18 | #### 导入 API
19 |
20 | 导入格式如下:
21 |
22 | - \
23 | - 仅传入 Path 时,无论是否勾选 ``检查Method``,默认匹配所有 HTTP 方法。
24 | - \ 支持解析 `PathVariable` ,格式为 `{任意字符}`。
25 | - \,\
26 | - `Method` 与 `Path` 之间使用 `,` 分隔。当勾选 ``检查Method`` 时,当前 Path 仅匹配指定 HTTP 方法。
27 | - \ 支持解析 `PathVariable` ,格式为 `{任意字符}`。
28 | - xxxxx
29 | - 传入任意字符进行匹配,通常用于模糊匹配。
30 |
31 | 
32 |
33 | 
34 |
35 | #### 选择匹配模式
36 |
37 | 不同匹配模式仅针对 Path。
38 |
39 | ##### 精确匹配
40 |
41 | 选择精确匹配模式时,不支持 `启用URL编码`、`检查完整数据包`。
42 |
43 | 精确匹配仅匹配 API,不匹配 GET 请求参数,且需要 API 完全匹配。
44 |
45 | 导入如下内容。
46 |
47 | 
48 |
49 | 此时可匹配接口 `/user/register`,`/user/login`,`/user/chave/info`。
50 |
51 | 但无法匹配 `/test/user/login/test`,`/user/loginabc`,`/user/chave/infomation`,`/test/user/chave/info` 以及 `参数中的xxx`。
52 |
53 | 
54 |
55 | ##### 半模糊匹配
56 |
57 | 选择半模糊匹配模式时,不支持 `启用URL编码`、`检查完整数据包`。
58 |
59 | 半模糊匹配仅匹配 API,不匹配 GET 请求参数,但支持匹配不完全相同 API。
60 |
61 | 导入如下内容。
62 |
63 | 
64 |
65 | 此时可匹配接口 `/user/login`,`/user/register`,`/user/chave/info`,`/test/user/login/test`,`/test/user/chave/info/abc`。
66 |
67 | 但无法匹配 `/user/loginabc`,`/user/chave/infomation`,`/xxx`,`/testxxx` 以及 `参数中的xxx`。
68 |
69 | 
70 |
71 | ##### 模糊匹配
72 |
73 | 选择模糊匹配模式时,支持 `启用URL编码`、`检查完整数据包`。
74 |
75 | 模糊匹配在默认情况下,匹配 `Path + 参数`。
76 |
77 | 导入如下内容。
78 |
79 | 
80 |
81 | ###### 解析 PathVariable
82 |
83 | 切换到模糊匹配模式时,会弹出窗口,选择是否解析 PathVariable。选择 `是` 则解析,选择 `否` 则不解析。
84 |
85 | 当解析 PathVariable 时,此时可匹配接口 `/test/user/abc/infomation` 与参数 `/test/user/abc/infoamtion`,`/test/user/{name}/infomation`。
86 |
87 | 
88 |
89 | 当选择不解析 PathVariable 时,此时无法匹配接口 `/test/user/abc/infoamtion` 与参数 `/test/user/abc/infoamtion`,仅可匹配参数 `/test/user/{name}/infomation`。
90 |
91 | 
92 |
93 | ###### 启用 URL 编码
94 |
95 | 当未勾选 `启用URL解码` 时,此时无法匹配参数中经过 URL 编码的 `a b c d e f g`。
96 |
97 | 
98 |
99 | 
100 |
101 | 勾选 `启用URL解码`,此时会对 request 进行 URL 解码,此时可匹配参数中经过 URL 编码的 `a b c d e f g`。
102 |
103 | 
104 |
105 | 
106 |
107 | ###### 检查完整数据包
108 |
109 | 当未勾选 `检查完整数据包` 时,此时仅检查请求 `Path + 参数`,未检查数据包中其他内容。
110 |
111 | 此时无法匹配请求体中的 `a b c d e f g` 与 `xxx`。
112 |
113 | 
114 |
115 | 勾选 `检查完整数据包时` 时,此时将检查整个数据包,此时可匹配 `a b c d e f g`,`xxx`。
116 |
117 | 
118 |
119 | 
120 |
121 | 该功能可与 `启用URL解码` 同时开启,可匹配完整请求中被 URL 编码的数据。
122 |
123 | 
124 |
125 | #### 检查 Method
126 |
127 | 勾选 `检查Method` 后,需要 Method 与 Path 同时匹配才会高亮。
128 |
129 | 若 Method 为空,勾选 `检查Method` 依然匹配所有 HTTP 方法。
130 |
131 | #### 检查 history
132 |
133 | 点击 `检查history` 后,会根据当前配置情况重新检查 history 中所有记录,原高亮记录会被覆盖。
134 |
135 | #### 切换测试状态
136 |
137 | 选择一条或多条 API,点击 `切换测试状态`,可切换选中条目测试状态。
138 |
139 | 当 **State** 为 **true** 时,该条 API 不再进行匹配。
140 |
141 | 
142 |
143 | 
144 |
145 | #### 操作 API 列表
146 |
147 | ##### 修改数据
148 |
149 | - 修改 Method
150 | - 仅支持修改为 GET、POST、PUT、DELETE、OPTIONS。
151 | - 修改 State
152 | - 仅支持修改为 true、false。
153 | - 修改 Path、Result、Note、Domain
154 | - 无限制
155 |
156 | ##### 删除数据
157 |
158 | 选中一条或多条 API,按下退格键即可删除选中条目。
159 |
160 | ##### 列表排序
161 |
162 | 暂不支持...
163 |
164 | #### 查找 API
165 |
166 | ##### 快速查找
167 |
168 | - \:精确查找 Path,并选中。
169 | - \,\:精确查找 Method + Path,并选中。
170 | - *:选中全部条目。
171 |
172 | 
173 |
174 | 
175 |
176 | ##### 条件查找
177 |
178 | 按条件信息查找,如 `method=get`,`path=/service`,`result=xxx`,`state=true` 等。
179 |
180 | 不支持多条件搜索,不支持模糊搜索。
181 |
182 | 
183 |
184 | 
185 |
186 | 
187 |
188 | ### 敏感信息检查
189 |
190 | 目前采用 HaE 部分敏感信息规则进行检查。
191 |
192 | 首次安装插件时,会在当前用户目录下创建配置文件夹。
193 |
194 | 
195 |
196 | #### 开启功能
197 |
198 | 开启敏感信息检查功能必须先导入 API,该功能仅对 API 列表中匹配的记录进行检查。
199 |
200 | 
201 |
202 | 导入 API 后,在 `Sensitive Info` 标签页勾选开启敏感信息检查。该勾选状态默认不勾选,状态不保存。
203 |
204 | 初次启用功能由于配置文件不存在,会询问是否使用默认规则,选择是即可自动创建规则文件。
205 |
206 | 
207 |
208 | 插件自带规则均来自 HaE 插件部分敏感信息规则。
209 |
210 | 
211 |
212 | #### 编辑规则
213 |
214 | 所有修改均同步本地配置文件。
215 |
216 | ##### 添加规则
217 |
218 | 
219 |
220 | 
221 |
222 | ##### 修改规则
223 |
224 | 
225 |
226 | 
227 |
228 | 
229 |
230 | ##### 删除规则
231 |
232 | 支持选中多条规则同时删除。
233 |
234 | 
235 |
236 | 
237 |
238 | ##### 切换规则启用状态
239 |
240 | 支持选中多条规则同时切换状态,`true=启用`,`false=未启用`。
241 |
242 | 
243 |
244 | 
245 |
246 | #### 功能效果
247 |
248 | 开启敏感信息检查后,当 API 列表中匹配到敏感信息时,`history` 中标记为 `橙色`,同时列出匹配到的字段信息。
249 |
250 | 
251 |
252 | 同时 API 列表中 `Result` 字段提示 `存在敏感信息`。
253 |
254 | 
255 |
256 | ## 更新计划
257 |
258 | - HaE 规则敏感信息检查(v2.0.0 已完成)
259 | - API 未授权访问检查(v3.0.0 开发中)
260 |
--------------------------------------------------------------------------------
/assets/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Chave0v0/API-Highlighter/8e42cf13e4ccf336a5f9673a54c8222c176cbab2/assets/.DS_Store
--------------------------------------------------------------------------------
/assets/image-20250131143303914.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Chave0v0/API-Highlighter/8e42cf13e4ccf336a5f9673a54c8222c176cbab2/assets/image-20250131143303914.png
--------------------------------------------------------------------------------
/assets/image-20250131143734141.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Chave0v0/API-Highlighter/8e42cf13e4ccf336a5f9673a54c8222c176cbab2/assets/image-20250131143734141.png
--------------------------------------------------------------------------------
/assets/image-20250131150531983.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Chave0v0/API-Highlighter/8e42cf13e4ccf336a5f9673a54c8222c176cbab2/assets/image-20250131150531983.png
--------------------------------------------------------------------------------
/assets/image-20250131151601732.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Chave0v0/API-Highlighter/8e42cf13e4ccf336a5f9673a54c8222c176cbab2/assets/image-20250131151601732.png
--------------------------------------------------------------------------------
/assets/image-20250131151831909.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Chave0v0/API-Highlighter/8e42cf13e4ccf336a5f9673a54c8222c176cbab2/assets/image-20250131151831909.png
--------------------------------------------------------------------------------
/assets/image-20250131152150163.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Chave0v0/API-Highlighter/8e42cf13e4ccf336a5f9673a54c8222c176cbab2/assets/image-20250131152150163.png
--------------------------------------------------------------------------------
/assets/image-20250131152224779.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Chave0v0/API-Highlighter/8e42cf13e4ccf336a5f9673a54c8222c176cbab2/assets/image-20250131152224779.png
--------------------------------------------------------------------------------
/assets/image-20250131152949132.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Chave0v0/API-Highlighter/8e42cf13e4ccf336a5f9673a54c8222c176cbab2/assets/image-20250131152949132.png
--------------------------------------------------------------------------------
/assets/image-20250131153024127.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Chave0v0/API-Highlighter/8e42cf13e4ccf336a5f9673a54c8222c176cbab2/assets/image-20250131153024127.png
--------------------------------------------------------------------------------
/assets/image-20250131153251402.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Chave0v0/API-Highlighter/8e42cf13e4ccf336a5f9673a54c8222c176cbab2/assets/image-20250131153251402.png
--------------------------------------------------------------------------------
/assets/image-20250131153522783.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Chave0v0/API-Highlighter/8e42cf13e4ccf336a5f9673a54c8222c176cbab2/assets/image-20250131153522783.png
--------------------------------------------------------------------------------
/assets/image-20250131153624442.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Chave0v0/API-Highlighter/8e42cf13e4ccf336a5f9673a54c8222c176cbab2/assets/image-20250131153624442.png
--------------------------------------------------------------------------------
/assets/image-20250131153719159.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Chave0v0/API-Highlighter/8e42cf13e4ccf336a5f9673a54c8222c176cbab2/assets/image-20250131153719159.png
--------------------------------------------------------------------------------
/assets/image-20250131153838072.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Chave0v0/API-Highlighter/8e42cf13e4ccf336a5f9673a54c8222c176cbab2/assets/image-20250131153838072.png
--------------------------------------------------------------------------------
/assets/image-20250131153912482.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Chave0v0/API-Highlighter/8e42cf13e4ccf336a5f9673a54c8222c176cbab2/assets/image-20250131153912482.png
--------------------------------------------------------------------------------
/assets/image-20250131155246057.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Chave0v0/API-Highlighter/8e42cf13e4ccf336a5f9673a54c8222c176cbab2/assets/image-20250131155246057.png
--------------------------------------------------------------------------------
/assets/image-20250131155558419.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Chave0v0/API-Highlighter/8e42cf13e4ccf336a5f9673a54c8222c176cbab2/assets/image-20250131155558419.png
--------------------------------------------------------------------------------
/assets/image-20250131155745214.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Chave0v0/API-Highlighter/8e42cf13e4ccf336a5f9673a54c8222c176cbab2/assets/image-20250131155745214.png
--------------------------------------------------------------------------------
/assets/image-20250131160031773.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Chave0v0/API-Highlighter/8e42cf13e4ccf336a5f9673a54c8222c176cbab2/assets/image-20250131160031773.png
--------------------------------------------------------------------------------
/assets/image-20250131201354108.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Chave0v0/API-Highlighter/8e42cf13e4ccf336a5f9673a54c8222c176cbab2/assets/image-20250131201354108.png
--------------------------------------------------------------------------------
/assets/image-20250131201535978.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Chave0v0/API-Highlighter/8e42cf13e4ccf336a5f9673a54c8222c176cbab2/assets/image-20250131201535978.png
--------------------------------------------------------------------------------
/assets/image-20250131203231727.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Chave0v0/API-Highlighter/8e42cf13e4ccf336a5f9673a54c8222c176cbab2/assets/image-20250131203231727.png
--------------------------------------------------------------------------------
/assets/image-20250131203259330.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Chave0v0/API-Highlighter/8e42cf13e4ccf336a5f9673a54c8222c176cbab2/assets/image-20250131203259330.png
--------------------------------------------------------------------------------
/assets/image-20250131204156562.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Chave0v0/API-Highlighter/8e42cf13e4ccf336a5f9673a54c8222c176cbab2/assets/image-20250131204156562.png
--------------------------------------------------------------------------------
/assets/image-20250131204216952.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Chave0v0/API-Highlighter/8e42cf13e4ccf336a5f9673a54c8222c176cbab2/assets/image-20250131204216952.png
--------------------------------------------------------------------------------
/assets/image-20250131204256345.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Chave0v0/API-Highlighter/8e42cf13e4ccf336a5f9673a54c8222c176cbab2/assets/image-20250131204256345.png
--------------------------------------------------------------------------------
/assets/image-20250203170903647.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Chave0v0/API-Highlighter/8e42cf13e4ccf336a5f9673a54c8222c176cbab2/assets/image-20250203170903647.png
--------------------------------------------------------------------------------
/assets/image-20250203214020393.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Chave0v0/API-Highlighter/8e42cf13e4ccf336a5f9673a54c8222c176cbab2/assets/image-20250203214020393.png
--------------------------------------------------------------------------------
/assets/image-20250203214446338.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Chave0v0/API-Highlighter/8e42cf13e4ccf336a5f9673a54c8222c176cbab2/assets/image-20250203214446338.png
--------------------------------------------------------------------------------
/assets/image-20250203214514020.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Chave0v0/API-Highlighter/8e42cf13e4ccf336a5f9673a54c8222c176cbab2/assets/image-20250203214514020.png
--------------------------------------------------------------------------------
/assets/image-20250203230445654.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Chave0v0/API-Highlighter/8e42cf13e4ccf336a5f9673a54c8222c176cbab2/assets/image-20250203230445654.png
--------------------------------------------------------------------------------
/assets/image-20250203230544618.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Chave0v0/API-Highlighter/8e42cf13e4ccf336a5f9673a54c8222c176cbab2/assets/image-20250203230544618.png
--------------------------------------------------------------------------------
/assets/image-20250203230640616.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Chave0v0/API-Highlighter/8e42cf13e4ccf336a5f9673a54c8222c176cbab2/assets/image-20250203230640616.png
--------------------------------------------------------------------------------
/assets/image-20250203230657728.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Chave0v0/API-Highlighter/8e42cf13e4ccf336a5f9673a54c8222c176cbab2/assets/image-20250203230657728.png
--------------------------------------------------------------------------------
/assets/image-20250203230720331.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Chave0v0/API-Highlighter/8e42cf13e4ccf336a5f9673a54c8222c176cbab2/assets/image-20250203230720331.png
--------------------------------------------------------------------------------
/assets/image-20250203231321030.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Chave0v0/API-Highlighter/8e42cf13e4ccf336a5f9673a54c8222c176cbab2/assets/image-20250203231321030.png
--------------------------------------------------------------------------------
/assets/image-20250203231338677.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Chave0v0/API-Highlighter/8e42cf13e4ccf336a5f9673a54c8222c176cbab2/assets/image-20250203231338677.png
--------------------------------------------------------------------------------
/assets/image-20250203231607512.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Chave0v0/API-Highlighter/8e42cf13e4ccf336a5f9673a54c8222c176cbab2/assets/image-20250203231607512.png
--------------------------------------------------------------------------------
/assets/image-20250203231625954.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Chave0v0/API-Highlighter/8e42cf13e4ccf336a5f9673a54c8222c176cbab2/assets/image-20250203231625954.png
--------------------------------------------------------------------------------
/assets/image-20250203232232994.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Chave0v0/API-Highlighter/8e42cf13e4ccf336a5f9673a54c8222c176cbab2/assets/image-20250203232232994.png
--------------------------------------------------------------------------------
/assets/image-20250204203345613.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Chave0v0/API-Highlighter/8e42cf13e4ccf336a5f9673a54c8222c176cbab2/assets/image-20250204203345613.png
--------------------------------------------------------------------------------
/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 | 4.0.0
6 |
7 | org.example
8 | API-Highlighter
9 | 1.0-SNAPSHOT
10 |
11 |
12 | 17
13 | 17
14 |
15 |
16 |
17 |
18 |
19 | org.apache.maven.plugins
20 | maven-assembly-plugin
21 | 3.3.0
22 |
23 |
24 | jar-with-dependencies
25 |
26 |
27 |
28 | com.chave.Main
29 |
30 |
31 |
32 |
33 |
34 | make-assembly
35 | package
36 |
37 | single
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 | net.portswigger.burp.extensions
49 | montoya-api
50 | 2024.7
51 |
52 |
53 |
54 | org.projectlombok
55 | lombok
56 | 1.18.30
57 |
58 |
59 |
60 | org.yaml
61 | snakeyaml
62 | 2.0
63 |
64 |
65 |
--------------------------------------------------------------------------------
/src/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Chave0v0/API-Highlighter/8e42cf13e4ccf336a5f9673a54c8222c176cbab2/src/.DS_Store
--------------------------------------------------------------------------------
/src/main/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Chave0v0/API-Highlighter/8e42cf13e4ccf336a5f9673a54c8222c176cbab2/src/main/.DS_Store
--------------------------------------------------------------------------------
/src/main/java/burp/api/montoya/core/ToolType.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2022-2023. PortSwigger Ltd. All rights reserved.
3 | *
4 | * This code may be used to extend the functionality of Burp Suite Community Edition
5 | * and Burp Suite Professional, provided that this usage does not violate the
6 | * license terms for those products.
7 | */
8 |
9 | package burp.api.montoya.core;
10 |
11 | /**
12 | * Tools in Burp Suite.
13 | */
14 | public enum ToolType
15 | {
16 | SUITE("Suite"),
17 | TARGET("Target"),
18 | PROXY("Proxy"),
19 | SCANNER("Scanner"),
20 | INTRUDER("Intruder"),
21 | REPEATER("Repeater"),
22 | LOGGER("Logger"),
23 | SEQUENCER("Sequencer"),
24 | DECODER("Decoder"),
25 | COMPARER("Comparer"),
26 | EXTENSIONS("Extensions"),
27 | RECORDED_LOGIN_REPLAYER("Recorded login replayer"),
28 | ORGANIZER("Organizer");
29 |
30 | private final String toolName;
31 |
32 | ToolType(String toolName)
33 | {
34 | this.toolName = toolName;
35 | }
36 |
37 | /**
38 | * @return The tool name.
39 | */
40 | public String toolName()
41 | {
42 | return toolName;
43 | }
44 |
45 | /**
46 | * @return The tool name.
47 | */
48 | @Override
49 | public String toString()
50 | {
51 | return toolName;
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/src/main/java/com/chave/Main.java:
--------------------------------------------------------------------------------
1 | package com.chave;
2 |
3 | import burp.api.montoya.BurpExtension;
4 | import burp.api.montoya.MontoyaApi;
5 | import burp.api.montoya.logging.Logging;
6 | import com.chave.config.SensitiveInfoConfig;
7 | import com.chave.editor.RequestEditor;
8 | import com.chave.editor.ResponseEditor;
9 | import com.chave.handler.APIHighLighterHandler;
10 | import com.chave.ui.MainUI;
11 | import java.io.*;
12 |
13 | public class Main implements BurpExtension {
14 |
15 | public static MontoyaApi API;
16 | public static MainUI UI;
17 |
18 | @Override
19 | public void initialize(MontoyaApi montoyaApi) {
20 | API = montoyaApi;
21 | Logging log = API.logging();
22 |
23 | API.extension().setName("API Highlighter");
24 | log.logToOutput("API Highlighter v2.1.2\n\n" +
25 | "Rebuild: Chave\n" +
26 | "GitHub: https://github.com/Chave0v0/API-Highlighter\n");
27 |
28 | // 初始化ui
29 | UI = new MainUI();
30 | API.userInterface().registerSuiteTab("API Highlighter", UI.getMainTabbedPane());
31 | API.http().registerHttpHandler(new APIHighLighterHandler());
32 | // 添加敏感信息展示Tab
33 | API.userInterface().registerHttpRequestEditorProvider(new RequestEditor());
34 | API.userInterface().registerHttpResponseEditorProvider(new ResponseEditor());
35 |
36 | // 检查存放配置文件的目录是否存在,若不存在则创建目录
37 | File rule_dir = new File(SensitiveInfoConfig.RULE_CONFIG_DIR);
38 | if (!rule_dir.exists()) {
39 | log.logToOutput("配置文件目录不存在, 即将自动创建...");
40 | boolean created = rule_dir.mkdirs(); // 创建目录及其父目录
41 | if (created) {
42 | log.logToOutput("[+] 配置文件目录创建成功: " + rule_dir.getAbsolutePath());
43 | } else {
44 | log.logToOutput("[-] 配置文件目录创建失败.");
45 | }
46 | } else {
47 | log.logToOutput("[+] 配置文件目录已存在, 无需创建.");
48 | }
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/src/main/java/com/chave/config/APIConfig.java:
--------------------------------------------------------------------------------
1 | package com.chave.config;
2 |
3 | import com.chave.pojo.APIItem;
4 | import java.util.ArrayList;
5 | import java.util.HashMap;
6 |
7 | public class APIConfig {
8 | public static ArrayList TARGET_API = new ArrayList<>();
9 |
10 | public static final HashMap ITEM_FIELD = new HashMap();
11 |
12 | public static final String SENSITIVE_INFO_RESULT = "存在敏感信息";
13 |
14 | static {
15 | ITEM_FIELD.put(0, "method");
16 | ITEM_FIELD.put(1, "path");
17 | ITEM_FIELD.put(2, "result");
18 | ITEM_FIELD.put(3, "state");
19 | ITEM_FIELD.put(4, "note");
20 | ITEM_FIELD.put(5, "isFound");
21 | }
22 |
23 | }
24 |
--------------------------------------------------------------------------------
/src/main/java/com/chave/config/Color.java:
--------------------------------------------------------------------------------
1 | package com.chave.config;
2 |
3 | public class Color {
4 | public static String NONE = "None";
5 | public static String RED = "Red";
6 | public static String ORANGE = "Orange";
7 | public static String YELLOW = "Yellow";
8 | public static String GREEN = "Green";
9 | public static String CYAN ="Cyan";
10 | public static String BLUE = "Blue";
11 | public static String PINK = "Pink";
12 | public static String MAGENTA = "Magenta";
13 | public static String GRAY = "Gray";
14 | }
15 |
--------------------------------------------------------------------------------
/src/main/java/com/chave/config/SensitiveInfoConfig.java:
--------------------------------------------------------------------------------
1 | package com.chave.config;
2 |
3 | import com.chave.pojo.RuleItem;
4 |
5 | import java.util.ArrayList;
6 |
7 | public class SensitiveInfoConfig {
8 | public static Boolean IS_CHECK_SENSITIVE_INFO = Boolean.FALSE;
9 | public static String RULE_CONFIG_DIR = System.getProperty("os.name").toLowerCase().contains("win") ? System.getProperty("user.home") + "\\.config\\API-Highlighter\\" : System.getProperty("user.home") + "/.config/API-Highlighter/";
10 | public static String RULE_CONFIG_FILE = System.getProperty("os.name").toLowerCase().contains("win") ? System.getProperty("user.home") + "\\.config\\API-Highlighter\\Rules.yml" : System.getProperty("user.home") + "/.config/API-Highlighter/Rules.yml";
11 | public static String DEFAULT_RULE_LIST_DATA = "rO0ABXNyABNqYXZhLnV0aWwuQXJyYXlMaXN0eIHSHZnHYZ0DAAFJAARzaXpleHAAAAAKdwQAAAAKc3IAF2NvbS5jaGF2ZS5wb2pvLlJ1bGVJdGVtdqK4luS3hqYCAARMAAZsb2FkZWR0ABNMamF2YS9sYW5nL0Jvb2xlYW47TAAEbmFtZXQAEkxqYXZhL2xhbmcvU3RyaW5nO0wABXJlZ2V4cQB+AARMAAVzY29wZXEAfgAEeHBzcgARamF2YS5sYW5nLkJvb2xlYW7NIHKA1Zz67gIAAVoABXZhbHVleHABdAAFRW1haWx0AGEoKFthLXowLTldW198XC5dKSpbYS16MC05XStAKFthLXowLTldWy18X3xcLl0pKlthLXowLTldK1wuKCg/IWpzfGNzc3xqcGd8anBlZ3xwbmd8aWNvKVthLXpdezIsfSkpdAAIcmVzcG9uc2VzcQB+AAJxAH4AB3QADkNoaW5lc2UgSURDYXJkdAB8W14wLTldKChcZHs4fSgwXGR8MTB8MTF8MTIpKFswLTJdXGR8MzB8MzEpXGR7M30kKXwoXGR7Nn0oMTh8MTl8MjApXGR7Mn0oMFsxLTldfDEwfDExfDEyKShbMC0yXVxkfDMwfDMxKVxkezN9KFxkfFh8eCkpKVteMC05XXQACHJlc3BvbnNlc3EAfgACcQB+AAd0ABVDaGluZXNlIE1vYmlsZSBOdW1iZXJ0AHRbXlx3XSgoPzooPzpcK3wwMCk4Nik/MSg/Oig/OjNbXGRdKXwoPzo0WzUtNzldKXwoPzo1WzAtMzUtOV0pfCg/OjZbNS03XSl8KD86N1swLThdKXwoPzo4W1xkXSl8KD86OVsxODldKSlcZHs4fSlbXlx3XXQACHJlc3BvbnNlc3EAfgACcQB+AAd0ABNJbnRlcm5hbCBJUCBBZGRyZXNzdACFW14wLTldKCgxMjdcLjBcLjBcLjEpfCgxMFwuXGR7MSwzfVwuXGR7MSwzfVwuXGR7MSwzfSl8KDE3MlwuKCgxWzYtOV0pfCgyXGQpfCgzWzAxXSkpXC5cZHsxLDN9XC5cZHsxLDN9KXwoMTkyXC4xNjhcLlxkezEsM31cLlxkezEsM30pKXQACHJlc3BvbnNlc3EAfgACcQB+AAd0ABRDaGluZXNlIEJhbmsgQ2FyZCBJRHQAHFteMC05XShbMS05XVxkezEyLDE4fSlbXjAtOV10AAhyZXNwb25zZXNxAH4AAnEAfgAHdAAJQ2xvdWQgS2V5dAA3KChhY2Nlc3NrZXlpZCl8KGFjY2Vzc2tleXNlY3JldCl8KExUQUlbYS16MC05XXsxMiwyMH0pKXQAA2FueXNxAH4AAnEAfgAHdAAOUGFzc3dvcmQgRmllbGR0AEUoKHwnfCIpKFtwXShhc3N8d2R8YXNzd2R8YXNzd29yZCkpKHwnfCIpKDp8PSkoIHwpKCd8IikoLio/KSgnfCIpKHwsKSl0AAhyZXNwb25zZXNxAH4AAnEAfgAHdAAOVXNlcm5hbWUgRmllbGR0AFEoKHwnfCIpKChbdV0oc2VyfG5hbWV8YW1lfHNlcm5hbWUpKXwoYWNjb3VudCkpKHwnfCIpKDp8PSkoIHwpKCd8IikoLio/KSgnfCIpKHwsKSl0AAhyZXNwb25zZXNxAH4AAnEAfgAHdAAPSkRCQyBDb25uZWN0aW9udAAnKGpkYmM6W2EtejpdKzovL1thLXowLTlcLlwtXzo7PS9APywmXSspdAADYW55c3EAfgACcQB+AAd0AA9TZW5zaXRpdmUgRmllbGR0AG4oKHwnfCIpKFtcd117MCwxMH0pKChrZXkpfChzZWNyZXQpfCh0b2tlbil8KGNvbmZpZyl8KGF1dGgpfChhY2Nlc3MpfChhZG1pbikpKHwnfCIpKDp8PSkofCkoJ3wiKSguKj8pKCd8IikofCwpKXQACHJlc3BvbnNleA==";
12 |
13 | public static ArrayList RULE_LIST;
14 | }
15 |
--------------------------------------------------------------------------------
/src/main/java/com/chave/config/UserConfig.java:
--------------------------------------------------------------------------------
1 | package com.chave.config;
2 |
3 | import com.chave.pojo.MatchMod;
4 |
5 | public class UserConfig {
6 | public static MatchMod MATCH_MOD = MatchMod.exactMatch;
7 | public static Boolean IS_URL_DECODE = Boolean.FALSE;
8 | public static Boolean IS_CHECK_ENTIRE_REQUEST = Boolean.FALSE;
9 | public static Boolean IS_CHECK_HTTP_METHOD = Boolean.FALSE;
10 | public static Boolean IS_ANALYZE_PATHVARIABLE = Boolean.FALSE;
11 |
12 | }
13 |
--------------------------------------------------------------------------------
/src/main/java/com/chave/editor/RequestEditor.java:
--------------------------------------------------------------------------------
1 | package com.chave.editor;
2 |
3 | import burp.api.montoya.http.message.HttpRequestResponse;
4 | import burp.api.montoya.http.message.requests.HttpRequest;
5 | import burp.api.montoya.ui.Selection;
6 | import burp.api.montoya.ui.editor.extension.EditorCreationContext;
7 | import burp.api.montoya.ui.editor.extension.ExtensionProvidedHttpRequestEditor;
8 | import burp.api.montoya.ui.editor.extension.HttpRequestEditorProvider;
9 | import com.chave.Main;
10 | import com.chave.config.SensitiveInfoConfig;
11 | import com.chave.service.SensitiveInfoMatchService;
12 | import com.chave.utils.Util;
13 | import javax.swing.*;
14 | import javax.swing.table.DefaultTableCellRenderer;
15 | import javax.swing.table.DefaultTableModel;
16 | import javax.swing.table.JTableHeader;
17 | import javax.swing.table.TableCellRenderer;
18 | import java.awt.*;
19 | import java.lang.reflect.InvocationTargetException;
20 | import java.util.ArrayList;
21 | import java.util.HashMap;
22 | import java.util.Set;
23 |
24 | public class RequestEditor implements HttpRequestEditorProvider {
25 | @Override
26 | public ExtensionProvidedHttpRequestEditor provideHttpRequestEditor(EditorCreationContext creationContext) {
27 | return new Editor();
28 | }
29 |
30 | private static class Editor implements ExtensionProvidedHttpRequestEditor {
31 | private HttpRequestResponse requestResponse;
32 | private final JTabbedPane jTabbedPane = new JTabbedPane();
33 | private SensitiveInfoMatchService sensitiveInfoMatchService = new SensitiveInfoMatchService();
34 |
35 | public Editor() {
36 | }
37 |
38 | @Override
39 | public HttpRequest getRequest() {
40 | return requestResponse.request();
41 | }
42 |
43 | @Override
44 | public void setRequestResponse(HttpRequestResponse requestResponse) {
45 | this.requestResponse = requestResponse;
46 | }
47 |
48 | @Override
49 | public boolean isEnabledFor(HttpRequestResponse requestResponse) {
50 | HttpRequest request = requestResponse.request();
51 |
52 | // 防止空指针
53 | if (request == null) {
54 | return false;
55 | }
56 |
57 | try {
58 | HashMap apiMatchResult = Util.getAPIMatchResult(request);
59 | boolean isMatched = (boolean) apiMatchResult.get("isMatched");
60 | if (isMatched && SensitiveInfoConfig.IS_CHECK_SENSITIVE_INFO) {
61 | HashMap result = sensitiveInfoMatchService.sensitiveInfoMatch(request);
62 | if (!result.isEmpty()) {
63 | genreateEditorUI(result);
64 | return true;
65 | }
66 | } else {
67 | return false;
68 | }
69 | } catch (InvocationTargetException invocationTargetException) {
70 | // 预期内异常
71 | } catch (Exception e) {
72 | Main.API.logging().logToError(e);
73 | }
74 | return false;
75 | }
76 |
77 | @Override
78 | public String caption() {
79 | return "MarkInfo";
80 | }
81 |
82 | @Override
83 | public Component uiComponent() {
84 | return jTabbedPane;
85 | }
86 |
87 | @Override
88 | public Selection selectedData() {
89 | return null;
90 | }
91 |
92 | @Override
93 | public boolean isModified() {
94 | return false;
95 | }
96 |
97 | private void genreateEditorUI(HashMap result) {
98 | Set keys = result.keySet();
99 |
100 | // 每次均清空原有标签进行刷新
101 | jTabbedPane.removeAll();
102 |
103 | for (String key : keys) {
104 | // 计数器
105 | int index = 0;
106 | // 构建表格数据
107 | ArrayList dataList = (ArrayList) result.get(key);
108 | Object[][] data = new Object[dataList.size()][2];
109 | for (String dataItem : dataList) {
110 | data[index][0] = index + 1;
111 | data[index][1] = dataItem;
112 | index++;
113 | }
114 | // 创建表格
115 | String[] columnName = {"#", "Information"};
116 | DefaultTableModel model = new DefaultTableModel(data, columnName);
117 | JTable table = new JTable(model);
118 | // 设置列宽
119 | table.getColumnModel().getColumn(0).setMaxWidth(75);
120 | // 设置第一行居中
121 | TableCellRenderer centerRenderer = new DefaultTableCellRenderer();
122 | ((DefaultTableCellRenderer) centerRenderer).setHorizontalAlignment(SwingConstants.CENTER);
123 | table.getColumnModel().getColumn(0).setCellRenderer(centerRenderer);
124 | // 设置表头背景
125 | JTableHeader tableHeader = table.getTableHeader();
126 | tableHeader.setBackground(new Color(215, 215, 215));
127 | // 创建表格滚动面板
128 | JScrollPane tableScrollPane = new JScrollPane(table);
129 |
130 | // 创建标签页
131 | jTabbedPane.addTab(key, tableScrollPane);
132 | }
133 | }
134 | }
135 | }
136 |
--------------------------------------------------------------------------------
/src/main/java/com/chave/editor/ResponseEditor.java:
--------------------------------------------------------------------------------
1 | package com.chave.editor;
2 |
3 | import burp.api.montoya.http.message.HttpRequestResponse;
4 | import burp.api.montoya.http.message.requests.HttpRequest;
5 | import burp.api.montoya.http.message.responses.HttpResponse;
6 | import burp.api.montoya.ui.Selection;
7 | import burp.api.montoya.ui.editor.extension.*;
8 | import com.chave.Main;
9 | import com.chave.config.SensitiveInfoConfig;
10 | import com.chave.service.SensitiveInfoMatchService;
11 | import com.chave.utils.Util;
12 | import javax.swing.*;
13 | import javax.swing.table.DefaultTableCellRenderer;
14 | import javax.swing.table.DefaultTableModel;
15 | import javax.swing.table.JTableHeader;
16 | import javax.swing.table.TableCellRenderer;
17 | import java.awt.*;
18 | import java.lang.reflect.InvocationTargetException;
19 | import java.util.ArrayList;
20 | import java.util.HashMap;
21 | import java.util.Set;
22 |
23 | public class ResponseEditor implements HttpResponseEditorProvider {
24 |
25 | @Override
26 | public ExtensionProvidedHttpResponseEditor provideHttpResponseEditor(EditorCreationContext creationContext) {
27 | return new Editor();
28 | }
29 |
30 | private static class Editor implements ExtensionProvidedHttpResponseEditor {
31 | private HttpRequestResponse requestResponse;
32 | private final JTabbedPane jTabbedPane = new JTabbedPane();
33 | private SensitiveInfoMatchService sensitiveInfoMatchService = new SensitiveInfoMatchService();
34 |
35 | public Editor() {
36 | }
37 |
38 | @Override
39 | public HttpResponse getResponse() {
40 | return requestResponse.response();
41 | }
42 |
43 | @Override
44 | public void setRequestResponse(HttpRequestResponse requestResponse) {
45 | this.requestResponse = requestResponse;
46 | }
47 |
48 | @Override
49 | public boolean isEnabledFor(HttpRequestResponse requestResponse) {
50 | HttpResponse response = requestResponse.response();
51 | HttpRequest request = requestResponse.request();
52 |
53 | // 防止空指针
54 | if (response == null || request == null) {
55 | return false;
56 | }
57 |
58 | try {
59 | HashMap apiMatchResult = Util.getAPIMatchResult(request);
60 | boolean isMatched = (boolean) apiMatchResult.get("isMatched");
61 | if (isMatched && SensitiveInfoConfig.IS_CHECK_SENSITIVE_INFO) {
62 | HashMap result = sensitiveInfoMatchService.sensitiveInfoMatch(response);
63 | if (!result.isEmpty()) {
64 | genreateEditorUI(result);
65 | return true;
66 | }
67 | } else {
68 | return false;
69 | }
70 | } catch (InvocationTargetException invocationTargetException) {
71 | // 预期内异常
72 | } catch (Exception e) {
73 | Main.API.logging().logToError(e);
74 | }
75 | return false;
76 | }
77 |
78 | @Override
79 | public String caption() {
80 | return "MarkInfo";
81 | }
82 |
83 | @Override
84 | public Component uiComponent() {
85 | return jTabbedPane;
86 | }
87 |
88 | @Override
89 | public Selection selectedData() {
90 | return null;
91 | }
92 |
93 | @Override
94 | public boolean isModified() {
95 | return false;
96 | }
97 |
98 | private void genreateEditorUI(HashMap result) {
99 | Set keys = result.keySet();
100 |
101 | // 每次均清空原有标签进行刷新
102 | jTabbedPane.removeAll();
103 |
104 | for (String key : keys) {
105 | // 计数器
106 | int index = 0;
107 | // 构建表格数据
108 | ArrayList dataList = (ArrayList) result.get(key);
109 | Object[][] data = new Object[dataList.size()][2];
110 | for (String dataItem : dataList) {
111 | data[index][0] = index + 1;
112 | data[index][1] = dataItem;
113 | index++;
114 | }
115 | // 创建表格
116 | String[] columnName = {"#", "Information"};
117 | DefaultTableModel model = new DefaultTableModel(data, columnName);
118 | JTable table = new JTable(model);
119 | // 设置列宽
120 | table.getColumnModel().getColumn(0).setMaxWidth(75);
121 | // 设置第一行居中
122 | TableCellRenderer centerRenderer = new DefaultTableCellRenderer();
123 | ((DefaultTableCellRenderer) centerRenderer).setHorizontalAlignment(SwingConstants.CENTER);
124 | table.getColumnModel().getColumn(0).setCellRenderer(centerRenderer);
125 | // 设置表头背景
126 | JTableHeader tableHeader = table.getTableHeader();
127 | tableHeader.setBackground(new Color(215, 215, 215));
128 | // 创建表格滚动面板
129 | JScrollPane tableScrollPane = new JScrollPane(table);
130 |
131 | // 创建标签页
132 | jTabbedPane.addTab(key, tableScrollPane);
133 | }
134 | }
135 | }
136 | }
137 |
--------------------------------------------------------------------------------
/src/main/java/com/chave/handler/APIHighLighterHandler.java:
--------------------------------------------------------------------------------
1 | package com.chave.handler;
2 |
3 | import burp.api.montoya.core.ToolType;
4 | import burp.api.montoya.http.handler.*;
5 | import burp.api.montoya.http.message.requests.HttpRequest;
6 | import burp.api.montoya.logging.Logging;
7 | import com.chave.Main;
8 | import com.chave.config.APIConfig;
9 | import com.chave.config.Color;
10 | import com.chave.config.SensitiveInfoConfig;
11 | import com.chave.pojo.APIItem;
12 | import com.chave.service.SensitiveInfoMatchService;
13 | import com.chave.utils.Util;
14 | import java.util.HashMap;
15 |
16 | public class APIHighLighterHandler implements HttpHandler {
17 | private Logging log;
18 | private SensitiveInfoMatchService sensitiveInfoMatchService;
19 | private HashMap messageIdList;
20 |
21 | public APIHighLighterHandler() {
22 | this.log = Main.API.logging();
23 | this.sensitiveInfoMatchService = new SensitiveInfoMatchService();
24 | this.messageIdList = new HashMap<>();
25 | }
26 |
27 | @Override
28 | public RequestToBeSentAction handleHttpRequestToBeSent(HttpRequestToBeSent requestToBeSent) {
29 | try {
30 | // 只监听来自proxy与repeter的流量 减小检测量
31 | if (requestToBeSent.toolSource().isFromTool(ToolType.PROXY) || requestToBeSent.toolSource().isFromTool(ToolType.REPEATER)) {
32 | HashMap apiMatchResult = Util.getAPIMatchResult(requestToBeSent);
33 | boolean isMatched = (boolean) apiMatchResult.get("isMatched");
34 | APIItem matchedItem = (APIItem) apiMatchResult.get("api");
35 |
36 | if (isMatched) {
37 | // 添加到arraylist中 为了检查对应response
38 | if (messageIdList.get(requestToBeSent.messageId()) == null) {
39 | messageIdList.put(requestToBeSent.messageId(), requestToBeSent);
40 | }
41 |
42 | // 对匹配到的接口进行标记
43 | Util.setAPIFound(matchedItem.getPath(), requestToBeSent);
44 |
45 | // 匹配到进行高亮处理
46 | Util.setHighlightColor(requestToBeSent, Color.YELLOW);
47 |
48 | if (SensitiveInfoConfig.IS_CHECK_SENSITIVE_INFO) {
49 | // 只对匹配到的接口进行敏感信息检查
50 | HashMap sensitiveInfoMatchResult = sensitiveInfoMatchService.sensitiveInfoMatch(requestToBeSent);
51 | if (!sensitiveInfoMatchResult.isEmpty()) {
52 | // 对history进行红色高亮处理
53 | Util.setHighlightColor(requestToBeSent, Color.ORANGE);
54 | // 标记result 存在敏感信息
55 | Util.setAPIResult(APIConfig.SENSITIVE_INFO_RESULT, matchedItem.getPath(), requestToBeSent);
56 | }
57 | }
58 |
59 | // 刷新列表
60 | Util.flushAPIList(Main.UI.getHighlighterMainUI().getApiTable());
61 | }
62 | }
63 | } catch (Exception e) {
64 | log.logToError("request handler异常");
65 | }
66 |
67 | return null;
68 | }
69 |
70 | @Override
71 | public ResponseReceivedAction handleHttpResponseReceived(HttpResponseReceived responseReceived) {
72 | try {
73 | if (SensitiveInfoConfig.IS_CHECK_SENSITIVE_INFO) {
74 | // 查询当前response对应的request是否被匹配
75 | HttpRequest request = messageIdList.get(responseReceived.messageId());
76 | if (request != null) {
77 | HashMap sensitiveInfoMatch = sensitiveInfoMatchService.sensitiveInfoMatch(responseReceived);
78 |
79 | if (!sensitiveInfoMatch.isEmpty()) {
80 | // 对history进行红色高亮处理
81 | Util.setHighlightColor(responseReceived, Color.ORANGE);
82 |
83 | // 重新匹配一次 找到对应的apiItem
84 | HashMap apiMatchResult = Util.getAPIMatchResult(request);
85 | APIItem matchedItem = (APIItem) apiMatchResult.get("api");
86 |
87 | // 标记result 存在敏感信息
88 | Util.setAPIResult(APIConfig.SENSITIVE_INFO_RESULT, matchedItem.getPath(), request);
89 |
90 | // 刷新列表
91 | Util.flushAPIList(Main.UI.getHighlighterMainUI().getApiTable());
92 |
93 | }
94 | }
95 | }
96 | } catch (Exception e) {
97 | log.logToError("response handler异常");
98 | }
99 |
100 | return null;
101 | }
102 | }
103 |
--------------------------------------------------------------------------------
/src/main/java/com/chave/pojo/APIItem.java:
--------------------------------------------------------------------------------
1 | package com.chave.pojo;
2 |
3 | import lombok.AllArgsConstructor;
4 | import lombok.Data;
5 | import lombok.NoArgsConstructor;
6 |
7 | @Data
8 | @NoArgsConstructor
9 | @AllArgsConstructor
10 | public class APIItem {
11 | private String method = null;
12 | private String path;
13 | private String result;
14 | private Boolean state = Boolean.FALSE;
15 | private String note;
16 | private String isFound;
17 |
18 | public APIItem(String path) {
19 | this.path = path;
20 | }
21 |
22 | public APIItem(String method, String path) {
23 | this.method = method;
24 | this.path = path;
25 | }
26 |
27 | @Override
28 | public boolean equals(Object o) {
29 | if (this == o) return true;
30 | if (o == null || getClass() != o.getClass()) return false;
31 |
32 | APIItem item = (APIItem) o;
33 |
34 | if (item.getMethod() == null) {
35 | if (this.method == null) {
36 | if (item.getPath().equalsIgnoreCase(this.path)) {
37 | return true;
38 | }
39 |
40 | return false;
41 | } else {
42 | return false;
43 | }
44 | } else {
45 | if (this.method == null) {
46 | return false;
47 | } else {
48 | if (item.getMethod().equalsIgnoreCase(this.method) && item.getPath().equalsIgnoreCase(this.path)) {
49 | return true;
50 | }
51 |
52 | return false;
53 | }
54 | }
55 | }
56 |
57 | }
58 |
--------------------------------------------------------------------------------
/src/main/java/com/chave/pojo/MatchMod.java:
--------------------------------------------------------------------------------
1 | package com.chave.pojo;
2 |
3 | public enum MatchMod {
4 | exactMatch,
5 | semiFuzzMatch,
6 | fuzzMatch;
7 | }
8 |
--------------------------------------------------------------------------------
/src/main/java/com/chave/pojo/RuleItem.java:
--------------------------------------------------------------------------------
1 | package com.chave.pojo;
2 |
3 | import lombok.AllArgsConstructor;
4 | import lombok.Data;
5 | import lombok.NoArgsConstructor;
6 | import lombok.ToString;
7 | import java.io.Serializable;
8 |
9 | @Data
10 | @ToString
11 | @NoArgsConstructor
12 | @AllArgsConstructor
13 | public class RuleItem implements Serializable {
14 | private String name;
15 | private Boolean loaded;
16 | private String regex;
17 | private String scope;
18 | }
19 |
--------------------------------------------------------------------------------
/src/main/java/com/chave/service/APIMatchService.java:
--------------------------------------------------------------------------------
1 | package com.chave.service;
2 |
3 | import burp.api.montoya.http.message.requests.HttpRequest;
4 | import burp.api.montoya.logging.Logging;
5 | import com.chave.Main;
6 | import com.chave.config.APIConfig;
7 | import com.chave.config.UserConfig;
8 | import com.chave.pojo.APIItem;
9 | import com.chave.utils.Util;
10 | import java.util.HashMap;
11 | import java.util.regex.Matcher;
12 | import java.util.regex.Pattern;
13 |
14 | public class APIMatchService {
15 | private Logging log;
16 |
17 |
18 | public APIMatchService() {
19 | this.log = Main.API.logging();
20 | }
21 |
22 | // 精确匹配(只匹配path)
23 | // 不支持启用URL编码
24 | // 不支持检查完整数据包
25 | // 支持检查Method
26 | public HashMap exactMatch(HttpRequest request) {
27 | APIItem matchedItem = null;
28 | boolean isMatched = false;
29 | // 获取单纯的path
30 | String path = request.pathWithoutQuery();
31 |
32 | for (APIItem apiItem : APIConfig.TARGET_API) {
33 |
34 | // 如果测试状态是true(已测试状态) 则不再进行匹配
35 | if (apiItem.getState()) {
36 | continue;
37 | }
38 |
39 | // 处理没有 PathVariable 的情况
40 | if (isMatched = apiItem.getPath().equalsIgnoreCase(path)) {
41 | if (UserConfig.IS_CHECK_HTTP_METHOD && apiItem.getMethod() != null) {
42 | if (isMatched = (apiItem.getMethod().equalsIgnoreCase(request.method()))) { // 比较http method
43 | matchedItem = apiItem;
44 | break;
45 | }
46 | } else {
47 | matchedItem = apiItem;
48 | break;
49 | }
50 | } else {
51 | // 处理有 PathVariable 的情况
52 | Pattern pattern = Pattern.compile("^" + Util.convertPathToRegex(apiItem.getPath()) + "$", Pattern.CASE_INSENSITIVE);
53 | Matcher matcher = pattern.matcher(path);
54 | if (isMatched = matcher.matches()) {
55 | if (UserConfig.IS_CHECK_HTTP_METHOD && apiItem.getMethod() != null) {
56 | if (isMatched = (apiItem.getMethod().equalsIgnoreCase(request.method()))) {
57 | matchedItem = apiItem;
58 | break;
59 | }
60 | } else {
61 | matchedItem = apiItem;
62 | break;
63 | }
64 | }
65 | }
66 | }
67 |
68 | HashMap result = new HashMap();
69 | result.put("api", matchedItem);
70 | result.put("isMatched", isMatched);
71 |
72 | return result;
73 | }
74 |
75 |
76 | // 半模糊匹配(只匹配path)
77 | // 不支持启用URL编码
78 | // 不支持检查完整数据包
79 | // 支持检查Method
80 | public HashMap semiFuzzMatch(HttpRequest request) {
81 | boolean isMatched = false;
82 | Pattern pattern = null;
83 | APIItem matchedItem = null;
84 |
85 | // 获取单纯的path
86 | String path = request.pathWithoutQuery();
87 |
88 | for (APIItem apiItem : APIConfig.TARGET_API) {
89 |
90 | // 如果测试状态是true(已测试状态) 则不再进行匹配
91 | if (apiItem.getState()) {
92 | continue;
93 | }
94 |
95 | try {
96 | // 声明没有 PathVariable 情况下的正则
97 | pattern = Pattern.compile("^(/[^/]+)*" + apiItem.getPath() + "(/.*)?$", Pattern.CASE_INSENSITIVE);
98 | } catch (Exception e) {
99 | // 如果正则编译捕获异常,并且有"{",认为是有PathVariable的情况,重新生成正则。
100 | if (apiItem.getPath().contains("{")) {
101 | pattern = Pattern.compile("^(/[^/]+)*" + Util.convertPathToRegex(apiItem.getPath()) + "(/.*)?$", Pattern.CASE_INSENSITIVE);
102 | } else {
103 | // 其他情况认为是预期外的异常,直接输出log
104 | log.logToError("半精确匹配出现异常" + e.getCause());
105 | }
106 | }
107 |
108 | Matcher matcher = pattern.matcher(path);
109 | if (isMatched = matcher.matches()) {
110 | if (UserConfig.IS_CHECK_HTTP_METHOD && apiItem.getMethod() != null) {
111 | if (isMatched = (apiItem.getMethod().equalsIgnoreCase(request.method()))) { // 比较http method
112 | matchedItem = apiItem;
113 | break;
114 | }
115 | } else {
116 | matchedItem = apiItem;
117 | break;
118 | }
119 | }
120 | }
121 |
122 |
123 | HashMap result = new HashMap();
124 | result.put("api", matchedItem);
125 | result.put("isMatched", isMatched);
126 |
127 | return result;
128 | }
129 |
130 | // 模糊匹配(默认匹配path+参数)
131 | // 支持启用URL编码
132 | // 支持检查完整数据包
133 | // 支持检查Method
134 | public HashMap fuzzMatch(HttpRequest request) {
135 | boolean isMatched = false;
136 | Pattern pattern = null;
137 | APIItem matchedItem = null;
138 |
139 | for (APIItem apiItem : APIConfig.TARGET_API) {
140 | // 每次循环先赋值 便于找到匹配到的item位置
141 |
142 | // 如果测试状态是true(已测试状态) 则不再进行匹配
143 | if (apiItem.getState()) {
144 | continue;
145 | }
146 |
147 | if (UserConfig.IS_ANALYZE_PATHVARIABLE) {
148 | pattern = Pattern.compile(".*" + Util.convertPathToRegex(apiItem.getPath()) + ".*", Pattern.CASE_INSENSITIVE);
149 | } else {
150 | pattern = Pattern.compile(".*" + Pattern.quote(apiItem.getPath()) + ".*", Pattern.CASE_INSENSITIVE);
151 | }
152 |
153 |
154 | if (UserConfig.IS_CHECK_ENTIRE_REQUEST) {
155 | // 检查完整数据包匹配逻辑
156 | String requestData = request.toString();
157 |
158 | // 如果开启url编码 先对request进行解码
159 | if (UserConfig.IS_URL_DECODE) {
160 | requestData = Util.urlDecode(requestData);
161 | }
162 |
163 | // 去除换行 否则正则匹配异常
164 | requestData = requestData.replaceAll("\r\n", "");
165 |
166 | Matcher matcher = pattern.matcher(requestData);
167 |
168 | if (isMatched = matcher.matches()) {
169 | // 如果需要匹配method 则再次匹配method
170 | if (UserConfig.IS_CHECK_HTTP_METHOD && apiItem.getMethod() != null) {
171 | if (isMatched = (apiItem.getMethod().equalsIgnoreCase(request.method()))) { // 比较http method
172 | matchedItem = apiItem;
173 | break;
174 | }
175 | } else {
176 | matchedItem = apiItem;
177 | break;
178 | }
179 | }
180 | } else {
181 | // 默认情况下匹配path+参数 模糊匹配包含匹配参数 无需处理
182 | String path = request.path();
183 |
184 | if (UserConfig.IS_URL_DECODE) {
185 | // 处理开启url编码情况 先对path进行url解码
186 | path = Util.urlDecode(path);
187 | }
188 |
189 | Matcher matcher = pattern.matcher(path);
190 |
191 | if (isMatched = matcher.matches()) {
192 | if (UserConfig.IS_CHECK_HTTP_METHOD && apiItem.getMethod() != null) {
193 | // 如果需要检查method 并且apiItem的method不为空
194 | if (isMatched = (apiItem.getMethod().equalsIgnoreCase(request.method()))) { // 比较http method
195 | matchedItem = apiItem;
196 | break;
197 | }
198 | } else {
199 | matchedItem = apiItem;
200 | break;
201 | }
202 | }
203 | }
204 | }
205 |
206 | HashMap result = new HashMap();
207 | result.put("api", matchedItem);
208 | result.put("isMatched", isMatched);
209 | return result;
210 | }
211 | }
212 |
--------------------------------------------------------------------------------
/src/main/java/com/chave/service/SensitiveInfoMatchService.java:
--------------------------------------------------------------------------------
1 | package com.chave.service;
2 |
3 | import burp.api.montoya.http.message.requests.HttpRequest;
4 | import burp.api.montoya.http.message.responses.HttpResponse;
5 | import burp.api.montoya.logging.Logging;
6 | import com.chave.Main;
7 | import com.chave.config.SensitiveInfoConfig;
8 | import com.chave.pojo.RuleItem;
9 | import java.util.ArrayList;
10 | import java.util.HashMap;
11 | import java.util.regex.Matcher;
12 | import java.util.regex.Pattern;
13 |
14 | public class SensitiveInfoMatchService {
15 | private Logging log;
16 | private HashMap requestResult;
17 | private HashMap responseResult;
18 |
19 | public SensitiveInfoMatchService() {
20 | this.log = Main.API.logging();
21 | }
22 |
23 | public HashMap sensitiveInfoMatch(HttpRequest request) {
24 | try {
25 | // 每次调用初始化一个result
26 | requestResult = new HashMap<>();
27 |
28 | for (RuleItem ruleItem : SensitiveInfoConfig.RULE_LIST) {
29 | // 如果规则未启用 直接跳过
30 | if (!ruleItem.getLoaded()) {
31 | continue;
32 | }
33 |
34 | if (ruleItem.getScope().equals("response")) {
35 | // 如果规则只检查response 在request这里直接跳过
36 | continue;
37 | }
38 |
39 | ArrayList matchedData = new ArrayList<>();
40 |
41 | // 由于是敏感信息检查 替换掉\r\n方便匹配
42 | String requestData = request.toString().replaceAll("\r\n", ",");
43 |
44 | Pattern pattern = Pattern.compile(ruleItem.getRegex());
45 | Matcher matcher = pattern.matcher(requestData);
46 |
47 | while (matcher.find()) {
48 | matchedData.add(matcher.group());
49 | }
50 |
51 | // 匹配到了才往result中加数据
52 | if (matchedData.size() > 0) {
53 | requestResult.put(ruleItem.getName(), matchedData);
54 | }
55 | }
56 | } catch (NullPointerException nullPointerException) {
57 | // 空指针会在未开启敏感信息检查时出现 预期内异常 暂不做处理
58 | }
59 |
60 |
61 | return requestResult;
62 | }
63 |
64 |
65 | public HashMap sensitiveInfoMatch(HttpResponse response) {
66 | try {
67 | // 每次调用初始化一个result
68 | responseResult = new HashMap<>();
69 |
70 | for (RuleItem ruleItem : SensitiveInfoConfig.RULE_LIST) {
71 | // 如果规则未启用 直接跳过
72 | if (!ruleItem.getLoaded()) {
73 | continue;
74 | }
75 |
76 | if (ruleItem.getScope().equals("request")) {
77 | // 如果规则只检查request 在response这里直接跳过
78 | continue;
79 | }
80 |
81 | ArrayList matchedData = new ArrayList<>();
82 |
83 | // 由于是敏感信息检查 替换掉\r\n方便匹配
84 | String responseData = response.toString().replaceAll("\r\n", ",");
85 |
86 | Pattern pattern = Pattern.compile(ruleItem.getRegex());
87 | Matcher matcher = pattern.matcher(responseData);
88 |
89 | while (matcher.find()) {
90 | matchedData.add(matcher.group());
91 | }
92 |
93 | // 匹配到了才往result中加数据
94 | if (matchedData.size() > 0) {
95 | responseResult.put(ruleItem.getName(), matchedData);
96 | }
97 | }
98 | } catch (NullPointerException nullPointerException) {
99 | // 空指针会在未开启敏感信息检查时出现 预期内异常 暂不做处理
100 | }
101 |
102 | return responseResult;
103 | }
104 |
105 | }
106 |
--------------------------------------------------------------------------------
/src/main/java/com/chave/ui/HighlighterMainUI.java:
--------------------------------------------------------------------------------
1 | package com.chave.ui;
2 |
3 | import burp.api.montoya.http.message.requests.HttpRequest;
4 | import burp.api.montoya.http.message.responses.HttpResponse;
5 | import burp.api.montoya.logging.Logging;
6 | import burp.api.montoya.proxy.ProxyHttpRequestResponse;
7 | import com.chave.Main;
8 | import com.chave.config.APIConfig;
9 | import com.chave.config.SensitiveInfoConfig;
10 | import com.chave.config.UserConfig;
11 | import com.chave.pojo.APIItem;
12 | import com.chave.pojo.MatchMod;
13 | import com.chave.service.APIMatchService;
14 | import com.chave.service.SensitiveInfoMatchService;
15 | import com.chave.utils.Util;
16 | import lombok.Getter;
17 | import javax.swing.*;
18 | import javax.swing.border.TitledBorder;
19 | import javax.swing.event.*;
20 | import javax.swing.table.DefaultTableCellRenderer;
21 | import javax.swing.table.DefaultTableModel;
22 | import javax.swing.table.JTableHeader;
23 | import javax.swing.table.TableCellRenderer;
24 | import java.awt.*;
25 | import java.awt.event.*;
26 | import java.lang.reflect.Field;
27 | import java.lang.reflect.Method;
28 | import java.util.EventObject;
29 | import java.util.HashMap;
30 | import java.util.List;
31 |
32 | @Getter
33 | public class HighlighterMainUI {
34 | private Logging log;
35 |
36 | // 定义相关组件
37 | private JPanel highlighterPanel;
38 | private JPanel userOperationPanel;
39 | private JPanel apiSearchPanel;
40 | private JButton importAPIButton;
41 | private JButton changeStateButton;
42 | private JButton checkHistoryButton;
43 | private JButton apiSearchButton;
44 | private JComboBox matchModComboBox;
45 | private JCheckBox urldecodeCheckBox;
46 | private JCheckBox checkEntireReqCheckBox;
47 | private JCheckBox checkMethodCheckBox;
48 | private JTable apiTable;
49 | private JTextField apiSearchTextField;
50 |
51 |
52 | public HighlighterMainUI() {
53 | this.log = Main.API.logging();
54 | initHighlighterUI();
55 | }
56 |
57 | private void initHighlighterUI() {
58 |
59 | // 创建主面板并设置 BoxLayout 垂直排列
60 | highlighterPanel = new JPanel();
61 | BoxLayout mainLayout = new BoxLayout(highlighterPanel, BoxLayout.Y_AXIS);
62 | highlighterPanel.setLayout(mainLayout);
63 |
64 |
65 | // 创建 JTextArea
66 | JTextArea userInputTextArea = new JTextArea();
67 | TitledBorder titledBorder = BorderFactory.createTitledBorder("批量导入API");
68 | userInputTextArea.setBorder(BorderFactory.createCompoundBorder(userInputTextArea.getBorder(), titledBorder));
69 | JScrollPane scrollPane = new JScrollPane(userInputTextArea);
70 | scrollPane.setMaximumSize(new Dimension(2000, 260));
71 | scrollPane.setMaximumSize(new Dimension(2000, 260));
72 | scrollPane.setPreferredSize(new Dimension(2000, 260));
73 |
74 |
75 | // 设置用户操作面板
76 | userOperationPanel = new JPanel();
77 | BoxLayout userConfigLayout = new BoxLayout(userOperationPanel, BoxLayout.X_AXIS);
78 | userOperationPanel.setLayout(userConfigLayout);
79 | userOperationPanel.setMaximumSize(new Dimension(1000, 24));
80 | userOperationPanel.setMinimumSize(new Dimension(1000, 24));
81 | userOperationPanel.setPreferredSize(new Dimension(1000, 24));
82 | // 创建导入API按钮
83 | importAPIButton = new JButton("导入API");
84 | importAPIButton.setAlignmentX(Component.CENTER_ALIGNMENT);
85 | importAPIButton.setAlignmentY(Component.CENTER_ALIGNMENT);
86 | // 创建匹配模式下拉框
87 | String[] matchOptions = {"精确匹配", "半模糊匹配", "模糊匹配"};
88 | matchModComboBox = new JComboBox<>(matchOptions);
89 | matchModComboBox.setMaximumSize(new Dimension(100, 20));
90 | matchModComboBox.setAlignmentX(Component.CENTER_ALIGNMENT);
91 | matchModComboBox.setAlignmentY(Component.CENTER_ALIGNMENT);
92 | matchModComboBox.setSelectedIndex(0); // 默认选择精确匹配
93 | // 创建复选框启用URL解码
94 | urldecodeCheckBox = new JCheckBox("启用URL解码");
95 | urldecodeCheckBox.setEnabled(false); // 默认是精确匹配,初始化禁用
96 | // 创建复选框检查完整数据包
97 | checkEntireReqCheckBox = new JCheckBox("检查完整数据包");
98 | checkEntireReqCheckBox.setEnabled(false); // 默认是精确匹配,初始化禁用
99 | // 创建复选框检查Method
100 | checkMethodCheckBox = new JCheckBox("检查Method");
101 | // 创建检查History按钮
102 | checkHistoryButton = new JButton("检查history");
103 | // 创建切换漏洞状态按钮
104 | changeStateButton = new JButton("切换测试状态");
105 | // 向用户配置面板添加元素
106 | userOperationPanel.add(Box.createHorizontalGlue());
107 | userOperationPanel.add(importAPIButton);
108 | userOperationPanel.add(Box.createHorizontalStrut(20));
109 | userOperationPanel.add(matchModComboBox);
110 | userOperationPanel.add(Box.createHorizontalStrut(20));
111 | userOperationPanel.add(urldecodeCheckBox);
112 | userOperationPanel.add(Box.createHorizontalStrut(20));
113 | userOperationPanel.add(checkEntireReqCheckBox);
114 | userOperationPanel.add(Box.createHorizontalStrut(20));
115 | userOperationPanel.add(checkMethodCheckBox);
116 | userOperationPanel.add(Box.createHorizontalStrut(20));
117 | userOperationPanel.add(checkHistoryButton);
118 | userOperationPanel.add(Box.createHorizontalStrut(20));
119 | userOperationPanel.add(changeStateButton);
120 | userOperationPanel.add(Box.createHorizontalGlue());
121 |
122 |
123 |
124 | // 创建api列表
125 | String[] columnName = {"Method", "Path", "Result", "State", "Note", "IsFound"};
126 | DefaultTableModel model = new DefaultTableModel(columnName, 0) {
127 | @Override
128 | public boolean isCellEditable(int row, int column) {
129 | return true;
130 | }
131 | };
132 | apiTable = new JTable(model);
133 | apiTable.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION); // 支持不连续的多行选择
134 | // 禁止第三列表格编辑
135 | DefaultCellEditor disabledEditor = new DefaultCellEditor(new JTextField()) {
136 | @Override
137 | public boolean isCellEditable(EventObject anEvent) {
138 | return false;
139 | }
140 | };
141 | apiTable.getColumnModel().getColumn(2).setCellEditor(disabledEditor);
142 | // 设置第一列和第四列和第五列数据居中对齐
143 | TableCellRenderer centerRenderer = new DefaultTableCellRenderer();
144 | ((DefaultTableCellRenderer) centerRenderer).setHorizontalAlignment(SwingConstants.CENTER);
145 | apiTable.getColumnModel().getColumn(0).setCellRenderer(centerRenderer);
146 | apiTable.getColumnModel().getColumn(3).setCellRenderer(centerRenderer);
147 | apiTable.getColumnModel().getColumn(5).setCellRenderer(centerRenderer);
148 | // 设置表头背景
149 | JTableHeader apiTableHeader = apiTable.getTableHeader();
150 | apiTableHeader.setBackground(new Color(215, 215, 215));
151 | // 创建表格滚动面板
152 | JScrollPane apiTableScrollPane = new JScrollPane(apiTable);
153 | apiTableScrollPane.setMaximumSize(new Dimension(2000, 850));
154 |
155 |
156 |
157 | // 创建查找api面板
158 | apiSearchPanel = new JPanel();
159 | BoxLayout apiSearchLayout = new BoxLayout(apiSearchPanel, BoxLayout.X_AXIS);
160 | apiSearchPanel.setLayout(apiSearchLayout);
161 | apiSearchPanel.setMaximumSize(new Dimension(2000, 25));
162 | apiSearchPanel.setMinimumSize(new Dimension(2000, 25));
163 | // 创建搜索框
164 | apiSearchTextField = new JFormattedTextField();
165 | // 创建搜索按钮
166 | apiSearchButton = new JButton("查找API");
167 | // 将元素添加到面板
168 | apiSearchPanel.add(Box.createHorizontalStrut(5));
169 | apiSearchPanel.add(apiSearchTextField);
170 | apiSearchPanel.add(Box.createHorizontalStrut(5));
171 | apiSearchPanel.add(apiSearchButton);
172 | apiSearchPanel.add(Box.createHorizontalStrut(5));
173 |
174 |
175 |
176 | // 添加各个面板
177 | highlighterPanel.add(scrollPane); // 添加导入api面板
178 | highlighterPanel.add(userOperationPanel); // 添加用户配置面板
179 | highlighterPanel.add(apiTableScrollPane); // 添加api列表
180 | highlighterPanel.add(Box.createVerticalStrut(2)); // 添加一定间距
181 | highlighterPanel.add(apiSearchPanel); // 添加api查找面板
182 |
183 |
184 | // 导入API按钮监听器
185 | importAPIButton.addActionListener(new ActionListener() {
186 | @Override
187 | public void actionPerformed(ActionEvent e) {
188 | String userInput = userInputTextArea.getText().trim();
189 | if (userInput.length() == 0) {
190 | return;
191 | }
192 | String[] lines = userInput.split("\n");
193 | for (String line : lines) {
194 | // 如果包含","则认为需要创建带有method的对象
195 | if (line.contains(",")) {
196 | String[] split = line.split(",", 2);
197 | String method = split[0].trim();
198 | String path = split[1].trim();
199 | // 处理method为空 输入不合法的情况
200 | if (method.length() == 0
201 | || (!method.equalsIgnoreCase("GET")
202 | && !method.equalsIgnoreCase("POST")
203 | && !method.equalsIgnoreCase("PUT")
204 | && !method.equalsIgnoreCase("DELETE")
205 | && !method.equalsIgnoreCase("OPTIONS"))) {
206 | method = null;
207 | }
208 | if (path.length() == 0) {
209 | continue;
210 | }
211 |
212 |
213 | try {
214 | APIItem item;
215 | if (method == null) {
216 | item = new APIItem(path);
217 | } else {
218 | item = new APIItem(method.toUpperCase(), path);
219 | }
220 | if (!Util.checkAPIItemExist(item)) {
221 | APIConfig.TARGET_API.add(item);
222 | }
223 | } catch (Exception exception) {
224 | log.logToError("导入api出现异常" + exception.getCause());
225 | continue;
226 | }
227 |
228 |
229 | } else {
230 | if (line.trim().length() == 0) {
231 | continue;
232 | }
233 |
234 | try {
235 | APIItem item = new APIItem(line.trim());
236 | if (!Util.checkAPIItemExist(item)) {
237 | APIConfig.TARGET_API.add(item);
238 | }
239 | } catch (Exception exception) {
240 | log.logToError(exception);
241 | continue;
242 | }
243 |
244 |
245 | }
246 | }
247 |
248 | try {
249 | // 导入之后清空输入面板 清空当前列表刷新
250 | userInputTextArea.setText("");
251 | Util.flushAPIList(apiTable);
252 | } catch (Exception exception) {
253 | log.logToError("导入api后刷新异常" + exception.getCause());
254 | }
255 |
256 | }
257 | });
258 |
259 |
260 | // 监听匹配模式监听器
261 | matchModComboBox.addActionListener(new ActionListener() {
262 | @Override
263 | public void actionPerformed(ActionEvent e) {
264 | // 获取用户选择
265 | String selectedOption = (String) matchModComboBox.getSelectedItem();
266 |
267 | if ("精确匹配".equals(selectedOption)) {
268 | UserConfig.MATCH_MOD = MatchMod.exactMatch;
269 | // 不支持开启url解码
270 | urldecodeCheckBox.setEnabled(false);
271 | urldecodeCheckBox.setSelected(false);
272 | // 不支持检查完整数据包
273 | checkEntireReqCheckBox.setEnabled(false);
274 | checkEntireReqCheckBox.setSelected(false);
275 | // 每次切换匹配模式均初始化配置为false
276 | UserConfig.IS_URL_DECODE = Boolean.FALSE;
277 | UserConfig.IS_CHECK_ENTIRE_REQUEST = Boolean.FALSE;
278 | UserConfig.IS_CHECK_HTTP_METHOD = Boolean.FALSE;
279 | } else if ("半模糊匹配".equals(selectedOption)) {
280 | UserConfig.MATCH_MOD = MatchMod.semiFuzzMatch;
281 | // 不支持开启url解码
282 | urldecodeCheckBox.setEnabled(false);
283 | urldecodeCheckBox.setSelected(false);
284 | // 不支持检查完整数据包
285 | checkEntireReqCheckBox.setEnabled(false);
286 | // 每次切换匹配模式均初始化配置为false
287 | UserConfig.IS_URL_DECODE = Boolean.FALSE;
288 | UserConfig.IS_CHECK_ENTIRE_REQUEST = Boolean.FALSE;
289 | UserConfig.IS_CHECK_HTTP_METHOD = Boolean.FALSE;
290 | } else if ("模糊匹配".equals(selectedOption)) {
291 | UserConfig.MATCH_MOD = MatchMod.fuzzMatch;
292 | // 不支持开启url解码
293 | urldecodeCheckBox.setEnabled(true);
294 | urldecodeCheckBox.setSelected(false);
295 | // 不支持检查完整数据包
296 | checkEntireReqCheckBox.setEnabled(true);
297 | checkEntireReqCheckBox.setSelected(false);
298 | // 每次切换匹配模式均初始化配置为false 是否解析路径参数除外
299 | UserConfig.IS_URL_DECODE = Boolean.FALSE;
300 | UserConfig.IS_CHECK_ENTIRE_REQUEST = Boolean.FALSE;
301 | UserConfig.IS_CHECK_HTTP_METHOD = Boolean.FALSE;
302 |
303 | // 询问是否解析PathVariable
304 | showPathVariableDialog();
305 | }
306 | }
307 | });
308 |
309 |
310 | // 监听列表修改 同步对象修改 同时刷新列表防止输入预期外字符导致列表与ArrayList不一致
311 | model.addTableModelListener(new TableModelListener() {
312 | @Override
313 | public void tableChanged(TableModelEvent e) {
314 | try {
315 | int eventType = e.getType();
316 | int rowNumber = e.getLastRow();
317 | int columnNumber = e.getColumn();
318 | String value = ((String) model.getValueAt(rowNumber, columnNumber)).trim();
319 |
320 | // 同步修改ArrayList中的对象
321 | if (eventType == TableModelEvent.UPDATE) {
322 | APIItem item = APIConfig.TARGET_API.get(rowNumber);
323 | Field field = APIItem.class.getDeclaredField((String) APIConfig.ITEM_FIELD.get(columnNumber));
324 | field.setAccessible(true);
325 |
326 | // 验证数据合法性 数据合法才进行修改
327 | if (columnNumber == 0) {
328 | if (value.equalsIgnoreCase("GET")
329 | || value.equalsIgnoreCase("POST")
330 | || value.equalsIgnoreCase("PUT")
331 | || value.equalsIgnoreCase("DELETE")
332 | || value.equalsIgnoreCase("OPTIONS")) {
333 | field.set(item, value.toUpperCase());
334 | } else if (value.equalsIgnoreCase("null")) {
335 | field.set(item, null);
336 | }
337 | } else if (columnNumber == 3) {
338 | if (value.equalsIgnoreCase("true") || value.equalsIgnoreCase("false")) {
339 | field.set(item, Boolean.parseBoolean(value));
340 | }
341 | } else {
342 | field.set(item, value);
343 | }
344 |
345 | // 修改之后刷新列表 防止数据不一致
346 | Util.flushAPIList(apiTable);
347 |
348 | }
349 | } catch (ArrayIndexOutOfBoundsException arrayIndexOutOfBoundsException) {
350 | // 由于添加数据时也会触发该监听器,这里捕获添加多行数据时抛出的异常 不做处理
351 | } catch (Exception exception) {
352 | // 捕获预期外的异常
353 | log.logToError("修改表格出现异常");
354 | }
355 |
356 | }
357 | });
358 |
359 |
360 | // 添加url解码复选框监听器
361 | urldecodeCheckBox.addItemListener(new ItemListener() {
362 | @Override
363 | public void itemStateChanged(ItemEvent e) {
364 | if (e.getStateChange() == ItemEvent.SELECTED) {
365 | UserConfig.IS_URL_DECODE = Boolean.TRUE;
366 | } else if (e.getStateChange() == ItemEvent.DESELECTED) {
367 | UserConfig.IS_URL_DECODE = Boolean.FALSE;
368 | }
369 | }
370 | });
371 |
372 |
373 | // 添加检查完整数据包监听器
374 | checkEntireReqCheckBox.addItemListener(new ItemListener() {
375 | @Override
376 | public void itemStateChanged(ItemEvent e) {
377 | if (e.getStateChange() == ItemEvent.SELECTED) {
378 | UserConfig.IS_CHECK_ENTIRE_REQUEST = Boolean.TRUE;
379 | } else if (e.getStateChange() == ItemEvent.DESELECTED) {
380 | UserConfig.IS_CHECK_ENTIRE_REQUEST = Boolean.FALSE;
381 | }
382 | }
383 | });
384 |
385 | // 添加检查method监听器
386 | checkMethodCheckBox.addItemListener(new ItemListener() {
387 | @Override
388 | public void itemStateChanged(ItemEvent e) {
389 | if (e.getStateChange() == ItemEvent.SELECTED) {
390 | UserConfig.IS_CHECK_HTTP_METHOD = Boolean.TRUE;
391 | } else if (e.getStateChange() == ItemEvent.DESELECTED) {
392 | UserConfig.IS_CHECK_HTTP_METHOD = Boolean.FALSE;
393 | }
394 | }
395 | });
396 |
397 |
398 | // 检查history监听器
399 | checkHistoryButton.addActionListener(new ActionListener() {
400 | @Override
401 | public void actionPerformed(ActionEvent e) {
402 | // 获取匹配service用于检查
403 | APIMatchService apiMatchService = new APIMatchService();
404 | SensitiveInfoMatchService sensitiveInfoMatchService = new SensitiveInfoMatchService();
405 | // 获取所有history
406 | List historyList = Main.API.proxy().history();
407 | // 检查history先清空所有result和found状态 重新记录
408 | for (APIItem apiItem : APIConfig.TARGET_API) {
409 | if (apiItem.getState().equals(Boolean.FALSE)) { // 仅重置未测试完成的接口result、IsFound信息
410 | apiItem.setResult(null);
411 | apiItem.setIsFound(null);
412 | }
413 | }
414 | for (ProxyHttpRequestResponse proxyHttpRequestResponse : historyList) {
415 | // 获取要检查的request和response
416 | HttpRequest request = proxyHttpRequestResponse.request();
417 | HttpResponse response = proxyHttpRequestResponse.response();
418 | // 遍历检查
419 | try {
420 | HashMap apiMatchResult = Util.getAPIMatchResult(request);
421 | boolean isMatched = (boolean) apiMatchResult.get("isMatched");
422 | APIItem matchedItem = (APIItem) apiMatchResult.get("api");
423 |
424 | // 匹配到进行高亮
425 | if (isMatched) {
426 | // 匹配到进行高亮处理
427 | Util.setHighlightColor(proxyHttpRequestResponse, com.chave.config.Color.YELLOW);
428 |
429 | // 对匹配到的接口进行标记Found
430 | Util.setAPIFound(matchedItem.getPath(), request);
431 |
432 | if (SensitiveInfoConfig.IS_CHECK_SENSITIVE_INFO) {
433 | // 只对匹配到的接口进行敏感信息检查
434 | HashMap requestResult = sensitiveInfoMatchService.sensitiveInfoMatch(request);
435 | HashMap responseResult = sensitiveInfoMatchService.sensitiveInfoMatch(response);
436 | if (!requestResult.isEmpty() || !responseResult.isEmpty()) {
437 | // 对history进行红色高亮处理
438 | Util.setHighlightColor(proxyHttpRequestResponse, com.chave.config.Color.ORANGE);
439 |
440 | // 标记result 存在敏感信息
441 | Util.setAPIResult(APIConfig.SENSITIVE_INFO_RESULT, matchedItem.getPath(), request);
442 | }
443 | }
444 |
445 | // 刷新列表
446 | Util.flushAPIList(Main.UI.getHighlighterMainUI().getApiTable());
447 | } else {
448 | // 检查后如果没匹配到直接去除高亮
449 | Util.setHighlightColor(proxyHttpRequestResponse, com.chave.config.Color.NONE);
450 | }
451 | } catch (Exception exception) {
452 | log.logToError("检查history中存在异常");
453 | continue;
454 | }
455 | }
456 | }
457 | });
458 |
459 |
460 | // 添加表格键盘时间监听器 实现按退格键删除数据
461 | apiTable.addKeyListener(new KeyAdapter() {
462 | @Override
463 | public void keyPressed(KeyEvent e) {
464 | if (e.getKeyCode() == KeyEvent.VK_BACK_SPACE) {
465 | // 支持多行同时删除
466 | int[] selectedRows = apiTable.getSelectedRows();
467 |
468 | // 如果有选中的行
469 | if (selectedRows.length > 0) {
470 | // 由于删除行时会影响索引,所以需要倒序删除
471 | for (int i = selectedRows.length - 1; i >= 0; i--) {
472 | int row = selectedRows[i];
473 | // 删除选中的行
474 | APIConfig.TARGET_API.remove(row);
475 | model.removeRow(row);
476 | }
477 | }
478 |
479 | // 修改之后刷新列表 防止数据不一致
480 | Util.flushAPIList(apiTable);
481 | }
482 | }
483 | });
484 |
485 |
486 | // 查找API监听器
487 | apiSearchButton.addActionListener(new ActionListener() {
488 | @Override
489 | public void actionPerformed(ActionEvent e) {
490 | String searchAPI = apiSearchTextField.getText();
491 | // 先去除前后空格
492 | searchAPI = searchAPI.trim().toLowerCase();
493 | // 先去除目前所有的选中状态
494 | apiTable.clearSelection();
495 | // 支持精确匹配
496 |
497 | if (searchAPI.length() != 0) {
498 | if (searchAPI.contains("=")) {
499 |
500 | // 精确匹配支持所有字段匹配
501 | String[] split = searchAPI.split("=", 2);
502 | String key = split[0].trim();
503 | String value = split[1].trim();
504 | int index = 0;
505 |
506 | // 反射获取getter方法
507 | String methodName = "get" + key.substring(0, 1).toUpperCase() + key.substring(1);
508 | Method getterMethod = null;
509 | try {
510 | getterMethod = APIItem.class.getMethod(methodName, null);
511 | } catch (Exception exception) {
512 | log.logToError("查询key输入错误");
513 | try {
514 | // 当输入查询key错误时,默认查询path
515 | getterMethod = APIItem.class.getMethod("getPath");
516 | } catch (NoSuchMethodException noSuchMethodException) {
517 | // 这里不会有异常 方法一定存在
518 | }
519 | }
520 |
521 | for (APIItem apiItem : APIConfig.TARGET_API) {
522 | try {
523 | Object o = getterMethod.invoke(apiItem, null);
524 | if (o.toString().equalsIgnoreCase(value)) {
525 | apiTable.addRowSelectionInterval(index, index);
526 | apiTable.requestFocusInWindow(); // 立即刷新状态 便于删除
527 | }
528 | index++;
529 | } catch (NullPointerException nullPointerException) {
530 | // 空指针为预期内异常
531 | index++;
532 | continue;
533 | } catch (Exception exception) {
534 | index++;
535 | log.logToError(exception);
536 | }
537 | }
538 | } else {
539 | // 快速搜索仅支持快速搜索method/path/method,path
540 | if (searchAPI.contains(",")) {
541 | String[] split = searchAPI.split(",", 2);
542 | String method = split[0].trim();
543 | String path = split[1].trim();
544 | int index = 0;
545 |
546 | for (APIItem apiItem : APIConfig.TARGET_API) {
547 | if (apiItem.getMethod() == null) {
548 | index++;
549 | continue;
550 | }
551 |
552 | // 默认带","的情况就是匹配method的情况
553 | if (apiItem.getMethod().equalsIgnoreCase(method) && apiItem.getPath().equalsIgnoreCase(path)) {
554 | apiTable.setRowSelectionInterval(index, index);
555 | apiTable.requestFocusInWindow(); // 立即刷新状态 便于删除
556 | }
557 | index++;
558 | }
559 | } else {
560 | if (searchAPI.equals("*")) {
561 | apiTable.setRowSelectionInterval(0, APIConfig.TARGET_API.size() - 1);
562 | apiTable.requestFocusInWindow(); // 立即刷新状态 便于删除
563 | } else {
564 | String path = searchAPI;
565 | int index = 0;
566 | for (APIItem apiItem : APIConfig.TARGET_API) {
567 | if (apiItem.getPath().equalsIgnoreCase(path)) {
568 | apiTable.addRowSelectionInterval(index, index);
569 | apiTable.requestFocusInWindow(); // 立即刷新状态 便于删除
570 | }
571 | index++;
572 | }
573 | }
574 | }
575 | }
576 | }
577 | }
578 | });
579 |
580 |
581 | // 切换测试状态按钮监听器
582 | changeStateButton.addActionListener(new ActionListener() {
583 | @Override
584 | public void actionPerformed(ActionEvent e) {
585 | // 支持多行同时修改
586 | int[] selectedRows = apiTable.getSelectedRows();
587 |
588 | for (int selectedRow : selectedRows) {
589 | if (APIConfig.TARGET_API.get(selectedRow).getState() == Boolean.FALSE) {
590 | APIConfig.TARGET_API.get(selectedRow).setState(Boolean.TRUE);
591 | } else {
592 | APIConfig.TARGET_API.get(selectedRow).setState(Boolean.FALSE);
593 | }
594 | }
595 |
596 | // 刷新列表
597 | Util.flushAPIList(apiTable);
598 | }
599 | });
600 | }
601 |
602 |
603 | private static void showPathVariableDialog() {
604 | // 根据 UserConfig.IS_ANALYZE_PATHVARIABLE 提示当前状态
605 | JLabel jLabel = new JLabel("当前状态:" + UserConfig.IS_ANALYZE_PATHVARIABLE);
606 |
607 | // 创建确认对话框
608 | int option = JOptionPane.showConfirmDialog(null, jLabel,
609 | "是否解析 PathVariable?", JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE);
610 |
611 | // 检测用户选择
612 | if (option == JOptionPane.YES_OPTION) {
613 | // 用户选择了 "是"
614 | UserConfig.IS_ANALYZE_PATHVARIABLE = true; // 更新配置
615 | } else if (option == JOptionPane.NO_OPTION) {
616 | // 用户选择了 "否"
617 | UserConfig.IS_ANALYZE_PATHVARIABLE = false; // 更新配置
618 | } else if (option == JOptionPane.CLOSED_OPTION) {
619 | // 用户直接关闭了对话框,不做处理
620 | }
621 | }
622 | }
623 |
--------------------------------------------------------------------------------
/src/main/java/com/chave/ui/MainUI.java:
--------------------------------------------------------------------------------
1 | package com.chave.ui;
2 |
3 | import burp.api.montoya.logging.Logging;
4 | import com.chave.Main;
5 | import lombok.Getter;
6 | import javax.swing.*;
7 |
8 | @Getter
9 | public class MainUI {
10 | private JTabbedPane mainTabbedPane = new JTabbedPane();
11 | private Logging log;
12 | private HighlighterMainUI highlighterMainUI;
13 | private SensitiveInfoMainUI sensitiveInfoMainUI;
14 |
15 | public MainUI() {
16 | this.log = Main.API.logging();
17 | initUI();
18 | }
19 |
20 | private void initUI() {
21 | // 创建各个组件ui实例
22 | highlighterMainUI = new HighlighterMainUI();
23 | sensitiveInfoMainUI = new SensitiveInfoMainUI();
24 |
25 | mainTabbedPane.add("Highlighter", highlighterMainUI.getHighlighterPanel()); // 添加高亮功能ui
26 | mainTabbedPane.add("Sensitive Info", sensitiveInfoMainUI.getSensitiveInfoPanel()); // 添加敏感信息检查功能ui
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/src/main/java/com/chave/ui/SensitiveInfoMainUI.java:
--------------------------------------------------------------------------------
1 | package com.chave.ui;
2 |
3 | import burp.api.montoya.logging.Logging;
4 | import com.chave.Main;
5 | import com.chave.config.SensitiveInfoConfig;
6 | import com.chave.pojo.RuleItem;
7 | import com.chave.utils.Util;
8 | import lombok.Getter;
9 | import javax.swing.*;
10 | import javax.swing.table.DefaultTableCellRenderer;
11 | import javax.swing.table.DefaultTableModel;
12 | import javax.swing.table.JTableHeader;
13 | import javax.swing.table.TableCellRenderer;
14 | import java.awt.*;
15 | import java.awt.event.ActionEvent;
16 | import java.awt.event.ActionListener;
17 | import java.awt.event.ItemEvent;
18 | import java.awt.event.ItemListener;
19 | import java.io.*;
20 | import java.util.ArrayList;
21 | import java.util.EventObject;
22 |
23 | @Getter
24 | public class SensitiveInfoMainUI {
25 | private Logging log;
26 |
27 | // 创建相关组件
28 | private JPanel sensitiveInfoPanel;
29 | private JPanel userConfigPanel;
30 | private JPanel ruleListMainPanel;
31 | private JPanel userOperationPanel;
32 | private JButton addRuleButton;
33 | private JButton editRuleButton;
34 | private JButton removeRuleButton;
35 | private JButton changeRuleLoadStateButton;
36 | private JTextField userConfigTextField;
37 | private JCheckBox isCheckSensitiveInfoCheckBox;
38 | private JLabel ruleFileLabel;
39 | private JTable ruleTable;
40 |
41 | public SensitiveInfoMainUI() {
42 | this.log = Main.API.logging();
43 | initSensitiveInfoUI();
44 | }
45 |
46 | private void initSensitiveInfoUI() {
47 | // 创建主面板并设置 BoxLayout 垂直排列
48 | sensitiveInfoPanel = new JPanel();
49 | BoxLayout mainLayOut = new BoxLayout(sensitiveInfoPanel, BoxLayout.Y_AXIS);
50 | sensitiveInfoPanel.setLayout(mainLayOut);
51 |
52 |
53 | // 绘制用户配置界面
54 | userConfigPanel = new JPanel();
55 | BoxLayout userConfigLayout = new BoxLayout(userConfigPanel, BoxLayout.X_AXIS);
56 | userConfigPanel.setLayout(userConfigLayout);
57 | userConfigPanel.setMaximumSize(new Dimension(2000, 25));
58 | userConfigPanel.setMinimumSize(new Dimension(2000, 25));
59 | // 创建配置文件输入框
60 | userConfigTextField = new JTextField();
61 | userConfigTextField.setText(SensitiveInfoConfig.RULE_CONFIG_FILE);
62 | // 创建开启敏感信息检查复选框
63 | isCheckSensitiveInfoCheckBox = new JCheckBox("开启敏感信息检查");
64 | // 创建规则文件输入提示标签
65 | ruleFileLabel = new JLabel("规则配置文件:");
66 | // 将组件添加到面板
67 | userConfigPanel.add(Box.createHorizontalStrut(10));
68 | userConfigPanel.add(ruleFileLabel);
69 | userConfigPanel.add(Box.createHorizontalStrut(13));
70 | userConfigPanel.add(userConfigTextField);
71 | userConfigPanel.add(Box.createHorizontalStrut(20));
72 | userConfigPanel.add(isCheckSensitiveInfoCheckBox);
73 | userConfigPanel.add(Box.createHorizontalStrut(10));
74 |
75 |
76 | // 绘制规则展示、操作面板
77 | ruleListMainPanel = new JPanel(); // 主面板
78 | BoxLayout ruleListMainLayout = new BoxLayout(ruleListMainPanel, BoxLayout.X_AXIS);
79 | ruleListMainPanel.setLayout(ruleListMainLayout);
80 | userOperationPanel = new JPanel(); // 用户操作面板
81 | BoxLayout userOperationLayout = new BoxLayout(userOperationPanel, BoxLayout.Y_AXIS);
82 | userOperationPanel.setLayout(userOperationLayout);
83 | userOperationPanel.setMaximumSize(new Dimension(80, 10000));
84 | userOperationPanel.setMaximumSize(new Dimension(80, 10000));
85 | // 创建列表操作按钮
86 | addRuleButton = new JButton("add");
87 | addRuleButton.setMaximumSize(new Dimension(100, 28));
88 | addRuleButton.setMinimumSize(new Dimension(100, 28));
89 | editRuleButton = new JButton("edit");
90 | editRuleButton.setMaximumSize(new Dimension(100, 28));
91 | editRuleButton.setMinimumSize(new Dimension(100, 28));
92 | removeRuleButton = new JButton("remove");
93 | removeRuleButton.setMaximumSize(new Dimension(100, 28));
94 | removeRuleButton.setMinimumSize(new Dimension(100, 28));
95 | changeRuleLoadStateButton = new JButton("load/unload");
96 | changeRuleLoadStateButton.setMaximumSize(new Dimension(100, 28));
97 | changeRuleLoadStateButton.setMinimumSize(new Dimension(100, 28));
98 | // 将用户操作按钮添加到操作面板
99 | userOperationPanel.add(addRuleButton);
100 | userOperationPanel.add(Box.createVerticalStrut(20));
101 | userOperationPanel.add(editRuleButton);
102 | userOperationPanel.add(Box.createVerticalStrut(20));
103 | userOperationPanel.add(removeRuleButton);
104 | userOperationPanel.add(Box.createVerticalStrut(20));
105 | userOperationPanel.add(changeRuleLoadStateButton);
106 |
107 |
108 | // 创建规则展示表格
109 | String[] columnName = {"Loaded", "Name", "Regex", "Scope"};
110 | DefaultTableModel model = new DefaultTableModel(columnName, 0) {
111 | @Override
112 | public boolean isCellEditable(int row, int column) {
113 | return true;
114 | }
115 | };
116 | ruleTable = new JTable(model);
117 | ruleTable.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION); // 支持不连续的多行选择
118 | // 设置表头背景
119 | JTableHeader ruleTableHeader = ruleTable.getTableHeader();
120 | ruleTableHeader.setBackground(new Color(215, 215, 215));
121 | // 创建表格滚动面板
122 | JScrollPane ruleTableScrollPane = new JScrollPane(ruleTable);
123 | // 设置表格默认宽度
124 | ruleTable.getColumnModel().getColumn(0).setMaxWidth(100);
125 | ruleTable.getColumnModel().getColumn(0).setMinWidth(100);
126 | ruleTable.getColumnModel().getColumn(1).setMaxWidth(200);
127 | ruleTable.getColumnModel().getColumn(1).setMinWidth(200);
128 | ruleTable.getColumnModel().getColumn(3).setMaxWidth(150);
129 | ruleTable.getColumnModel().getColumn(3).setMinWidth(150);
130 | // 设置第一列(索引0)和第四列(索引3)数据居中对齐
131 | TableCellRenderer centerRenderer = new DefaultTableCellRenderer();
132 | ((DefaultTableCellRenderer) centerRenderer).setHorizontalAlignment(SwingConstants.CENTER);
133 | ruleTable.getColumnModel().getColumn(0).setCellRenderer(centerRenderer);
134 | ruleTable.getColumnModel().getColumn(3).setCellRenderer(centerRenderer);
135 | // 禁止直接表格编辑
136 | DefaultCellEditor disabledEditor = new DefaultCellEditor(new JTextField()) {
137 | @Override
138 | public boolean isCellEditable(EventObject anEvent) {
139 | return false;
140 | }
141 | };
142 | ruleTable.getColumnModel().getColumn(0).setCellEditor(disabledEditor);
143 | ruleTable.getColumnModel().getColumn(1).setCellEditor(disabledEditor);
144 | ruleTable.getColumnModel().getColumn(2).setCellEditor(disabledEditor);
145 | ruleTable.getColumnModel().getColumn(3).setCellEditor(disabledEditor);
146 | // 将各个组件添加到展示面板
147 | ruleListMainPanel.add(Box.createHorizontalStrut(10));
148 | ruleListMainPanel.add(userOperationPanel);
149 | ruleListMainPanel.add(Box.createHorizontalStrut(10));
150 | ruleListMainPanel.add(ruleTableScrollPane);
151 | ruleListMainPanel.add(Box.createHorizontalStrut(10));
152 |
153 |
154 | // 将各个组件添加到主面板
155 | sensitiveInfoPanel.add(Box.createVerticalStrut(20));
156 | sensitiveInfoPanel.add(userConfigPanel);
157 | sensitiveInfoPanel.add(Box.createVerticalStrut(20));
158 | sensitiveInfoPanel.add(ruleListMainPanel);
159 | sensitiveInfoPanel.add(Box.createVerticalStrut(10));
160 |
161 |
162 |
163 | isCheckSensitiveInfoCheckBox.addItemListener(new ItemListener() {
164 | @Override
165 | public void itemStateChanged(ItemEvent e) {
166 | if (e.getStateChange() == ItemEvent.SELECTED && SensitiveInfoConfig.IS_CHECK_SENSITIVE_INFO == Boolean.FALSE) {
167 | try {
168 | String filePath = userConfigTextField.getText().trim();
169 | File ruleYamlFile = new File(filePath);
170 | if (ruleYamlFile.exists()) {
171 | Util.loadRuleYamlConfig(filePath);
172 | SensitiveInfoConfig.IS_CHECK_SENSITIVE_INFO = Boolean.TRUE;
173 | isCheckSensitiveInfoCheckBox.setSelected(true);
174 | } else {
175 | showCreateDefaultConfigDialog(isCheckSensitiveInfoCheckBox);
176 | }
177 |
178 | // 如果成功加载yaml配置 则展示规则列表
179 | if (SensitiveInfoConfig.IS_CHECK_SENSITIVE_INFO) {
180 | Util.flushRuleList(ruleTable);
181 | }
182 | } catch (Exception exception) {
183 | isCheckSensitiveInfoCheckBox.setSelected(false);
184 | log.logToError("Yaml配置文件加载异常.");
185 | }
186 |
187 | } else if (e.getStateChange() == ItemEvent.DESELECTED && SensitiveInfoConfig.IS_CHECK_SENSITIVE_INFO == Boolean.TRUE) {
188 | // 清空表格
189 | model.setRowCount(0);
190 | // 直接清空list
191 | SensitiveInfoConfig.RULE_LIST = null;
192 | // 关闭检查敏感信息
193 | SensitiveInfoConfig.IS_CHECK_SENSITIVE_INFO = Boolean.FALSE;
194 | }
195 | }
196 | });
197 |
198 |
199 | changeRuleLoadStateButton.addActionListener(new ActionListener() {
200 | @Override
201 | public void actionPerformed(ActionEvent e) {
202 | operateRuleDialog("changeState");
203 | }
204 | });
205 |
206 |
207 | addRuleButton.addActionListener(new ActionListener() {
208 | @Override
209 | public void actionPerformed(ActionEvent e) {
210 | operateRuleDialog("add");
211 | }
212 | });
213 |
214 | editRuleButton.addActionListener(new ActionListener() {
215 | @Override
216 | public void actionPerformed(ActionEvent e) {
217 | operateRuleDialog("edit");
218 | }
219 | });
220 |
221 | removeRuleButton.addActionListener(new ActionListener() {
222 | @Override
223 | public void actionPerformed(ActionEvent e) {
224 | operateRuleDialog("remove");
225 | }
226 | });
227 |
228 | }
229 |
230 | // 添加规则
231 | private void operateRuleDialog(String operation) {
232 | try {
233 | // 创建弹窗ui需要组件
234 | JPanel operateRuleMainPanel = new JPanel();
235 | JPanel namePanel = new JPanel();
236 | JPanel regexPanel = new JPanel();
237 | JPanel scopePanel = new JPanel();
238 | JLabel nameLabel = new JLabel("Name: ");
239 | JLabel regexLabel = new JLabel("Regex: ");
240 | JLabel scopeLabel = new JLabel("Scope: ");
241 | JLabel removeTipLabel = new JLabel("是否删除所有选中规则?");
242 | JTextField nameTextField = new JTextField();
243 | JTextField regexTextField = new JTextField();
244 | String[] scopeOptions = {"any", "request", "response"};
245 | JComboBox scopeComboBox = new JComboBox(scopeOptions);
246 |
247 | // 设置布局
248 | BoxLayout addRuleMainLayout = new BoxLayout(operateRuleMainPanel, BoxLayout.Y_AXIS);
249 | BoxLayout nameLayout = new BoxLayout(namePanel, BoxLayout.X_AXIS);
250 | BoxLayout regexLayout = new BoxLayout(regexPanel, BoxLayout.X_AXIS);
251 | BoxLayout scopeLayout = new BoxLayout(scopePanel, BoxLayout.X_AXIS);
252 | operateRuleMainPanel.setLayout(addRuleMainLayout);
253 | namePanel.setLayout(nameLayout);
254 | regexPanel.setLayout(regexLayout);
255 | scopePanel.setLayout(scopeLayout);
256 |
257 | // 添加各个组件
258 | namePanel.add(nameLabel);
259 | namePanel.add(Box.createHorizontalStrut(3));
260 | namePanel.add(nameTextField);
261 | regexPanel.add(regexLabel);
262 | regexPanel.add(regexTextField);
263 | scopePanel.add(scopeLabel);
264 | scopePanel.add(scopeComboBox);
265 | operateRuleMainPanel.add(namePanel);
266 | operateRuleMainPanel.add(Box.createVerticalStrut(10));
267 | operateRuleMainPanel.add(regexPanel);
268 | operateRuleMainPanel.add(Box.createVerticalStrut(10));
269 | operateRuleMainPanel.add(scopePanel);
270 |
271 |
272 | int option = 0;
273 | if (operation.equals("add")) {
274 | option = JOptionPane.showConfirmDialog(null, operateRuleMainPanel, "添加规则", JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE);
275 | } else if (operation.equals("edit")) {
276 | int[] selectedRows = ruleTable.getSelectedRows();
277 | if (!(selectedRows.length > 0)) {
278 | return; // 如果没选中 直接退出 防止异常
279 | }
280 | int selectedRow = selectedRows[0];
281 |
282 | // 如果是编辑 先展示当前数据
283 | nameTextField.setText(SensitiveInfoConfig.RULE_LIST.get(selectedRow).getName());
284 | regexTextField.setText(SensitiveInfoConfig.RULE_LIST.get(selectedRow).getRegex());
285 | scopeComboBox.setSelectedItem(SensitiveInfoConfig.RULE_LIST.get(selectedRow).getScope());
286 |
287 | option = JOptionPane.showConfirmDialog(null, operateRuleMainPanel, "编辑规则", JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE);
288 | } else if (operation.equals("remove")) {
289 | int[] selectedRows = ruleTable.getSelectedRows();
290 | if (!(selectedRows.length > 0)) {
291 | return; // 如果没选中 直接退出 防止异常
292 | }
293 | option = JOptionPane.showConfirmDialog(null, removeTipLabel, "删除规则", JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE);
294 | } else if (operation.equals("changeState")) {
295 | int[] selectedRows = ruleTable.getSelectedRows();
296 | if (!(selectedRows.length > 0)) {
297 | return; // 如果没选中 直接退出 防止异常
298 | }
299 | }
300 |
301 |
302 | // 只有选择"是" 进行操作 其他情况不做处理
303 | if (option == JOptionPane.YES_OPTION) {
304 | if (operation.equals("add")) {
305 | RuleItem ruleItem = new RuleItem(nameTextField.getText(), Boolean.TRUE, regexTextField.getText(), (String) scopeComboBox.getSelectedItem());
306 | SensitiveInfoConfig.RULE_LIST.add(ruleItem);
307 | } else if (operation.equals("edit")) {
308 | int selectedRow = ruleTable.getSelectedRows()[0]; // 如果同时选择多行 只取第一个
309 |
310 | // 修改rule_list中的值
311 | RuleItem ruleItem = SensitiveInfoConfig.RULE_LIST.get(selectedRow);
312 | ruleItem.setName(nameTextField.getText());
313 | ruleItem.setRegex(regexTextField.getText());
314 | ruleItem.setScope((String) scopeComboBox.getSelectedItem());
315 | } else if (operation.equals("remove")) {
316 | int[] selectedRows = ruleTable.getSelectedRows();
317 | // 如果有选中的行
318 | if (selectedRows.length > 0) {
319 | // 由于删除行时会影响索引,所以需要倒序删除
320 | for (int i = selectedRows.length - 1; i >= 0; i--) {
321 | int row = selectedRows[i];
322 | // 删除选中的行
323 | SensitiveInfoConfig.RULE_LIST.remove(row);
324 | }
325 | }
326 | } else if (operation.equals("changeState")) {
327 | // 支持多行同时修改
328 | int[] selectedRows = ruleTable.getSelectedRows();
329 |
330 | for (int selectedRow : selectedRows) {
331 | if (SensitiveInfoConfig.RULE_LIST.get(selectedRow).getLoaded() == Boolean.FALSE) {
332 | SensitiveInfoConfig.RULE_LIST.get(selectedRow).setLoaded(Boolean.TRUE);
333 | } else {
334 | SensitiveInfoConfig.RULE_LIST.get(selectedRow).setLoaded(Boolean.FALSE);
335 | }
336 | }
337 | }
338 |
339 | // 刷新列表 直接导出新的数据覆盖原文件
340 | Util.flushRuleList(ruleTable);
341 | Util.exportToYaml();
342 | }
343 | } catch (Exception e) {
344 | log.logToError(e);
345 | }
346 | }
347 |
348 |
349 |
350 | private void showCreateDefaultConfigDialog(JCheckBox jCheckBox) throws IOException, ClassNotFoundException {
351 | JLabel jLabel = new JLabel("是否使用默认规则?");
352 | // 创建确认对话框
353 | int option = JOptionPane.showConfirmDialog(null, jLabel, "目标文件不存在", JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE);
354 |
355 | // 检测用户选择
356 | if (option == JOptionPane.YES_OPTION) {
357 | // 用户选择了 "是"
358 | ByteArrayInputStream bais = new ByteArrayInputStream(Util.base64ToByteCode(SensitiveInfoConfig.DEFAULT_RULE_LIST_DATA));
359 | ObjectInputStream ois = new ObjectInputStream(bais);
360 | SensitiveInfoConfig.RULE_LIST = (ArrayList) ois.readObject();
361 |
362 | // 切换敏感信息检查状态
363 | SensitiveInfoConfig.IS_CHECK_SENSITIVE_INFO = Boolean.TRUE;
364 | // 将默认规则导出到文件
365 | Util.exportToYaml();
366 | jCheckBox.setSelected(true);
367 | } else if (option == JOptionPane.NO_OPTION) {
368 | // 用户选择了 "否",保持未勾选状态
369 | jCheckBox.setSelected(false);
370 | } else if (option == JOptionPane.CLOSED_OPTION) {
371 | // 用户直接关闭了对话框,保持未勾选状态
372 | jCheckBox.setSelected(false);
373 | }
374 | }
375 |
376 | }
377 |
378 |
379 |
--------------------------------------------------------------------------------
/src/main/java/com/chave/utils/Util.java:
--------------------------------------------------------------------------------
1 | package com.chave.utils;
2 |
3 | import burp.api.montoya.core.Annotations;
4 | import burp.api.montoya.http.message.requests.HttpRequest;
5 | import burp.api.montoya.internal.ObjectFactoryLocator;
6 | import com.chave.Main;
7 | import com.chave.config.APIConfig;
8 | import com.chave.config.SensitiveInfoConfig;
9 | import com.chave.config.UserConfig;
10 | import com.chave.pojo.APIItem;
11 | import com.chave.pojo.RuleItem;
12 | import com.chave.service.APIMatchService;
13 | import org.yaml.snakeyaml.DumperOptions;
14 | import org.yaml.snakeyaml.Yaml;
15 | import javax.swing.*;
16 | import javax.swing.table.DefaultTableModel;
17 | import java.io.*;
18 | import java.lang.reflect.InvocationTargetException;
19 | import java.lang.reflect.Method;
20 | import java.util.*;
21 |
22 | public class Util {
23 | public static String convertPathToRegex(String path) {
24 | // 使用正则表达式替换 {.*} 为 [^/]+
25 | return path.replaceAll("\\{[^/]+\\}", "[^/]+");
26 | }
27 |
28 | public static boolean checkAPIItemExist(APIItem o) {
29 | boolean isExist = false;
30 |
31 | if (APIConfig.TARGET_API.isEmpty()) {
32 | return isExist;
33 | }
34 |
35 | for (APIItem apiItem : APIConfig.TARGET_API) {
36 | if (apiItem.equals(o)) {
37 | isExist = true;
38 | break;
39 | }
40 | }
41 | return isExist;
42 | }
43 |
44 |
45 | public static void setHighlightColor(Object obj, String color) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
46 | Class> requestClass = obj.getClass();
47 | Method annotationsMethod = requestClass.getMethod("annotations");
48 | Annotations annotations = (Annotations) annotationsMethod.invoke(obj, null);
49 |
50 | annotations.setHighlightColor(ObjectFactoryLocator.FACTORY.highlightColor(color));
51 | }
52 |
53 | public static synchronized void flushAPIList(JTable table) {
54 | // 修改之后刷新列表 防止数据不一致
55 | DefaultTableModel model = (DefaultTableModel) table.getModel();
56 | model.setRowCount(0);
57 | for (APIItem apiItem : APIConfig.TARGET_API) {
58 | model.addRow(new Object[]{apiItem.getMethod(), apiItem.getPath(), apiItem.getResult(), apiItem.getState(), apiItem.getNote(), apiItem.getIsFound()});
59 | }
60 | }
61 |
62 | public static void flushRuleList(JTable table) {
63 | // 修改之后刷新列表 防止数据不一致
64 | DefaultTableModel model = (DefaultTableModel) table.getModel();
65 | model.setRowCount(0);
66 | for (RuleItem ruleItem : SensitiveInfoConfig.RULE_LIST) {
67 | model.addRow(new Object[]{ruleItem.getLoaded(), ruleItem.getName(), ruleItem.getRegex(), ruleItem.getScope()});
68 | }
69 | }
70 |
71 | public static String urlDecode(String input) {
72 | return Main.API.utilities().urlUtils().decode(input);
73 | }
74 |
75 | public static void loadRuleYamlConfig(String filePath) throws FileNotFoundException {
76 | FileInputStream fis = new FileInputStream(filePath);
77 | SensitiveInfoConfig.RULE_CONFIG_FILE = filePath;
78 |
79 | LinkedHashMap linkedHashMap = new Yaml().load(fis);
80 | ArrayList arrayList = (ArrayList) linkedHashMap.get("rules");
81 |
82 | SensitiveInfoConfig.RULE_LIST = new ArrayList();
83 | for (LinkedHashMap hashMap : arrayList) {
84 | RuleItem ruleItem = new RuleItem((String) hashMap.get("name"), (Boolean) hashMap.get("loaded"), (String) hashMap.get("regex"), (String) hashMap.get("scope"));
85 | SensitiveInfoConfig.RULE_LIST.add(ruleItem);
86 | }
87 | }
88 |
89 | public static HashMap getAPIMatchResult(HttpRequest request) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
90 | Method matchMethod = APIMatchService.class.getMethod(UserConfig.MATCH_MOD.name(), HttpRequest.class);
91 | HashMap apiMatchResult = (HashMap) matchMethod.invoke(new APIMatchService(), request);
92 | return apiMatchResult;
93 | }
94 |
95 | // 设置api找到状态
96 | public static void setAPIFound(String path, HttpRequest request) {
97 | ArrayList matchedItem = new ArrayList<>();
98 | for (APIItem apiItem : APIConfig.TARGET_API) {
99 | if (apiItem.getPath().equals(path)) {
100 | matchedItem.add(apiItem);
101 | }
102 | }
103 |
104 | if (UserConfig.IS_CHECK_HTTP_METHOD) {
105 | for (APIItem apiItem : matchedItem) {
106 | if (apiItem.getMethod() == null) {
107 | apiItem.setIsFound("Found");
108 | } else {
109 | if (apiItem.getMethod().equalsIgnoreCase(request.method())) {
110 | apiItem.setIsFound("Found");
111 | }
112 | }
113 | }
114 | } else {
115 | for (APIItem apiItem : matchedItem) {
116 | apiItem.setIsFound("Found");
117 | }
118 | }
119 | }
120 |
121 | // 设置APIItem result
122 | public static void setAPIResult(String result, String path, HttpRequest request) {
123 | ArrayList matchedItem = new ArrayList<>();
124 | for (APIItem apiItem : APIConfig.TARGET_API) {
125 | if (apiItem.getPath().equals(path)) {
126 | matchedItem.add(apiItem);
127 | }
128 | }
129 |
130 | if (UserConfig.IS_CHECK_HTTP_METHOD) {
131 | for (APIItem apiItem : matchedItem) {
132 | if (apiItem.getMethod() == null) {
133 | if (apiItem.getResult() != null && !apiItem.getResult().contains(result)) {
134 | apiItem.setResult(apiItem.getResult() + "/" + result);
135 | } else {
136 | apiItem.setResult(result);
137 | }
138 | } else {
139 | if (apiItem.getMethod().equalsIgnoreCase(request.method())) {
140 | if (apiItem.getResult() != null && !apiItem.getResult().contains(result)) {
141 | apiItem.setResult(apiItem.getResult() + "/" + result);
142 | } else {
143 | apiItem.setResult(result);
144 | }
145 | }
146 | }
147 | }
148 | } else {
149 | for (APIItem apiItem : matchedItem) {
150 | if (apiItem.getResult() != null && !apiItem.getResult().contains(result)) {
151 | apiItem.setResult(apiItem.getResult() + "/" + result);
152 | } else {
153 | apiItem.setResult(result);
154 | }
155 | }
156 | }
157 | }
158 |
159 | public static byte[] getSerializedData(Object obj) throws IOException {
160 | ByteArrayOutputStream bos = new ByteArrayOutputStream();
161 | ObjectOutputStream oos = new ObjectOutputStream(bos);
162 | oos.writeObject(obj);
163 | return bos.toByteArray();
164 | }
165 |
166 | public static String byteCodeToBase64(byte[] code) {
167 | return Base64.getEncoder().encodeToString(code);
168 | }
169 |
170 | public static byte[] base64ToByteCode(String bs) {
171 | byte[] value = null;
172 |
173 | Class base64;
174 | try {
175 | base64 = Class.forName("java.util.Base64");
176 | Object decoder = base64.getMethod("getDecoder", (Class[])null).invoke(base64, (Object[])null);
177 | value = (byte[])((byte[])decoder.getClass().getMethod("decode", String.class).invoke(decoder, bs));
178 | } catch (Exception var6) {
179 | try {
180 | base64 = Class.forName("sun.misc.BASE64Decoder");
181 | Object decoder = base64.newInstance();
182 | value = (byte[])((byte[])decoder.getClass().getMethod("decodeBuffer", String.class).invoke(decoder, bs));
183 | } catch (Exception var5) {
184 | }
185 | }
186 |
187 | return value;
188 | }
189 |
190 | public static void exportToYaml() throws IOException {
191 | Map yamlData = new LinkedHashMap<>();
192 | List