随着Java Web应用模块化、微服务化的程度越来越高,传统的单应用、单项目中的安全风险正逐渐转变为跨组件、跨应用、跨项目等复杂路径下的安全风险,传统白盒工具针对单项目的扫描无法覆盖这种类型的漏洞产生场景,包括:二方包、项目与二方包结合、项目与三方包结合、项目与项目通过API结合、项目与项目通过消息队列/数据库结合等众多细分场景。
笔者用白盒工具(CheckMarx、Coverity、内部自研白盒、CodeQL)在每个细分场景下都做了对比和测试,现有工具的检测效果都不理想,相比之下,CodeQL 基于编译时的数据流、控制流采集方案,效果优于其它工具,有望解决项目与二方包、项目与三方包结合的漏洞检测场景下的漏洞检测。
由于 CodeQL 强依赖于代码编译,如果只是对个别项目做代码审计,倒是可以配置环境、配置构建命令实现检测,但笔者的真实场景是在 CI/CD 的构建流程里做统一的安全控制。如果联合 CI/CD 部门做适配开发,将带来很大的人力成本,而且 CodeQL 的检测方案还无法解决全部细分场景的问题,所以笔者索性自己实现,即不需要额外的人力成本,又可以很灵活的测试、调试和变更,这感觉真香~
AST-Framework 产品的 sast-plugin 中增加了二方包、项目与二方包结合、项目与三方包结合 三种细分场景下的安全风险监测能力,使用 AST-Framework 的白盒扫描,并勾选☑️ “深度监测” 即可触发该能力,实现上述场景的漏洞检测。
白盒工具做二方包检测,遇到的挑战是什么?
该小节讨论的二方包,特指具有 API 接口,同时又作为组件引入至其它应用中的组件,比如:
spring-boot-starter-actuator
我们从应用中引入二方包的方式开始梳理,引入二方包的方式有两种:通过 Java 包管理工具( Maven、Gradle )拉取企业内部组件仓库、通过 classpath 直接引入运行环境中文件系统内的 Jar 包;其中,通过组件仓库引入的二方包又分为通过标准开发流程创建和非标创建两种。
根据二方包的引入方式可以看出,白盒只能覆盖走标准开发流程创建二方包的场景,针对非标创建二方包和直接引入文件系统内的二方包,无法直接检测。
解决方案
白盒无法有效检测二方包的原因包括流程未覆盖和能力未覆盖两类。针对流程未覆盖的情况,可以针对上述场景做针对性的解决方案,比如:在组件推送到组件库时,拉取 Jar 包做异步白盒检测、在测试环境中拉取 Java 应用启动时依赖的所有 Jar 包进行检测等,解决方案需要与企业内部的环境匹配才能达到最高的投入产出比,这里不过多论述,重点介绍如何解决能力未覆盖的问题。
大部分白盒应用都只支持源码级的检测,我们可以在白盒工具检测前,通过 sast-plugin 做 Jar 包反编译,还原 Jar 包为 Java 源代码,然后调用白盒工具,实现源码级的检测。反编译工具有很多,经过对比,最终选择了 IDEA 开源的 Java 反编译工具 fernflower。
调用 fernflower 对 jar 包进行反编译1
java -jar fernflower.jar <target jar> <source root path>
白盒做项目与二三方包联合检测、时,遇到的挑战是什么?
当我们做跨组件(本身也是跨项目的一种)检测时,遇到的挑战与白盒工具的实现方式和检测原理有很大的关系,主要分为以下两类:
- 传统白盒工具采用 AST 分析,然后把分析结果临时存储在内存、数据库等位置,然后在内存中进行污点链路的梳理,这种实现方式的挑战在于反编译二方包后,数据量激增,污点链路梳理时会放大 AST 分析时 路径爆炸 的缺点,同时需要 消耗大量内存资源。
- 基于 QL 的白盒工具,可以分别对项目、二方包进行 AST 解析并存入数据库或其它位置,然后在不同项目的结果上做关联查询,这部分的挑战在于,需要重新构建 AST 模型,添加不同项目的标识,模型的建立需要根据大量的场景进行抽象和验证。
跨项目API调用场景下,白盒检测遇到的挑战是什么?
笔者暂时无法解决传统白盒工具在跨项目 API 调用场景下的检测方案,只能在基于 QL 的白盒工具上,尝试一些解决方案。在基于 QL 的白盒工具里进行跨项目 API 调用场景下的漏洞检测时,核心点在于如何构建项目间的关联关系。
解决方案
关于跨项目的解决方案,欢迎大家带着自己的思考与笔者交流。也可以等 AST-Framework 产品发布后,直接体验效果。