网站首页 > 技术文章 正文
在当今的云原生环境中,保护 Java 应用程序不仅涉及我们编写的代码,还涉及整个容器堆栈。虽然 Java 一直保持着强大的安全记录,但Log4Shell等事件向我们表明,保持警惕至关重要。我们需要一种全面的方法来预防漏洞,从 Java JRE 基础容器映像到我们的 Java 应用程序依赖项以及应用程序代码本身。
去年,我与一位客户合作,他抱怨他们的 Node.js 容器基础镜像存在漏洞。这促使我对基础镜像(包括 Java)进行了更多研究。
Java 容器镜像现状
我使用开源grype漏洞扫描程序调查了流行的基于 Java 容器的镜像。结果令人大开眼界:
- 几乎所有基础镜像(包括来自主要提供商的基础镜像)都包含多个漏洞
- 漏洞数量从几个到几百个不等!
- 只有一个基础镜像没有漏洞:Chainguard 的 JRE 基础镜像
以下是截至 2025 年 2 月 7 日的调查结果:
JRE 映像 | 漏洞 | 图像大小(未压缩) |
| 5 严重 | 331MB |
bitnami/java:最新 | 3 严重 | 629MB |
openjdk:23-slim(已弃用) | 3 严重 | 468MB |
| 1 严重 | 202MB |
openjdk:latest(已弃用) | 0 严重 | 487MB |
ibm-semeru-runtimes:open-23-jre | 25 中 | 282MB |
eclipse-temurin:最新 | 43 中 | 478MB |
日食-temurin:23-jre-alpine | 7 中 | 205MB |
| 5 中等 | 686MB |
| 2 中等 | 149MB |
amazoncorretto:最新 | 2 中等 | 366MB |
amazoncorretto:23-alpine | 2 中等 | 366MB |
chainguard/jre:最新 | 0 | 226MB |
鉴于Chainguard Java JRE 映像是唯一没有漏洞的映像,您可能不得不尝试一下。最新标记是免费的,但特定 Java 版本的其他标记需要 Chainguard 订阅。但是,如果您可以运行最新版本的 Java JRE(目前为 23),则此映像是一个绝佳的选择。
如果您想要针对特定版本的 Java,并且您的组织不使用 Chainguard,我推荐 Amazon Corretto。我已经使用 Corretto 两年多了,没有出现任何问题,而且他们的镜像非常稳定,漏洞很少。Corretto 可以像 Chainguard 一样作为基础镜像进行替换,如本指南所示。
Java 容器构建选项
要为 Java 应用程序打包容器映像,有几个选项,包括:
- 传统的 Dockerfile:虽然简单,但这种方法通常会导致图像分层效率低下,并且需要 Docker(或同等)守护程序进行构建。
- 云原生 Buildpacks:Buildpack 集成提供了一条便捷的路径,但无法轻松定制基础镜像。
- Google 的 Jib:一个精简的插件,提供无守护进程构建、高效分层和基础图像灵活性。
对于我在 GitHub 上提供的Java(Spring Boot)演示应用程序,Jib 是首选的容器构建方法,但也提供了Dockerfile作为替代方案。如果您想了解 Jib 的图像分层工作原理,请参阅我的演示应用程序的README,了解如何使用dive检查容器图像的各层。
构建零漏洞容器镜像
使用 Chainguard 的 JRE 基础映像和 Google 的 Jib Maven 插件,让我们构建一个零漏洞的 Java 应用程序容器。如果您使用 Gradle,Jib Gradle 插件的工作方式与 Maven 插件类似。
1. 在 Maven 项目中配置 Jib
要将基础镜像更改为 Chainguard JRE 镜像,请将以下Jib Maven 插件配置添加到您的pom.xml中,就像在演示应用程序中所做的那样:
1 2 3 4 | … |
如果您不想使用 Jib,我们可以提供一个使用 Chainguard 的 JRE 基础镜像的示例Dockerfile 。
2. 构建容器镜像
运行以下 Maven Jib 命令为演示应用程序构建本地容器映像(需要 Docker):
1 | ./mvnw jib:dockerBuild |
如果使用Dockerfile而不是 Jib,请参阅演示应用程序的README以获取有关如何使用docker build构建容器映像的进一步说明。
3. 验证零漏洞
现在,图像已构建,您可以使用grype扫描本地机器上新构建的图像:
1 | grype docker.io/your-id/your-image:latest |
随着最新的Chainguard 基础镜像和所有 Maven 依赖项的更新,您应该看到以下结果:No vulnerabilities found
1 2 3 4 5 6 7 8 9 10 11 | Loaded image docker.io/your-id/your-image:latest Parsed image sha256:18f64293e66f391c41e7363c989687b852203e0fb9c32744f0c5d7b80a0e7f79 Cataloged contents 0b944452baefa268f36e01336d79d0fb1fc35f13bef0c11c262d3ef2c9e46d06 ├── Packages [74 packages] ├── File digests [1,186 files] ├── File metadata [1,186 locations] └── Executables [121 executables] Scanned for vulnerabilities [0 vulnerability matches] ├── by severity: 0 critical, 0 high, 0 medium, 0 low, 0 negligible └── by status: 0 fixed, 0 not-fixed, 0 ignored No vulnerabilities found |
使用 SBOM 主动检测漏洞
您无需等到容器构建完成后再进行操作,而是可以在开发周期的早期通过生成和扫描软件物料清单 (SBOM) 来发现漏洞。此 SBOM 以标准化 JSON 格式捕获应用程序的所有依赖项,可以使用grype等常用扫描工具读取。
CycloneDX 提供了一个Maven 插件(或Gradle 插件),用于根据应用程序的依赖关系树构建 SBOM。将以下插件添加到您的pom.xml中:
1 2 3 4 |
现在,你可以在容器化之前使用grype 扫描你的应用程序依赖项:
1 2 3 4 5 6 7 8 9 | grype target/classes/META-INF/sbom/application.cdx.json Scanned for vulnerabilities [4 vulnerability matches] ├── by severity: 0 critical, 2 high, 1 medium, 1 low, 0 negligible └── by status: 4 fixed, 0 not-fixed, 0 ignored NAME INSTALLED FIXED-IN TYPE VULNERABILITY SEVERITY logback-core 1.5.12 1.5.13 java-archive GHSA-pr98-23f8-jwxv Medium logback-core 1.5.12 1.5.13 java-archive GHSA-6v67-2wr5-gvf4 Low tomcat-embed-core 10.1.33 10.1.34 java-archive GHSA-5j33-cvvr-w245 High tomcat-embed-core 10.1.33 10.1.34 java-archive GHSA-27hp-xhwr-wr2m High |
如您在本例中看到的,SBOM 和grype在 Spring Boot 3.4.0 中发现了一个过时的 Tomcat 版本,其中有两个高漏洞。SBOM 方法的妙处在于,您可以标准化单个漏洞扫描工具(如grype)来扫描 SBOM 和镜像。通常,对于 Java,漏洞检查工具与容器镜像扫描工具是分开的,因此合并到单个漏洞扫描工具可能会有所帮助。
结论
虽然 Chainguard 目前提供唯一零漏洞的 Java 基础镜像,但其他镜像提供商正在努力减少漏洞数量。然而,仍然需要全面的安全策略,其中包括:
- 仔细选择基础图像
- 定期对容器镜像进行漏洞扫描
- SBOM 生成和扫描
- 自动依赖更新流程(即Dependabot)
通过遵循这些做法并使用现代工具,您可以构建和维护启动和保持安全的容器化 Java 应用程序。随时了解新的漏洞,更新依赖项,并定期检查您的安全状况,以保持 Java 应用程序的强大安全态势。
猜你喜欢
- 2025-03-20 轻松掌握如何用Dockerfile将java应用构建成镜像知识点
- 2025-03-20 实战:docker-jenkins(实战2对2)
- 2025-03-20 无需 Dockerfile,一条命令即可轻松快速地构建 Docker 镜像
- 2025-03-20 5 分钟,教你用 Docker 部署一个 Python 应用
- 2025-03-20 Dockerfile: ADD vs COPY(Dockerfile: ADD vs copy ai)
- 2025-03-20 你了解Docker吗?(dockerone)
- 2025-03-20 DockerFile镜像定制(docker镜像制作)
- 2025-03-20 Docker镜像优化:从1.16GB到22.4MB
- 2025-03-20 Docker 四种制作镜像方式(docker制作镜像经典案例)
- 2025-03-20 Dockerfile 最佳实践:构建高效镜像的专业指南
- 最近发表
- 标签列表
-
- cmd/c (57)
- c++中::是什么意思 (57)
- sqlset (59)
- ps可以打开pdf格式吗 (58)
- phprequire_once (61)
- localstorage.removeitem (74)
- routermode (59)
- vector线程安全吗 (70)
- & (66)
- java (73)
- org.redisson (64)
- log.warn (60)
- cannotinstantiatethetype (62)
- js数组插入 (83)
- resttemplateokhttp (59)
- gormwherein (64)
- linux删除一个文件夹 (65)
- mac安装java (72)
- reader.onload (61)
- outofmemoryerror是什么意思 (64)
- flask文件上传 (63)
- eacces (67)
- 查看mysql是否启动 (70)
- java是值传递还是引用传递 (58)
- 无效的列索引 (74)