
Java Audit Pipeline
- 12 installs
- 1.6k repo stars
- Updated July 19, 2026
- wgpsec/aboutsecurity
Helps with ai & agent building tasks during AI-assisted development.
About
java-audit-pipeline is a Claude Code skill for ai & agent building. It helps solo builders move faster with AI-assisted coding.
- java-audit-pipeline
- AI & Agent Building
- AI-coding skill
Java Audit Pipeline by the numbers
- 12 all-time installs (skills.sh)
- Ranked #11,618 of 16,546 AI & Agent Building skills by installs in the Skillselion catalog
- Data as of Aug 5, 2026 (Skillselion catalog sync)
npx skills add https://github.com/wgpsec/aboutsecurity --skill java-audit-pipelineAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 12 |
|---|---|
| repo stars | ★ 1.6k |
| Last updated | July 19, 2026 |
| Repository | wgpsec/aboutsecurity ↗ |
What it does
Helps with ai & agent building tasks during AI-assisted development.
Files
Java 白盒审计总方法论
白盒审计在源码层面发现漏洞,关注"代码为什么不安全"。发现漏洞后的实际利用技术(构造 payload、绕过 WAF、Gadget Chain 武器化)属于黑盒 exploit skill 范畴。Java 项目常以编译后的 .class / JAR / WAR 形式交付,需先完成反编译还原源码(详见 decompile-strategy.md)。
深入参考
- 证据合约系统与评分公式 → references/evidence-contract.md
- Java 危险函数分类速查 → references/sink-reference.md
- CFR 反编译策略 → references/decompile-strategy.md
---
审计 5 阶段概览
| 阶段 | 名称 | 核心任务 | 产出物 |
|---|---|---|---|
| P1 | 路由映射 | 解析所有入口点及其参数 | 路由清单 |
| P2 | 权限建模 | 分析认证/授权,标记裸露路由 | 权限矩阵 |
| P3 | 数据流追踪 | Source→Sink 完整路径追踪 | EVID_* 证据集 |
| P4 | 分类审计 | 按 Sink 类型深入检查 | 漏洞清单 |
| P5 | 报告组装 | 评分 + 利用链编排 | 审计报告 |
Phase 1: 路由映射与入口点识别
解析框架路由配置,建立完整的攻击面清单:
- Spring MVC:
@RequestMapping,@GetMapping,@PostMapping等组合注解,扫描所有@Controller/@RestController类 - Servlet:
web.xml中的<servlet-mapping>以及@WebServlet注解注册的 Servlet - JAX-RS:
@Path,@GET,@POST等注解,检查Application子类注册的资源 - Struts2:
struts.xml中的<action>映射和ActionMapping通配符规则 - WebService: CXF / Axis 的
@WebService端点和 WSDL 发布路径
产出: 路由清单,每条记录包含 URL 路径、Handler 方法签名、参数绑定方式(@RequestParam / @PathVariable / @RequestBody)、是否需认证。
Phase 2: 权限建模与认证审查
分析安全框架的过滤链配置,找出缺少认证保护的路由:
- Spring Security:
SecurityFilterChain/WebSecurityConfigurerAdapter中的antMatchers/requestMatchers规则 - Apache Shiro:
shiroFilterChainDefinition中的 URL-Filter 映射(anon / authc / perms) - 自定义拦截器:
HandlerInterceptor.preHandle()的注册范围和排除路径 - 检查 JWT / Session / OAuth2 Token 的签发与校验逻辑、密码存储方式(BCrypt / 明文)
Phase 3: 数据流追踪(Source → Sink)
每条潜在漏洞路径都要产出 EVID_* 证据点(详见 evidence-contract.md)。
三层分析法: 1. 面 — 全局关键字扫描: 搜索 Sink 函数(参考 sink-reference.md),快速定位危险代码区域 2. 线 — 逐行追踪变量流: 从 Sink 反向追溯到 Source,记录每一步的变量传递和过滤操作 3. 点 — 验证利用条件: 确认过滤是否可绕过、参数是否可控、执行路径是否可达
Java 特有关注点:
- 注解驱动的参数绑定(
@RequestParam自动 trim、@RequestBodyJSON 反序列化)隐式转换可能吞掉恶意输入或引入类型混淆 - AOP 切面(
@Around/@Before)可能在切面层执行全局过滤或日志记录,需确认切面是否生效 - 反射调用(
Method.invoke、Class.forName)会打断静态数据流追踪,需人工跟进 - 多态分派 — 接口/抽象类的实际实现类需逐一排查,不能仅看接口声明
当无法追踪到完整的 Source→Sink 路径时,只能标注为"待验证"。
Phase 4: 分类漏洞审计
按 Sink 类型分派到对应子 skill 进行深入审计:
- 注入类(SQL / CMD / LDAP / SpEL / OGNL / EL)
- 文件类(读取 / 上传 / 写入 / 路径穿越)
- 前端类(XSS / CSRF / 重定向)
- 序列化类(Java 原生反序列化 / FastJSON / Jackson / XXE)
- 认证配置类(越权 / 弱加密 / 信息泄露 / Actuator 暴露)
- 框架特定漏洞(已知 CVE、Spring / Struts2 / Shiro 配置缺陷)
Phase 5: 报告与利用链组装
严重度评分: Score = R * 0.40 + I * 0.35 + C * 0.25(R=可达性, I=影响范围, C=利用复杂度,各 0-3 分)
将同一目标上的多个漏洞组合为利用链(如: Actuator 信息泄露→Shiro 认证绕过→SpEL 注入→RCE)。
审计质量检查清单
- [ ] 所有公开路由均已纳入路由清单(含 Servlet / Filter 注册的隐式入口)
- [ ] 未认证路由已全部标记并优先审计
- [ ] 每个"已确认"漏洞都有完整的 EVID_* 证据链
- [ ] AOP 切面和全局 Filter 的实际覆盖范围已验证
- [ ] 反射调用和动态代理的数据流已人工跟进
- [ ] 框架版本及依赖组件版本已确认,已知 CVE 已交叉比对
- [ ] 漏洞评分使用了统一公式,等级划分一致
- [ ] 利用链可行性已在源码层面验证
CFR 反编译策略
Java 白盒审计的目标经常是编译后的 .class 文件、JAR 包或 WAR/EAR 部署包。反编译是审计的前置步骤,本文档提供系统化的反编译策略。
---
何时需要反编译
| 场景 | 说明 |
|---|---|
| 仅有 .class 文件 | 目标以编译后字节码交付,无源码 |
| 无源码的第三方 JAR | 需要审计依赖库中的危险调用或已知漏洞的实际实现 |
| Spring Boot fat JAR | BOOT-INF/classes 为业务代码,BOOT-INF/lib 为依赖 JAR |
| WAR 包 | WEB-INF/classes 为业务代码,WEB-INF/lib 为依赖 JAR |
| 混淆/加壳应用 | ProGuard / DashO 混淆后的代码,反编译可能失真但仍有审计价值 |
---
CFR 反编译器
CFR 是首选反编译器,对现代 Java(Lambda、Switch 表达式、Record 等)支持最好。
基本用法
单个 .class 文件:
java -jar cfr.jar Target.class单个 .class 文件输出到文件:
java -jar cfr.jar Target.class > Target.java整个 JAR 包反编译到目录:
java -jar cfr.jar app.jar --outputdir ./decompiled指定额外 classpath(解决依赖缺失警告):
java -jar cfr.jar app.jar --extraclasspath "lib/*" --outputdir ./decompiled常用选项
| 选项 | 说明 |
|---|---|
--outputdir <dir> | 输出目录,保持包路径结构 |
--extraclasspath <path> | 补充依赖 classpath,减少反编译错误 |
--decodelambdas true | 解码 Lambda 表达式(默认开启) |
--decodestringswitch true | 解码 String switch 语句 |
--removeboilerplate true | 移除编译器生成的样板代码 |
--silent true | 静默模式,仅输出反编译结果 |
--comments false | 不生成 CFR 注释 |
---
备选反编译器
Procyon
对泛型信息还原较好,某些场景下比 CFR 输出更可读:
java -jar procyon-decompiler.jar -o ./decompiled app.jarFernFlower(IntelliJ 内置)
IntelliJ IDEA 自带的反编译器,直接在 IDE 中打开 .class 文件即可查看。也可命令行使用:
java -jar fernflower.jar app.jar ./decompiled选择建议
| 反编译器 | 优势 | 劣势 |
|---|---|---|
| CFR | Lambda/现代语法最优,主动维护 | 极端混淆场景偶尔崩溃 |
| Procyon | 泛型还原好,注释保留 | 对 Java 11+ 语法支持稍弱 |
| FernFlower | IDE 集成方便,批量处理稳定 | 输出可读性略低于 CFR |
建议: 优先使用 CFR,CFR 输出异常时用 Procyon 补充,IDE 内快速浏览用 FernFlower。
---
Spring Boot fat JAR 解包策略
Spring Boot 的可执行 JAR 结构:
app.jar
├── META-INF/
│ └── MANIFEST.MF # Main-Class: JarLauncher, Start-Class: 实际主类
├── BOOT-INF/
│ ├── classes/ # 业务代码 .class 文件
│ └── lib/ # 依赖 JAR 包
└── org/springframework/boot/loader/ # Spring Boot Loader解包步骤
# 1. 解包 JAR
mkdir app-extracted && cd app-extracted
jar -xf ../app.jar
# 2. 反编译业务代码(优先审计)
java -jar cfr.jar BOOT-INF/classes --outputdir ./src-business
# 3. 按需反编译特定依赖(仅审计可疑依赖)
java -jar cfr.jar BOOT-INF/lib/suspicious-lib.jar --outputdir ./src-lib
# 4. 获取依赖清单用于 CVE 比对
ls BOOT-INF/lib/ > dependency-list.txtWAR 包解包
mkdir app-war && cd app-war
jar -xf ../app.war
# 业务代码在 WEB-INF/classes
java -jar cfr.jar WEB-INF/classes --outputdir ./src-business
# 依赖在 WEB-INF/lib
ls WEB-INF/lib/ > dependency-list.txt---
反编译产物的路由映射还原
反编译后需从 .java 源码中重建路由清单,重点关注:
注解保留
Java 编译器会将运行时可见注解(@Retention(RUNTIME))保留在 .class 文件中,CFR 能正确还原:
@RequestMapping,@GetMapping,@PostMapping等 Spring MVC 注解@WebServlet,@WebFilter等 Servlet 注解@Path,@GET,@POST等 JAX-RS 注解@PreAuthorize,@Secured等安全注解
参数名恢复
- 使用
-parameters编译的 .class 文件,CFR 可还原真实参数名 - 未使用
-parameters时,参数名显示为arg0,arg1等,但@RequestParam("name")注解中的值仍然可读 - Spring Boot 默认通过
spring-boot-maven-plugin保留参数名信息
路由还原检查清单
- [ ] 扫描所有
@Controller/@RestController类及其类级@RequestMapping - [ ] 拼接类级和方法级路径得到完整 URL
- [ ] 检查
web.xml或@WebServlet注册的 Servlet - [ ] 检查
FilterRegistrationBean或@WebFilter注册的 Filter 链 - [ ] 确认
application.properties/yml中的server.servlet.context-path前缀
---
注意事项
内部类
编译后内部类会生成独立的 .class 文件(如 Outer$Inner.class、Outer$1.class),CFR 通常能正确还原嵌套关系。匿名内部类(Outer$1.class)的还原可能不够直观,需对照外部类上下文理解。
Lambda 表达式
Java 8+ 的 Lambda 编译为 invokedynamic 指令和私有静态方法(lambda$methodName$0)。CFR 默认能将其还原为 Lambda 语法,但复杂的链式 Lambda(如 Stream API 多级操作)偶尔还原不完整,此时查看原始字节码中的 bootstrap method 有助于理解。
泛型擦除
Java 泛型在编译后被擦除为原始类型(List<String> → List),但泛型签名信息保留在 Signature 属性中。CFR 通常能还原泛型参数,但以下场景可能丢失:
- 局部变量的泛型类型(编译器未保留
LocalVariableTypeTable时) - 桥接方法(Bridge Method)— 编译器为泛型协变返回类型生成的合成方法,可能造成方法签名混淆
混淆代码
ProGuard 等混淆工具会重命名类/方法/字段为 a, b, c 等短名称:
- 反编译产物可读性大幅下降,但数据流追踪仍然有效
- 字符串常量不受混淆影响,可通过搜索 SQL 语句、URL 模式、日志信息等定位关键代码
- Spring 注解中的字符串值(如
@RequestMapping("/api/user"))不会被混淆 - 建议配合 mapping.txt(如果可获取)进行反混淆还原
证据合约系统
为什么需要证据合约
AI 进行源码审计时容易"看到危险函数就报漏洞",忽略上游过滤、参数可控性、路径可达性,导致大量误报。证据合约系统强制要求每个漏洞结论附带完整数据流证明。
核心原则: 没有从 Source 到 Sink 的完整证据链,就不能将漏洞标记为"已确认可利用"。
EVID_* 命名规则
格式: EVID_{漏洞类型}_{证据维度}。漏洞类型用大写缩写(SQL、CMD、XSS 等),证据维度描述该点证明的内容(EXEC_POINT=执行点、USER_PARAM=用户参数来源)。
各漏洞类型证据点定义
SQL 注入(SQL)
| 证据点 | 含义 |
|---|---|
EVID_SQL_EXEC_POINT | SQL 语句的实际执行位置(类:方法:行号 + 调用链) |
EVID_SQL_STRING_CONSTRUCTION | SQL 字符串的拼接/构造方式(字符串拼接 vs PreparedStatement vs MyBatis #{} vs ${}) |
EVID_SQL_USER_PARAM_TO_SQL_FRAGMENT | 用户输入进入 SQL 片段的完整路径(Controller 参数 → Service → DAO) |
命令注入(CMD)
| 证据点 | 含义 |
|---|---|
EVID_CMD_EXEC_POINT | 命令执行调用的位置(Runtime.exec / ProcessBuilder.start) |
EVID_CMD_COMMAND_STRING_CONSTRUCTION | 命令字符串/参数数组的拼接方式 |
EVID_CMD_USER_PARAM_TO_CMD_FRAGMENT | 用户输入进入命令参数的路径 |
SSRF
| 证据点 | 含义 |
|---|---|
EVID_SSRF_URL_NORMALIZATION | URL 的规范化/解析过程(是否经过 URL 类解析、是否存在重定向跟随) |
EVID_SSRF_FINAL_URL_HOST_PORT | 最终请求的目标主机和端口 |
EVID_SSRF_DNSIP_AND_INNER_BLOCK | DNS 解析结果及内网地址限制检查 |
文件操作(FILE)
| 证据点 | 含义 |
|---|---|
EVID_FILE_WRAPPER_PREFIX | 协议/路径前缀(file://、classpath:、jar: 等) |
EVID_FILE_RESOLVED_TARGET | 最终解析的文件路径(经过 Path.normalize / canonicalize 后) |
EVID_FILE_PATH_TRAVERSAL_CHECK | 路径穿越防护检查(是否过滤 ../、是否校验 canonical path) |
文件上传(UPLOAD)
| 证据点 | 含义 |
|---|---|
EVID_UPLOAD_DESTPATH | 上传文件的存储目标路径 |
EVID_UPLOAD_FILENAME_EXTENSION_PARSING_SANITIZE | 文件名和扩展名的解析与过滤逻辑(白名单/黑名单、Content-Type 校验) |
EVID_UPLOAD_ACCESSIBILITY_PROOF | 上传文件是否可被 Web 直接访问执行(静态资源映射、Servlet 容器解析规则) |
XSS
| 证据点 | 含义 |
|---|---|
EVID_XSS_OUTPUT_POINT | 输出到 HTML 的位置和上下文(JSP / Thymeleaf / FreeMarker 模板位置) |
EVID_XSS_USER_INPUT_INTO_OUTPUT | 用户输入到达输出点的路径 |
EVID_XSS_ESCAPE_OR_RAW_CONTROL | 转义/编码处理或 raw 输出控制(<c:out> vs <%= %>、th:text vs th:utext) |
反序列化(DESER)
| 证据点 | 含义 |
|---|---|
EVID_DESER_CALLSITE | 反序列化函数的调用位置(ObjectInputStream.readObject / JSON.parseObject / ObjectMapper.readValue) |
EVID_DESER_INPUT_SOURCE | 反序列化数据的来源(HTTP body / RMI / JMX / MQ 消息) |
EVID_DESER_OBJECT_TYPE_MAGIC_TRIGGER_CHAIN | 反序列化目标类型、魔术方法触发(readObject / readResolve / finalize)及可用 Gadget Chain |
XXE
| 证据点 | 含义 |
|---|---|
EVID_XXE_PARSER_CALL | XML 解析器的调用位置和类型(DocumentBuilderFactory / SAXParser / XMLInputFactory) |
EVID_XXE_INPUT_SOURCE | XML 数据的输入来源(用户上传 / API 请求体 / 配置文件) |
EVID_XXE_ENTITY_DOCTYPE_SAFETY_AND_ECHO | 外部实体/DTD 加载配置状态及解析结果是否回显 |
认证授权(AUTH)
| 证据点 | 含义 |
|---|---|
EVID_AUTH_PATH_PROTECTED_MATCH | 路由与安全规则的匹配关系(antMatchers 规则、Shiro URL 配置) |
EVID_AUTH_TOKEN_DECODE_JUDGMENT | Token/Session 的解码与校验逻辑(JWT 签名验证、Session 固定检查) |
EVID_AUTH_PERMISSION_CHECK_EXEC | 权限校验的实际执行(@PreAuthorize / hasRole / 自定义注解是否生效) |
表达式注入(EXPR)
| 证据点 | 含义 |
|---|---|
EVID_EXPR_EVAL_ENTRY | 表达式引擎的调用入口(SpEL ExpressionParser / OGNL ValueStack / EL ELProcessor) |
EVID_EXPR_EXPR_CONTROL | 用户输入对表达式内容的控制程度(完全可控 / 部分拼接 / 仅参数) |
EVID_EXPR_EXEC_CHAIN_ENTRY | 表达式执行到危险操作(Runtime.exec / ClassLoader)的调用链 |
其他类型简表
| 类型 | 证据点 |
|---|---|
| 重定向 (REDIR) | EVID_REDIR_TARGET_URL, EVID_REDIR_USER_INPUT_INTO_URL, EVID_REDIR_VALIDATION_CHECK |
| CSRF | EVID_CSRF_STATE_CHANGE_ACTION, EVID_CSRF_TOKEN_ABSENCE, EVID_CSRF_IMPACT_SCOPE |
| LDAP | EVID_LDAP_QUERY_CALL, EVID_LDAP_FILTER_CONSTRUCTION, EVID_LDAP_USER_INPUT_INTO_FILTER |
证据状态定义
| 标记 | 状态 | 含义 |
|---|---|---|
| ✅ | 已确认可利用 | Source→Sink 完整路径已追踪,过滤不充分或可绕过 |
| ⚠️ | 待验证 | 部分证据缺失(如无法确认过滤是否可绕过、反射调用打断追踪等) |
| 🔍 | 环境依赖 | 利用条件取决于运行环境(JDK 版本、容器配置、依赖版本) |
证据引用格式示例
完整 SQL 注入证据引用样例:
漏洞: SQL 注入 | 文件: com.example.dao.UserDAO | 严重度: High (Score: 2.55)
[EVID_SQL_EXEC_POINT]
位置: UserDAO.java:87 | 调用: jdbcTemplate.query(sql, ...)
[EVID_SQL_STRING_CONSTRUCTION]
位置: UserDAO.java:85-86
代码: String sql = "SELECT * FROM users WHERE id = '" + id + "'"
方式: 字符串直接拼接,未使用 PreparedStatement
[EVID_SQL_USER_PARAM_TO_SQL_FRAGMENT]
Source: UserController.java:23 — @RequestParam("id") String id
传递: UserController.getUser(id) → UserService.findById(id) → UserDAO.queryById(id) → sql 拼接
过滤: 无 | 结论: 用户输入直接拼入 SQL,可利用证据缺失处理规则
| 缺失情况 | 处理方式 | 标记状态 |
|---|---|---|
| Sink 存在但无法追溯 Source | 记录 Sink 位置,标注数据来源不明 | ⚠️ 待验证 |
| Source→Sink 路径中有反射/动态代理 | 记录已知部分,标注断点位置和反射目标 | ⚠️ 待验证 |
| 存在过滤但无法确认可否绕过 | 记录过滤逻辑,列出潜在绕过思路 | ⚠️ 待验证 |
| 完整路径已追踪且过滤不充分 | 提供全部 EVID_* 证据 | ✅ 已确认 |
| 完整路径已追踪且过滤充分 | 记录过滤方式,说明安全原因 | 安全 |
关键原则: "待验证"比"误报为已确认"的代价低得多。不确定时保守标记。
Java 特有: trace 不可用时的降级策略
当仅有 .class 文件、无法获得完整源码时,允许以下降级:
- 反编译产物(CFR / Procyon)可替代源码作为证据来源,但须标注"反编译还原"
- 反编译丢失的局部变量名不影响数据流追踪,以参数位置(arg0, arg1)替代
- Lambda 表达式和内部类反编译可能失真,此类路径上的证据降级为 ⚠️ 待验证
- 若关键 Sink 位于第三方 JAR 且无法反编译(混淆/加密),记录 JAR 名称和方法签名,标记为 🔍 环境依赖
严重度评分公式
三维度评分
可达性 R(Reachability, 0-3):
- 0 = 需管理员权限 + 特定配置才可触发
- 1 = 需普通用户认证后访问
- 2 = 未认证但需特定条件(特定 Content-Type、非默认路径)
- 3 = 未认证直接可达(公开接口、默认路径)
影响范围 I(Impact, 0-3):
- 0 = 非敏感信息泄露(版本号、路径)
- 1 = 敏感信息泄露(配置文件、数据库凭据、用户数据)
- 2 = 数据篡改 / 部分系统控制(SQL 写入、任意文件写入受限目录)
- 3 = RCE / 完全系统控制(命令执行、反序列化 Gadget Chain)
利用复杂度 C(Complexity, 0-3, 反向评分 — 越容易利用分越高):
- 0 = 需多步组合 + 竞态条件
- 1 = 需特定环境/版本 + 多步操作
- 2 = 简单构造 payload 即可利用
- 3 = 直接拼接 payload,无需额外条件
计算与映射
加权公式: Score = R * 0.40 + I * 0.35 + C * 0.25
CVSS 3.1 近似映射: CVSS ≈ Score / 3.0 * 10.0
| Score 范围 | CVSS 近似 | 等级 |
|---|---|---|
| 2.50 - 3.00 | 8.3 - 10.0 | Critical |
| 2.00 - 2.49 | 6.7 - 8.3 | High |
| 1.50 - 1.99 | 5.0 - 6.6 | Medium |
| < 1.50 | < 5.0 | Low |
Java 危险函数分类速查表
按漏洞类型分类,列出 Java 中常见的 Sink 函数及其审计要点。审计时以此表为索引进行全局关键字扫描,快速定位潜在漏洞代码区域。
---
SQL 注入(SQL)
Sink 函数: Statement.executeQuery, Statement.executeUpdate, Statement.execute, Connection.prepareStatement(拼接 SQL 时), MyBatis ${} 占位符, Hibernate Session.createQuery / Session.createSQLQuery(HQL/原生 SQL 拼接时), JPA @Query(nativeQuery=true 且拼接参数时), EntityManager.createNativeQuery, Spring JdbcTemplate.query/update(字符串拼接 SQL 时)
危险模式: 用户输入通过字符串拼接进入 SQL 语句。特别注意 MyBatis 的 ${} — 开发者常误以为 MyBatis 天然安全,但 ${} 是直接替换不做预编译;Hibernate HQL 拼接同样存在注入风险。ORDER BY、LIMIT、表名/列名等无法参数化的位置是高危区域。
安全验证: 是否使用 PreparedStatement 参数化绑定; MyBatis 是否使用 #{} 而非 ${}; JPA @Query 是否使用命名参数; 动态排序字段是否走白名单校验。
对应审计 skill: java-injection-audit
---
命令注入(CMD)
Sink 函数: Runtime.getRuntime().exec(), ProcessBuilder.command().start(), commons-exec: CommandLine / DefaultExecutor
危险模式: 用户输入拼入命令字符串或命令参数数组。Runtime.exec(String) 会经过 StringTokenizer 分割,与 Runtime.exec(String[]) 行为不同,可能影响注入方式。ProcessBuilder 使用数组参数时,各参数独立传递给 OS,shell 元字符注入难度增加但并非完全安全(参数本身可能被目标程序解释)。
安全验证: 命令和参数是否硬编码; 用户输入是否仅作为参数值(非命令本身); 是否存在白名单校验; 是否使用数组形式传参避免 shell 解释。
对应审计 skill: java-injection-audit
---
SSRF
Sink 函数: java.net.URL.openConnection, HttpURLConnection.connect, OkHttpClient.newCall().execute, Apache HttpClient: CloseableHttpClient.execute, Spring RestTemplate.getForObject / exchange, Spring WebClient.get().retrieve, java.net.Socket 直连
危险模式: 用户可控的 URL 被服务端发起请求。注意 URL.openConnection 支持 file://、jar://、netdoc:// 等协议; HTTP 客户端默认跟随 302 重定向可能绕过 host 校验。
安全验证: URL 白名单/黑名单验证; 是否限制了协议(仅 http/https); DNS Rebinding 防护(先解析 DNS 再校验 IP); 是否禁用了重定向跟随; 内网地址段(10/172.16/192.168/127)是否被阻断。
对应审计 skill: java-injection-audit
---
文件读取(FILE)
Sink 函数: FileInputStream, Files.readAllBytes / Files.readAllLines / Files.newInputStream, RandomAccessFile, ClassLoader.getResource / getResourceAsStream, java.nio.file.Path + Files.read*, new File().exists/length/lastModified(路径探测), ServletContext.getResourceAsStream
危险模式: 用户输入影响文件路径,可导致任意文件读取。Java NIO 的 Path.resolve 和 Path.normalize 行为需特别关注 — ../ 穿越在 normalize 后仍可能逃逸基准目录。ClassLoader.getResource 可被利用读取 classpath 下的敏感配置。
安全验证: 是否使用 canonical path 对比基准目录; Path.normalize() 后是否校验 startsWith(baseDir); 是否存在双重编码绕过(%2e%2e%2f); 文件名是否走白名单。
对应审计 skill: java-file-audit
---
文件上传(UPLOAD)
Sink 函数: MultipartFile.transferTo(), Part.write(), Files.copy(inputStream, targetPath), FileOutputStream.write(配合上传流)
危险模式: 用户上传的文件被存储到 Web 可访问目录且保留了可执行扩展名。Java 应用通常不像 PHP 那样直接执行上传文件,但 JSP/JSPX 文件上传到 webapp 目录下会被容器编译执行。
安全验证: 扩展名白名单还是黑名单(黑名单需覆盖 .jsp, .jspx, .jspf, .war); 存储目录是否在 webapp 根目录外; 是否使用随机文件名; 上传目录是否有容器解析 JSP 的配置; Content-Type 校验(可伪造但增加利用难度)。
对应审计 skill: java-file-audit
---
XSS
Sink 函数: JSP <%= expression %> / <% out.print() %>, JSTL 缺少 <c:out> 或 fn:escapeXml, Thymeleaf th:utext(不转义)vs th:text(自动转义), FreeMarker ${var?no_esc} / <#noescape>, Velocity $!{var}
危险模式: 用户输入未经 HTML 编码直接输出到页面。JSP 中 <%= %> 默认不转义; JSTL 的 ${param.name} 在 EL 表达式中直接输出也不转义; Thymeleaf 的 th:utext 明确跳过转义。
安全验证: JSP 是否使用 <c:out value=""> 或 fn:escapeXml(); Thymeleaf 是否使用 th:text 而非 th:utext; FreeMarker 全局 auto_escaping 配置; JavaScript 上下文中是否做了 JS 编码而非仅 HTML 编码; 全局 XSS Filter 的实际覆盖范围。
对应审计 skill: java-frontend-audit
---
XXE
Sink 函数: DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(), SAXParserFactory.newInstance().newSAXParser().parse(), XMLInputFactory.newInstance().createXMLStreamReader(), TransformerFactory.newInstance().newTransformer(), SchemaFactory.newInstance().newSchema(), XMLReader.parse(), Unmarshaller.unmarshal()(JAXB)
危险模式: 用户提交的 XML 数据被解析且未禁用外部实体和 DTD 加载。Java 的 XML 解析器默认配置大多不安全(允许外部实体),需显式禁用。
安全验证: 是否设置了 FEATURE_DISALLOW_DOCTYPE_DECL = true; 是否设置了 FEATURE_EXTERNAL_GENERAL_ENTITIES = false 和 FEATURE_EXTERNAL_PARAMETER_ENTITIES = false; XMLInputFactory 是否设置了 IS_SUPPORTING_EXTERNAL_ENTITIES = false 和 SUPPORT_DTD = false; 使用的 XML 库版本是否存在已知绕过。
对应审计 skill: java-serialization-audit
---
反序列化(DESER)
Sink 函数: ObjectInputStream.readObject() / readUnshared(), XMLDecoder.readObject(), FastJSON JSON.parseObject(str, Feature.SupportNonPublicField) / JSON.parse(autoType 未禁用时), Jackson ObjectMapper.enableDefaultTyping() / @JsonTypeInfo, Hessian HessianInput.readObject(), Kryo kryo.readObject()(无注册类限制时), XStream xstream.fromXML()
危险模式: 用户可控数据进入反序列化入口。Java 原生反序列化(ObjectInputStream)是最经典的 RCE 入口; FastJSON autoType 开启时可实例化任意类; Jackson enableDefaultTyping 同理; XMLDecoder 直接将 XML 映射为任意方法调用。
安全验证: ObjectInputStream 是否配置了 ObjectInputFilter(JDK 9+)或使用了 SerialKiller / contrast-rO0 等防护库; FastJSON 版本及 autoType 白名单/黑名单配置; Jackson 是否禁用了 DefaultTyping; 项目 classpath 中是否存在已知 Gadget Chain(Commons Collections / BeanUtils / C3P0 / JDK7u21 等)。
对应审计 skill: java-serialization-audit
---
表达式注入(EXPR)
Sink 函数: Spring SpEL ExpressionParser.parseExpression().getValue(), OGNL Ognl.getValue() / OgnlUtil.getValue()(Struts2), MVEL MVEL.eval(), EL 表达式 ELProcessor.eval() / ExpressionFactory.createValueExpression(), Groovy GroovyShell.evaluate() / GroovyClassLoader.parseClass()
危险模式: 用户输入被拼入表达式字符串并执行。SpEL 在 Spring 场景中极为常见(@Value 注解、Spring Security 表达式、Thymeleaf 预处理 __${expr}__); Struts2 的 OGNL 注入是历史上最高频的 RCE 入口之一。
安全验证: SpEL 是否使用了 SimpleEvaluationContext(安全)而非 StandardEvaluationContext(可 RCE); OGNL SecurityMemberAccess 配置; 表达式字符串是否硬编码; 用户输入是否仅作为表达式变量而非表达式本身。
对应审计 skill: java-injection-audit
---
重定向(REDIR)
Sink 函数: HttpServletResponse.sendRedirect(), Spring MVC return "redirect:" + url, RedirectView, ModelAndView("redirect:" + url), ResponseEntity.status(302).header("Location", url)
危险模式: 用户输入控制重定向目标 URL,可用于钓鱼攻击(Open Redirect)。在 OAuth2 / CAS 等认证流程中,开放重定向可升级为 Token/Code 窃取。
安全验证: 是否仅允许相对路径重定向; 是否有域名白名单; 是否检查了 URL scheme(防止 javascript: 协议); Spring Security 的 SavedRequestAwareAuthenticationSuccessHandler 是否限制了 targetUrl。
对应审计 skill: java-frontend-audit
---
LDAP 注入(LDAP)
Sink 函数: InitialDirContext.search(), SpringLdapTemplate.search(), DirContext.search(name, filter, controls)
危险模式: 用户输入拼入 LDAP 过滤器字符串(如 (&(uid={0})(userPassword={1}))),通过注入 *、)( 等字符修改查询逻辑。LDAP 认证绑定场景中,空密码可能导致匿名绑定成功。
安全验证: 是否使用参数化查询(SearchControls + filterArgs); 是否对 (, ), *, \, NUL 做了转义; Spring LDAP 的 LdapQueryBuilder 是否正确使用; ldap_bind 是否检查了空密码。
对应审计 skill: java-injection-audit