├── .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 | 9 | 10 | 14 | 15 | 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 | 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 | ![image-20250131152949132](assets/image-20250131152949132.png) 32 | 33 | ![image-20250131153024127](assets/image-20250131153024127.png) 34 | 35 | #### 选择匹配模式 36 | 37 | 不同匹配模式仅针对 Path。 38 | 39 | ##### 精确匹配 40 | 41 | 选择精确匹配模式时,不支持 `启用URL编码`、`检查完整数据包`。 42 | 43 | 精确匹配仅匹配 API,不匹配 GET 请求参数,且需要 API 完全匹配。 44 | 45 | 导入如下内容。 46 | 47 | ![image-20250131153251402](assets/image-20250131153251402.png) 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 | ![image-20250131143303914](assets/image-20250131143303914.png) 54 | 55 | ##### 半模糊匹配 56 | 57 | 选择半模糊匹配模式时,不支持 `启用URL编码`、`检查完整数据包`。 58 | 59 | 半模糊匹配仅匹配 API,不匹配 GET 请求参数,但支持匹配不完全相同 API。 60 | 61 | 导入如下内容。 62 | 63 | ![image-20250131153522783](assets/image-20250131153522783.png) 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 | ![image-20250131143734141](assets/image-20250131143734141.png) 70 | 71 | ##### 模糊匹配 72 | 73 | 选择模糊匹配模式时,支持 `启用URL编码`、`检查完整数据包`。 74 | 75 | 模糊匹配在默认情况下,匹配 `Path + 参数`。 76 | 77 | 导入如下内容。 78 | 79 | ![image-20250131153624442](assets/image-20250131153624442.png) 80 | 81 | ###### 解析 PathVariable 82 | 83 | 切换到模糊匹配模式时,会弹出窗口,选择是否解析 PathVariable。选择 `是` 则解析,选择 `否` 则不解析。 84 | 85 | 当解析 PathVariable 时,此时可匹配接口 `/test/user/abc/infomation` 与参数 `/test/user/abc/infoamtion`,`/test/user/{name}/infomation`。 86 | 87 | ![image-20250131151601732](assets/image-20250131151601732.png) 88 | 89 | 当选择不解析 PathVariable 时,此时无法匹配接口 `/test/user/abc/infoamtion` 与参数 `/test/user/abc/infoamtion`,仅可匹配参数 `/test/user/{name}/infomation`。 90 | 91 | ![image-20250131151831909](assets/image-20250131151831909.png) 92 | 93 | ###### 启用 URL 编码 94 | 95 | 当未勾选 `启用URL解码` 时,此时无法匹配参数中经过 URL 编码的 `a b c d e f g`。 96 | 97 | ![image-20250131153719159](assets/image-20250131153719159.png) 98 | 99 | ![image-20250131152224779](assets/image-20250131152224779.png) 100 | 101 | 勾选 `启用URL解码`,此时会对 request 进行 URL 解码,此时可匹配参数中经过 URL 编码的 `a b c d e f g`。 102 | 103 | ![image-20250131153838072](assets/image-20250131153838072.png) 104 | 105 | ![image-20250131153912482](assets/image-20250131153912482.png) 106 | 107 | ###### 检查完整数据包 108 | 109 | 当未勾选 `检查完整数据包` 时,此时仅检查请求 `Path + 参数`,未检查数据包中其他内容。 110 | 111 | 此时无法匹配请求体中的 `a b c d e f g` 与 `xxx`。 112 | 113 | ![image-20250131155246057](assets/image-20250131155246057.png) 114 | 115 | 勾选 `检查完整数据包时` 时,此时将检查整个数据包,此时可匹配 `a b c d e f g`,`xxx`。 116 | 117 | ![image-20250131155558419](assets/image-20250131155558419.png) 118 | 119 | ![image-20250131155745214](assets/image-20250131155745214.png) 120 | 121 | 该功能可与 `启用URL解码` 同时开启,可匹配完整请求中被 URL 编码的数据。 122 | 123 | ![image-20250131160031773](assets/image-20250131160031773.png) 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 | ![image-20250131201354108](assets/image-20250131201354108.png) 142 | 143 | ![image-20250131201535978](assets/image-20250131201535978.png) 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 | ![image-20250131203231727](assets/image-20250131203231727.png) 173 | 174 | ![image-20250131203259330](assets/image-20250131203259330.png) 175 | 176 | ##### 条件查找 177 | 178 | 按条件信息查找,如 `method=get`,`path=/service`,`result=xxx`,`state=true` 等。 179 | 180 | 不支持多条件搜索,不支持模糊搜索。 181 | 182 | ![image-20250131204156562](assets/image-20250131204156562.png) 183 | 184 | ![image-20250131204216952](assets/image-20250131204216952.png) 185 | 186 | ![image-20250131204256345](assets/image-20250131204256345.png) 187 | 188 | ### 敏感信息检查 189 | 190 | 目前采用 HaE 部分敏感信息规则进行检查。 191 | 192 | 首次安装插件时,会在当前用户目录下创建配置文件夹。 193 | 194 | ![image-20250203170903647](assets/image-20250203170903647.png) 195 | 196 | #### 开启功能 197 | 198 | 开启敏感信息检查功能必须先导入 API,该功能仅对 API 列表中匹配的记录进行检查。 199 | 200 | ![image-20250203214020393](assets/image-20250203214020393.png) 201 | 202 | 导入 API 后,在 `Sensitive Info` 标签页勾选开启敏感信息检查。该勾选状态默认不勾选,状态不保存。 203 | 204 | 初次启用功能由于配置文件不存在,会询问是否使用默认规则,选择是即可自动创建规则文件。 205 | 206 | ![image-20250203214446338](assets/image-20250203214446338.png) 207 | 208 | 插件自带规则均来自 HaE 插件部分敏感信息规则。 209 | 210 | ![image-20250203214514020](assets/image-20250203214514020.png) 211 | 212 | #### 编辑规则 213 | 214 | 所有修改均同步本地配置文件。 215 | 216 | ##### 添加规则 217 | 218 | ![image-20250203230445654](assets/image-20250203230445654.png) 219 | 220 | ![image-20250203230544618](assets/image-20250203230544618.png) 221 | 222 | ##### 修改规则 223 | 224 | ![image-20250203230640616](assets/image-20250203230640616.png) 225 | 226 | ![image-20250203230657728](assets/image-20250203230657728.png) 227 | 228 | ![image-20250203230720331](assets/image-20250203230720331.png) 229 | 230 | ##### 删除规则 231 | 232 | 支持选中多条规则同时删除。 233 | 234 | ![image-20250203231321030](assets/image-20250203231321030.png) 235 | 236 | ![image-20250203231338677](assets/image-20250203231338677.png) 237 | 238 | ##### 切换规则启用状态 239 | 240 | 支持选中多条规则同时切换状态,`true=启用`,`false=未启用`。 241 | 242 | ![image-20250203231607512](assets/image-20250203231607512.png) 243 | 244 | ![image-20250203231625954](assets/image-20250203231625954.png) 245 | 246 | #### 功能效果 247 | 248 | 开启敏感信息检查后,当 API 列表中匹配到敏感信息时,`history` 中标记为 `橙色`,同时列出匹配到的字段信息。 249 | 250 | ![image-20250204203345613](assets/image-20250204203345613.png) 251 | 252 | 同时 API 列表中 `Result` 字段提示 `存在敏感信息`。 253 | 254 | ![image-20250203232232994](assets/image-20250203232232994.png) 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> ruleList = new ArrayList<>(); 193 | 194 | for (RuleItem ruleItem : SensitiveInfoConfig.RULE_LIST) { 195 | Map ruleItemMap = new LinkedHashMap<>(); 196 | ruleItemMap.put("name", ruleItem.getName()); 197 | ruleItemMap.put("loaded", ruleItem.getLoaded()); 198 | ruleItemMap.put("regex", ruleItem.getRegex()); 199 | ruleItemMap.put("scope", ruleItem.getScope()); 200 | ruleList.add(ruleItemMap); 201 | } 202 | 203 | yamlData.put("rules", ruleList); 204 | 205 | // 配置YAML选项(保持块格式) 206 | DumperOptions options = new DumperOptions(); 207 | options.setDefaultFlowStyle(DumperOptions.FlowStyle.BLOCK); 208 | options.setIndent(2); 209 | options.setPrettyFlow(true); 210 | 211 | // 写入文件 212 | Yaml yaml = new Yaml(options); 213 | try (FileWriter writer = new FileWriter(SensitiveInfoConfig.RULE_CONFIG_FILE)) { 214 | yaml.dump(yamlData, writer); 215 | } 216 | 217 | } 218 | } 219 | --------------------------------------------------------------------------------