Java 审计和 PHP 最大的不同,是它的调用链又长又绕:一个用户输入可能穿过 Controller、Service、多个 Util、DAO 才落地,中间还夹着一堆框架和依赖。纯靠肉眼一层层点进去追,几天都追不完一条链。所以 Java 审计对工具的依赖更重——好的工具能把”追链""挖链""查组件”这些体力活自动化,让你把精力集中在真正需要判断的地方。这一篇把 Java 审计的工具矩阵讲清楚。
本文所有工具仅用于你对自有或已授权的 Java 代码做安全评估,切勿用于未授权目标。
工具矩阵:先有全局观
Java 审计工具比 PHP 更丰富,先按用途分好类,你才不会用错场景:
- 手工审计核心:IDEA(IntelliJ IDEA),追链、搜索、调试的主战场。
- 语义化静态分析:CodeQL,把代码变成数据库、用查询语言批量挖漏洞。
- 字节码级扫描:SpotBugs + Find Security Bugs 插件。
- 自动挖利用链:Tabby、gadgetinspector,专门找反序列化 gadget chain。
- 组件依赖扫描:OWASP Dependency-Check、Snyk、Dependency-Track。
- 反编译器:JADX、CFR、Procyon、Fernflower,无源码时把 class/jar 还原成代码。
- 动态诊断:Arthas,线上不停机看方法调用、参数、返回值。
这套矩阵的核心思路是:手工审为主(IDEA),语义查询和自动挖链为辅(CodeQL/Tabby),组件扫描兜底(Dependency-Check),无源码时靠反编译,线上问题靠 Arthas。
IDEA:Java 审计的绝对核心
不管有多少花哨工具,IDEA 始终是 Java 审计的主战场,因为 Java 是强类型、编译型语言,IDE 的语义能力远比 PHP 那边强。审计时你要把这几个快捷键练成肌肉记忆:
- 全局搜索(
Ctrl+Shift+F):搜危险字符串,如Runtime.getRuntime().exec、readObject、getParameter。 - 搜类(
Ctrl+N)、搜文件(Ctrl+Shift+N):快速定位 Controller、配置类、拦截器。 - 跳转定义(
Ctrl+B):从调用点跳到方法实现,正向追链。 - 找实现(
Ctrl+Alt+B):接口有多个实现类时,看真正跑的是哪个。 - 找调用处(
Find Usages,Alt+F7):从危险方法反向回溯谁调用了它。 - 调用层次(
Call Hierarchy,Ctrl+Alt+H):直接看一个方法的完整上下游调用树,追链神器。
配合 IDEA 内嵌的 Tomcat 和断点调试,你能清楚看到请求从 Controller 一路走到 DAO,参数在每一层变成了什么。可以说,八成的 Java 审计工作,都是在 IDEA 里”跳定义 + 找调用 + 下断点”这三件事里完成的。
CodeQL:把找漏洞变成写查询
当项目大到人工看不过来,就该请出 CodeQL。它是 GitHub 出品的语义化代码分析引擎,官方原生支持 Java。它的工作方式很特别:
- 先把源码编译成一个数据库,这个数据库完整记录了代码的语法树、数据流、控制流。
- 你用类似 SQL 的 QL 查询语言去描述”危险模式”。
比如你想找所有命令执行漏洞,可以写一条查询:“所有 Runtime.exec 的调用,其参数能从 request.getParameter 这类污点源经数据流追溯过来,且中途没有经过校验”。CodeQL 会在整个代码库里帮你把符合这个模式的路径全部找出来。
CodeQL 的强大在于污点分析(taint tracking):它真正理解数据是怎么在代码里流动的,能跨方法、跨类追踪 source 到 sink 的完整路径,误报比关键字匹配低得多。官方还维护了一大批现成的安全查询(SQL 注入、路径穿越、SSRF、反序列化等),你直接跑就能出结果。缺点是学习曲线陡、需要能成功编译项目、大项目建库慢。但一旦学会,它是批量、规则化挖同类漏洞的利器。此外,Semgrep 也支持 Java,规则更轻量、上手更快,适合和 CodeQL 搭配用。
SpotBugs + Find Security Bugs:字节码级扫描
SpotBugs(FindBugs 的继任者)是老牌的 Java 静态分析工具,它分析的是编译后的字节码而非源码。装上 Find Security Bugs 插件后,它能识别一百多种安全漏洞模式:SQL 注入、命令注入、XXE、弱加密、硬编码密钥、路径穿越等。
它的好处是接入简单——可以作为 Maven/Gradle 插件跑,也能接进 CI,每次构建自动扫。因为基于字节码,即使没有完整源码只有 jar 包也能分析。定位是”快速粗筛 + 持续集成守门”,配合 CodeQL 的深度分析形成互补。
Tabby 与 gadgetinspector:自动挖反序列化链
Java 反序列化漏洞的难点,是要在庞大的 classpath 里找出一条能”串起来执行命令”的 gadget chain(利用链)。人工找链极其烧脑,于是有了专门的自动挖链工具:
- Tabby:它把 Java 字节码分析后构建成方法调用图,存进 Neo4j 图数据库,然后你用图查询语言(Cypher)去搜”从某个反序列化入口能不能走到
Runtime.exec”这样的路径。它把”找链”变成了”图上找路径”,特别适合在大型项目或复杂依赖里挖新链、验证已知链是否可达。 - gadgetinspector:一个自动化的 gadget chain 发现工具,它静态分析 jar 包,尝试自动推断出可能的反序列化利用链,帮你在陌生依赖里快速定位潜在的危险链条。
这类工具体现了 Java 审计的一个特点:很多漏洞不在你的业务代码,而在依赖库的类之间的组合里。人工几乎不可能穷举这些组合,必须靠图分析和自动推断。
组件依赖扫描:一半的洞在这里
前面反复强调,Java 项目的漏洞一大半在第三方依赖里。专门扫依赖 CVE 的工具是必备项:
- OWASP Dependency-Check:开源,扫描
pom.xml/build.gradle里的组件,对照 NVD 漏洞库列出带已知 CVE 的依赖,能接 Maven/Gradle/CI。 - Snyk:商业为主(有免费额度),除了扫依赖 CVE,还能给修复建议、监控新披露的漏洞。
- Dependency-Track:一个持续的组件风险管理平台,基于 SBOM(软件物料清单)持续监控你所有项目的依赖风险。
审计时先跑一遍依赖扫描,把 fastjson、log4j-core、shiro、commons-collections 这些经典高危组件的版本对一遍,往往能低成本收获一批高危漏洞。别忘了间接依赖——A 依赖 B、B 依赖 C,出洞的常常是最底层的 C,IDEA 的依赖树或这些工具都能展开看。
反编译器:没有源码怎么办
审计的对象不总是有源码。拿到的可能是编译好的 .jar、.war 或单个 .class。这时需要反编译器把字节码还原成可读的 Java 代码:
- JADX:最常用之一,界面友好,还能直接反编译安卓 APK 里的 Java 代码,搜索、跳转都方便。
- CFR、Procyon、Fernflower:几款优秀的 Java 反编译引擎,对新语法、Lambda、泛型的还原度各有优劣,反编译效果不理想时可以换一个试试。
反编译后的代码可能变量名丢失、结构略乱,但足够你审逻辑和找危险调用。审闭源组件、分析可疑 jar 时,反编译器是必备。
Arthas:线上动态诊断
有些问题在测试环境复现不出来,或者你需要看正在运行的生产系统里方法到底怎么走。阿里开源的 Arthas 是 Java 线上诊断利器,无需重启应用就能:
watch某个方法的入参、返回值、异常,看用户传的参数到底长什么样。trace一次调用的完整链路和耗时,确认请求真实走过哪些方法。jad直接反编译线上正在运行的类,确认线上跑的代码和你手里的源码是不是一致。
Arthas 的价值在于”动态求证”:静态分析怀疑某处有洞,但吃不准运行时行为,用 Arthas 挂上去看真实数据,比反复猜靠谱得多。它是 Java 版的”Xdebug 加强版”,尤其在线上排查时无可替代。
一条能落地的 Java 审计工具流水线
把工具串成流程:
- 摸底:IDEA 导入项目,先读
pom.xml/application.yml,认清依赖、目录结构、入口与拦截器。 - 组件扫描:跑 Dependency-Check/Snyk,把带 CVE 的依赖版本先揪出来,对照经典高危组件。
- 静态粗筛:SpotBugs+FindSecBugs 快扫一遍,或用 Semgrep 跑安全规则,导出可疑清单。
- 深度分析:项目大就上 CodeQL 建库写查询,批量挖 SQL 注入、SSRF、反序列化等同类漏洞。
- 手工追链:在 IDEA 里对可疑点用跳定义、找调用、调用层次追完整链路,判断可控性与过滤。
- 挖利用链:怀疑反序列化时,用 Tabby/gadgetinspector 找可达的 gadget chain。
- 无源码时:用 JADX/CFR 反编译闭源组件或可疑 jar 再审。
- 动态求证:本地断点调试,或线上用 Arthas watch/trace 坐实运行时行为。
用工具的心法(Java 版)
Java 工具虽多,用法上和 PHP 一脉相承,但有几点要特别强调。
第一,别被工具的产出量吓退,也别被它的”没报”骗了。 CodeQL、SpotBugs 会报出大量结果,很多是误报;同时它们也一定会漏——尤其是靠框架特性、注解、反射触发的路径。工具产出是起点不是终点,人工判断和追链才是核心。
第二,组件扫描一定要做,而且要趁早做。 Java 漏洞一半在依赖里,这是投入产出比最高的一步。拿到项目第一件事就是扫依赖,往往还没开始审业务代码就先收获几个高危。
第三,静态、动态、图分析要三管齐下。 静态(CodeQL/IDEA)负责覆盖面,动态(断点/Arthas)负责确定性,图分析(Tabby)负责搞定人工搞不定的利用链组合。三者互补,才既全面又扎实。工具是把你的判断力放大,而不是替代——见过的真实调用链越多,你用工具的手感就越准。
这一篇你该记住的
- IDEA 是 Java 审计绝对核心:全局搜索、跳定义、找调用、调用层次、断点调试,八成工作在这里完成。
- CodeQL 把代码变数据库、用查询做污点分析,适合批量挖同类漏洞;Semgrep 更轻量可搭配。
- SpotBugs + Find Security Bugs 做字节码级快扫,易接 CI;Tabby/gadgetinspector 自动挖反序列化 gadget chain。
- Dependency-Check/Snyk 扫依赖 CVE 是投入产出比最高的一步,Java 漏洞一半在组件里,务必趁早做。
- 无源码用 JADX/CFR 反编译;线上动态求证用 Arthas 的 watch/trace/jad。
- 工具放大判断力但不替代判断:静态覆盖面 + 动态确定性 + 图分析挖链,三管齐下。
下一篇是代码审计系列的收尾:怎么把这些工具跑出来、手工追出来的发现,写成一份开发看得懂、老板看得明的审计报告,并给出真正能落地的修复建议。