尊敬的各位技术同行,
欢迎来到本次关于“Software Bill of Materials (SBOM)”的讲座。在当今复杂的软件生态系统中,第三方依赖无处不在,它们极大地加速了开发进程,但也带来了前所未有的安全挑战。软件供应链攻击的威胁日益严峻,从 SolarWinds 事件到 Log4j 漏洞,都深刻提醒我们,仅仅关注自身代码的安全已远远不够。我们需要一种机制,能够清晰地了解我们软件中的每一个“零件”,并据此自动化地审计其潜在的安全风险。这正是 Software Bill of Materials (SBOM) 诞生的核心价值。
今天,我们将深入探讨 SBOM 的概念、其重要性、核心标准,并重点聚焦如何在 Go 项目的构建流程中,利用自动化工具生成 SBOM,并进而审计第三方依赖的安全风险。我们将通过大量的代码示例,一步步演示如何将这一关键实践融入您的开发与部署流程,从而显著提升您的软件供应链安全性。
I. 软件供应链安全的基石
软件开发不再是孤立的活动。现代应用程序通常由数千个组件构成,其中大部分来自开源项目、第三方库、框架,甚至是操作系统和容器基础镜像。这种高度依赖的生态系统,虽然带来了效率和创新,却也为攻击者提供了新的切入点——软件供应链。
A. 软件供应链攻击的崛起
软件供应链攻击的目标不再是最终产品本身,而是其生产、交付或更新过程中的任何环节。攻击者可能通过以下方式渗透:
- 篡改开源组件:向常用库中植入恶意代码。
- 窃取代码签名密钥:对恶意软件进行合法签名。
- 利用构建系统漏洞:在编译或打包过程中注入恶意内容。
- 破坏分发渠道:在软件交付给用户前进行修改。
一旦供应链中的某个环节被攻破,其影响将波及所有使用受影响组件或流程的下游产品。这种“一传十,十传百”的扩散效应,使得软件供应链安全成为当前网络安全领域最紧迫的议题之一。
B. SBOM 的诞生背景与核心价值
面对日益严峻的软件供应链威胁,企业、政府和行业组织都在寻求更有效的防御策略。SBOM 正是在这种背景下应运而生的一种基础性工具。
SBOM,即软件物料清单 (Software Bill of Materials),顾名思义,它就像制造业中的产品物料清单一样,提供了一个关于软件产品中包含的所有组件的完整、准确、机器可读的列表。这个列表不仅仅是直接依赖,还应尽可能地包含所有间接(传递性)依赖,甚至包括操作系统组件、编译器、构建工具等。
SBOM 的核心价值在于:
- 提高透明度:让软件供应商和消费者都能清晰地了解软件的构成。
- 加速漏洞响应:当新的漏洞(如 Log4j 漏洞)被披露时,能够迅速识别哪些产品受到了影响,并采取行动。
- 满足合规性要求:越来越多的法规和标准(例如美国总统行政命令 EO 14028)要求软件供应商提供 SBOM。
C. 本讲座目标
本次讲座旨在:
- 深入理解 SBOM 的概念、组成要素及重要性。
- 掌握主流 SBOM 标准(SPDX、CycloneDX)。
- 学习如何在 Go 项目中自动化生成高质量的 SBOM。
- 利用 SBOM 结合自动化工具,审计第三方依赖的安全漏洞。
- 将 SBOM 生成与审计流程无缝集成到 CI/CD 流水线中。
- 探讨 SBOM 的最佳实践与未来发展趋势。
通过本次讲座,我希望您能够将 SBOM 视为软件开发生命周期中的一个不可或缺的环节,从而构建更安全、更可信赖的 Go 应用程序。
II. 什么是软件物料清单 (SBOM)?
SBOM 是对软件组件及其之间关系的正式的、机器可读的清单。它提供了软件构成元素的“DNA”图谱,使您能够追踪和管理这些组件。
A. SBOM 的定义与组成要素
一个完整的 SBOM 通常包含以下关键信息:
- 组件名称 (Component Name):库、模块或包的名称。例如:
github.com/gin-gonic/gin。 - 组件版本 (Component Version):组件的特定版本标识。例如:
v1.7.7。 - 供应商 (Supplier):提供该组件的实体。例如:
Gin-Gonic或Google。 - 唯一标识符 (Unique Identifier):
- PURL (Package URL):一种通用的 URL 方案,用于唯一标识和定位软件包。例如:
pkg:golang/github.com/gin-gonic/[email protected]。 - CPE (Common Platform Enumeration):一种结构化的命名方案,用于识别 IT 系统、平台和软件包。
- SWID (Software Identification Tag):用于识别已安装软件的标签。
- PURL (Package URL):一种通用的 URL 方案,用于唯一标识和定位软件包。例如:
- 许可证信息 (License Information):组件使用的许可证类型。例如:
MIT,Apache-2.0,GPL-3.0。这虽然不是直接的安全信息,但对合规性至关重要,且有时许可证的变更也可能引入新的风险。 - 依赖关系 (Dependency Relationships):组件之间的父子关系、同级关系等。例如:A 依赖 B,B 依赖 C。这是理解传递性依赖的关键。
- 哈希值 (Cryptographic Hashes):组件文件的哈希值(如 SHA-256),用于验证组件的完整性,确保其在传输过程中未被篡改。
表 1: SBOM 核心要素示例
| 要素 | 描述 | 示例 |
|---|---|---|
| 组件名称 | 软件库、模块或包的名称 | github.com/gin-gonic/gin |
| 组件版本 | 组件的特定版本 | v1.7.7 |
| 供应商 | 提供组件的实体或组织 | Gin-Gonic |
| 唯一标识符 (PURL) | 通用软件包定位符 | pkg:golang/github.com/gin-gonic/[email protected] |
| 许可证 | 组件使用的开源许可证 | MIT |
| 哈希值 (SHA256) | 组件内容的加密哈希值 | a1b2c3d4e5f67890... |
| 依赖关系 | 指明组件依赖于其他哪些组件 | myapp -> gin-gonic/gin, gin-gonic/gin -> go-playground/validator |
B. SBOM 的重要性:为什么我们需要它?
SBOM 不仅仅是一个列表,它是构建软件供应链信任和安全的基础。
-
透明度与可追溯性:
- 对供应商而言:更全面地了解其产品的构成,更好地管理风险。
- 对消费者而言:在部署软件前,可以审查其中包含的组件,评估其潜在风险,并做出明智的决策。
- 当供应链发生安全事件时,SBOM 能够提供快速追踪和溯源的能力。
-
漏洞管理与响应:
- 当新的零日漏洞或高危漏洞(如 CVE-2021-44228,即 Log4j 漏洞)被公开时,组织可以利用 SBOM 快速识别其所有产品、服务或内部系统是否使用了受影响的组件及其版本。
- 这大大缩短了从漏洞披露到风险评估再到打补丁的响应时间,将数周甚至数月的工作缩短到数小时或数天。
- 没有 SBOM,您可能需要耗费大量人力,手动检查每一个应用程序的依赖,这在大型组织中几乎是不可能完成的任务。
-
合规性要求:
- 全球范围内,政府和行业监管机构对软件安全的关注日益增加。例如,美国总统在 2021 年发布的《改善国家网络安全行政命令》(Executive Order 14028) 中,明确要求向美国政府销售软件的供应商必须提供 SBOM。
- 类似的合规性要求预计将在更多行业和地区推广,使得 SBOM 成为进入某些市场或与特定客户合作的必备条件。
-
许可证合规性 (次要但相关):
- 虽然本次讲座主要聚焦安全风险,但 SBOM 中包含的许可证信息对于确保软件的合法使用和分发也至关重要。
- 它可以帮助组织避免因违反开源许可证条款而带来的法律风险。
C. SBOM 的价值体现:从开发到运营
SBOM 的价值贯穿整个软件开发生命周期 (SDLC):
- 开发阶段:开发人员可以在早期阶段识别并修复存在漏洞的依赖,避免将问题带入后期。
- 构建阶段:自动化工具可以在构建时生成 SBOM,确保其与实际构建内容一致。
- 测试阶段:安全团队可以利用 SBOM 进行更全面的渗透测试和安全评估。
- 部署阶段:运维团队可以使用 SBOM 监控已部署软件的漏洞状态,并及时响应。
- 运营与维护阶段:持续的漏洞扫描和 SBOM 更新,确保软件在整个生命周期内的安全性。
III. 核心 SBOM 标准与格式
为了实现 SBOM 的互操作性和自动化处理,行业内已经建立了几个核心标准。了解这些标准对于选择合适的工具和集成策略至关重要。
A. SPDX (Software Package Data Exchange)
SPDX 是由 Linux Foundation 发起和维护的一个开放标准,旨在为软件组件、许可证和安全信息提供一种通用的格式。它历史悠久,功能全面,能够描述非常详细的软件信息。
-
历史与特点:
- SPDX 的目标是解决软件供应链中透明度不足的问题。
- 它提供了一种表达软件组件、依赖关系、许可证、版权、安全信息(如 CVE)以及其他元数据的标准化方式。
- SPDX 支持多种序列化格式,包括 Tag-Value (文本)、RDF/XML、JSON 和 YAML。
-
数据模型概览:
- SPDX 文档 (SPDX Document):SBOM 的顶层容器。
- 软件包 (Package):代表软件中的一个可分发组件。
- 文件 (File):软件包中的单个文件,可以包含许可证、哈希等信息。
- 片段 (Snippet):代码片段,用于描述从其他文件中提取的代码块。
- 许可证 (License):明确组件的许可证。
- 关系 (Relationship):描述软件包、文件等实体之间的关系,如
DEPENDS_ON,CONTAINS,GENERATED_FROM等。
-
SPDX 文档结构:
一个典型的 SPDX JSON 文档会包含以下顶级字段:SPDXID:文档的唯一标识符。spdxVersion:SPDX 规范的版本。dataLicense:SPDX 文档内容的许可证(通常是 CC0-1.0)。documentNamespace:文档的唯一 URI。creationInfo:文档创建信息,包括创建者、日期等。packages:包含所有软件包的数组,每个软件包有其名称、版本、许可证、哈希等。files:包含所有文件的数组(如果需要详细到文件级别)。relationships:描述组件之间关系的数组。hasExtractedLicensingInfo:额外的许可证信息。
B. CycloneDX
CycloneDX 是由 OWASP (Open Web Application Security Project) 发起的一个轻量级、安全为中心的 SBOM 标准。它特别强调在自动化工具和 CI/CD 流程中的易用性。
-
历史与特点:
- CycloneDX 专注于软件供应链可见性和漏洞管理。
- 它的设计目标是尽可能地简洁,便于机器解析和生成,使其非常适合自动化流程。
- 支持 JSON 和 XML 两种序列化格式。
- 在描述容器镜像、固件等非传统软件组件方面也表现出色。
-
轻量级与自动化友好:
- CycloneDX 的数据模型相对 SPDCX 更精简,主要关注组件、其版本、哈希、许可证以及最重要的是组件之间的依赖关系。
- 这使得它在生成和解析时效率更高,更适合作为 CI/CD 管道中的快速 SBOM 生成步骤。
-
数据模型概览:
一个典型的 CycloneDX JSON 文档会包含以下顶级字段:bomFormat:总是CycloneDX。specVersion:CycloneDX 规范的版本。serialNumber:BOM 的唯一标识符。version:BOM 文档的版本。metadata:描述 BOM 本身的元数据,如工具信息、时间戳等。components:一个数组,包含所有组件的信息,每个组件有name,version,purl,hashes,licenses等。dependencies:一个数组,描述组件之间的依赖关系,通常以 PURL 或组件的内部uuid作为引用。
C. SWID (Software Identification Tag) (简要提及)
SWID 标签是由 NIST (美国国家标准与技术研究院) 开发的 ISO/IEC 19770-2 标准,主要用于识别已安装的软件产品。它更多地关注软件的安装状态和生命周期管理,而不是像 SPDX 和 CycloneDX 那样提供全面的供应链信息。在 SBOM 语境中,SWID 标签可以作为组件的唯一标识符之一,但它本身不是一个完整的 SBOM 格式。
D. 标准比较与选择
| 特性 | SPDX | CycloneDX |
|---|---|---|
| 发起组织 | Linux Foundation | OWASP |
| 主要目标 | 综合的软件供应链透明度,包括许可证、版权、安全 | 安全为中心,自动化漏洞管理与供应链可见性 |
| 复杂性 | 较高,数据模型更详尽 | 较低,更轻量级,易于自动化 |
| 序列化格式 | Tag-Value, RDF/XML, JSON, YAML | JSON, XML |
| 用例场景 | 许可证合规性、详细的供应链审计、长期归档 | CI/CD 集成、快速漏洞扫描、容器 SBOM |
| 组件描述 | 可细致到文件和代码片段 | 通常到软件包级别 |
选择建议:
- 如果您需要非常详细的许可证、版权和文件级信息,或者需要与法律团队紧密合作,SPDX 可能是更好的选择。
- 如果您的主要目标是自动化漏洞管理,快速集成到 CI/CD 流程,并注重效率,那么 CycloneDX 通常是更受欢迎的选择。
- 许多工具(如
syft)可以同时生成这两种格式的 SBOM,因此您也可以根据下游系统的需求来选择输出格式。在本讲座中,我们将主要演示如何生成这两种主流格式。
IV. Go 项目中的 SBOM 生成:自动化实践
在 Go 项目中生成 SBOM,其核心挑战在于如何准确地识别所有的直接和间接依赖。Go Modules 机制为我们提供了便利,但依然需要专门的工具来解析这些信息并将其转换为标准化的 SBOM 格式。
A. Go 模块与依赖管理回顾
Go 1.11 引入的 Go Modules 极大地改进了 Go 语言的依赖管理。
go.mod:定义了模块的路径、Go 版本以及直接依赖及其版本。go.sum:包含了所有直接和间接依赖的加密哈希值,用于确保依赖的完整性和安全性。- 间接依赖 (Transitive Dependencies):当您的项目依赖的库又依赖了其他库时,这些就是间接依赖。SBOM 必须包含这些间接依赖,因为它们同样可能引入安全漏洞。
Go Modules 机制虽然提供了依赖信息,但它本身并未输出为标准化的 SBOM 格式。这就是为什么我们需要自动化工具。
B. 自动化工具 syft 深度解析
syft 是 Anchore 公司开发的一款强大的、开源的、语言无关的 SBOM 生成工具。它能够扫描文件系统、容器镜像、Git 仓库等,并自动检测其中的软件包、库和依赖关系,然后将其输出为 SPDX、CycloneDX 等多种标准格式的 SBOM。
-
syft的工作原理:
syft通过多种扫描器来检测不同类型的软件包和依赖:- 文件系统扫描:遍历指定目录,查找常见的包管理文件(如
go.mod,package.json,pom.xml,requirements.txt等)。 - Go Modules 扫描器:专门解析
go.mod和go.sum文件,识别 Go 模块及其依赖。 - 二进制文件扫描器:可以分析编译后的二进制文件,尝试识别嵌入的库信息(虽然对 Go 静态链接的二进制文件效果有限,但对其他语言可能有用)。
- 容器镜像扫描:可以解压容器镜像层,扫描其中的文件系统。
- 文件系统扫描:遍历指定目录,查找常见的包管理文件(如
-
安装与基本使用:
syft的安装非常简单,支持多种操作系统。安装
syft(Linux/macOS):# 使用 Homebrew (macOS/Linux) brew install syft # 或者使用 Go 安装 (可能需要手动配置PATH) go install github.com/anchore/syft/cmd/syft@latest # 或者从 GitHub Release 下载二进制文件并添加到 PATH # 访问 https://github.com/anchore/syft/releases 下载适合您系统的版本验证安装:
syft version # 例如输出: syft v0.98.0为了演示,我们先创建一个简单的 Go 项目:
my-go-app/main.go:package main import ( "fmt" "log" "net/http" "github.com/gin-gonic/gin" "github.com/spf13/viper" // 添加一个配置库作为依赖 ) func main() { // 初始化 Gin 框架 r := gin.Default() // 示例路由 r.GET("/ping", func(c *gin.Context) { c.JSON(http.StatusOK, gin.H{ "message": "pong", }) }) // 使用 viper 读取配置 (只是为了引入依赖) viper.SetConfigName("config") // config.json, config.yaml, etc. viper.AddConfigPath(".") err := viper.ReadInConfig() if err != nil { log.Printf("Error reading config file: %s", err) } else { log.Printf("Config loaded: %v", viper.AllSettings()) } fmt.Println("Server is running on :8080") // 启动 HTTP 服务器 if err := r.Run(":8080"); err != nil { log.Fatalf("Failed to run server: %v", err) } }初始化 Go 模块并下载依赖:
mkdir my-go-app cd my-go-app go mod init my-go-app go mod tidy # 这将生成 go.mod 和 go.sum 文件,并下载 gin 和 viper 及其间接依赖现在,我们可以使用
syft来扫描这个 Go 项目。示例:扫描一个简单的 Go 项目
# 在 my-go-app 目录下执行 syft dir .输出会是一个纯文本的组件列表,包含名称、版本、类型等信息。这对于快速查看很有用,但不是标准的 SBOM 格式。
-
生成不同格式的 SBOM:
syft最强大的功能是能够输出多种标准 SBOM 格式。生成 SPDX JSON 格式的 SBOM:
syft dir . -o spdx-json > my-go-app-spdx.jsonmy-go-app-spdx.json文件将包含详细的 SPDX 格式 SBOM。您可以打开文件查看其结构。它会列出my-go-app及其所有的 Go 模块依赖,包括gin,viper以及它们各自的间接依赖。生成 CycloneDX JSON 格式的 SBOM:
syft dir . -o cyclonedx-json > my-go-app-cyclonedx.jsonmy-go-app-cyclonedx.json文件将包含 CycloneDX 格式的 SBOM,通常比 SPDX 更简洁,但包含了所有核心信息。生成 GitHub Dependency Graph 格式的 SBOM:
GitHub Dependency Graph 是 GitHub 用于其依赖图和 Dependabot 警报的基础。syft也可以生成这种格式,便于集成到 GitHub 的安全功能中。syft dir . -o github > my-go-app-github.json表 2:
syft常用输出格式格式名称 描述 命令行选项 Text 纯文本列表,适合快速查看 text(默认)SPDX JSON SPDX 2.X 标准,JSON 格式 spdx-jsonSPDX Tag-Value SPDX 2.X 标准,Tag-Value 文本格式 spdx-tag-valueCycloneDX JSON CycloneDX 1.X 标准,JSON 格式 cyclonedx-jsonCycloneDX XML CycloneDX 1.X 标准,XML 格式 cyclonedx-xmlGitHub JSON GitHub Dependency Graph 格式 githubSyft JSON syft工具的内部 JSON 格式,包含更多细节syft-json -
过滤与配置:
syft提供了丰富的选项来过滤扫描内容或调整输出。-
排除文件/目录:
# 排除 vendor 目录 (如果使用 Go Modules vendor 模式) syft dir . --exclude vendor/ -o spdx-json > my-go-app-spdx.json # 排除特定文件类型 syft dir . --exclude "*.test" -o spdx-json - 仅包含特定类型包:
# 仅包含 Go 模块 syft dir . --scope=all-layers --package-type=go-module -o cyclonedx-json - 生成最小 SBOM (仅包含直接依赖):
这通常不是推荐做法,因为间接依赖也可能存在漏洞。但如果出于特殊目的,可以尝试:
syft默认会尝试包含所有可检测到的依赖。要严格限制,可能需要后处理 SBOM 文件或使用更复杂的过滤规则。对于 Go 模块,syft已经做得很好,会自动解析go.sum中的所有传递性依赖。
扫描编译后的二进制文件 (Go):
由于 Go 默认静态链接,将所有依赖编译到单个二进制文件中,这使得从二进制文件逆向推导依赖变得困难。syft能够尝试识别一些 Go 模块信息,但其准确性和完整性可能不如直接扫描go.mod/go.sum。go build -o my-go-app syft file my-go-app -o cyclonedx-json > my-go-app-binary-cyclonedx.json比较
my-go-app-cyclonedx.json和my-go-app-binary-cyclonedx.json,您会发现直接扫描源码目录(包含go.mod)生成的 SBOM 会更完整和准确。因此,推荐在构建前或构建时,直接扫描 Go 项目的源码目录。 -
C. 其他 Go-specific 或集成工具
虽然 syft 是一个通用且强大的 SBOM 生成工具,但也有一些 Go 生态系统内的工具值得关注。例如,govulncheck (我们稍后会详细介绍) 主要用于漏洞扫描,而不是 SBOM 生成。它关注的是 Go 模块的已知漏洞,并能精确到函数调用级别,但它不直接输出标准的 SBOM 格式。因此,在 Go 项目中,syft 仍然是生成标准 SBOM 的首选工具。
D. 将 SBOM 生成集成到本地构建流程
将 SBOM 生成集成到本地构建流程是实现自动化的第一步。
-
Makefile 示例:
在my-go-app目录下创建Makefile:.PHONY: build clean sbom APP_NAME := my-go-app SBOM_FILE_SPDX := $(APP_NAME)-spdx.json SBOM_FILE_CYCLONEDX := $(APP_NAME)-cyclonedx.json # 默认构建目标 build: $(APP_NAME) sbom $(APP_NAME): main.go @echo "Building $(APP_NAME)..." go build -o $@ . @echo "Build complete." sbom: @echo "Generating SBOMs..." syft dir . -o spdx-json > $(SBOM_FILE_SPDX) syft dir . -o cyclonedx-json > $(SBOM_FILE_CYCLONEDX) @echo "SPDX SBOM generated: $(SBOM_FILE_SPDX)" @echo "CycloneDX SBOM generated: $(SBOM_FILE_CYCLONEDX)" clean: @echo "Cleaning up..." rm -f $(APP_NAME) $(SBOM_FILE_SPDX) $(SBOM_FILE_CYCLONEDX) @echo "Cleanup complete."现在,只需运行
make,就可以同时构建应用程序并生成 SBOM。make -
脚本化生成:
对于更复杂的场景或非 Makefile 项目,可以使用 shell 脚本来自动化这个过程:
generate_sbom.sh:#!/bin/bash APP_NAME="my-go-app" OUTPUT_DIR="./sbom-output" mkdir -p "$OUTPUT_DIR" echo "Generating SPDX JSON SBOM for $APP_NAME..." syft dir . -o spdx-json > "$OUTPUT_DIR/$APP_NAME-spdx.json" if [ $? -ne 0 ]; then echo "Error generating SPDX SBOM. Exiting." exit 1 fi echo "SPDX SBOM saved to $OUTPUT_DIR/$APP_NAME-spdx.json" echo "Generating CycloneDX JSON SBOM for $APP_NAME..." syft dir . -o cyclonedx-json > "$OUTPUT_DIR/$APP_NAME-cyclonedx.json" if [ $? -ne 0 ]; then echo "Error generating CycloneDX SBOM. Exiting." exit 1 fi echo "CycloneDX SBOM saved to $OUTPUT_DIR/$APP_NAME-cyclonedx.json" echo "SBOM generation complete."运行脚本:
chmod +x generate_sbom.sh ./generate_sbom.sh这些本地集成方法是为 CI/CD 自动化打下基础的关键步骤。
V. 利用 SBOM 审计第三方依赖的安全风险
生成 SBOM 只是第一步,真正的价值在于如何利用它来持续审计和管理安全风险。这一阶段通常涉及将 SBOM 与漏洞数据库进行比对,以识别已知漏洞。
A. 漏洞数据源:NVD, OSV, GHSA
审计 SBOM 需要权威的漏洞数据来源:
-
NVD (National Vulnerability Database):
- 由美国国家标准与技术研究院 (NIST) 维护,是全球最主要的公共漏洞数据库之一。
- 它聚合了来自 CVE (Common Vulnerabilities and Exposures) 项目的漏洞信息,并提供了额外的分析,包括漏洞类型、影响范围、修复建议以及 CVSS (Common Vulnerability Scoring System) 评分。
- 缺点是更新可能不够及时,且有时粒度不够细致。
-
OSV (Open Source Vulnerabilities):
- 由 Google 主导的开源项目,旨在提供更准确、更及时的开源软件漏洞信息。
- OSV 的特点是数据以 git 仓库的形式组织,更容易被自动化工具消费。
- 它强调漏洞的“可到达性”,即某个漏洞是否真的会影响到使用该组件的代码。
- 对于 Go 项目,OSV 数据库包含了 Go 官方维护的漏洞信息。
-
GHSA (GitHub Security Advisories):
- GitHub 维护的漏洞数据库,包含了 GitHub 上托管的开源项目发现的漏洞。
- 这些安全通告通常与 GitHub 的 Dependabot 警报集成,可以直接通知项目维护者。
- GHSA 数据也经常被聚合到 NVD 和 OSV 等其他数据库中。
-
漏洞标识符 (CVE):
- CVE 是一个国际标准,为每个已公开的安全漏洞分配一个唯一的标识符(例如
CVE-2021-44228)。 - 通过 CVE ID,可以跨不同的数据库和工具追踪同一个漏洞。
- CVE 是一个国际标准,为每个已公开的安全漏洞分配一个唯一的标识符(例如
-
漏洞严重性 (CVSS):
- CVSS 提供了一种开放的、通用的漏洞严重性评分方法。
- 它根据漏洞的可利用性、影响范围、所需权限等因素,计算出一个 0-10 的分数,并分为低、中、高、严重四个等级。
- CVSS 评分帮助组织优先处理最关键的漏洞。
B. 自动化漏洞扫描工具 grype 深度解析
grype 是 Anchore 公司开发的另一个开源工具,与 syft 紧密集成。它能够以 syft 生成的 SBOM 作为输入,对照多个漏洞数据库进行扫描,并生成详细的漏洞报告。
-
grype的工作原理:如何与 SBOM 结合:grype维护了一个本地的漏洞数据库缓存(从 NVD、OSV、GHSA 等源同步)。- 当接收到 SBOM 时,
grype会解析 SBOM 中的每个组件(名称、版本、PURL 等)。 - 然后,它会查询本地漏洞数据库,查找与 SBOM 中组件匹配的已知漏洞。
- 匹配成功后,
grype会生成一个详细的报告,列出受影响的组件、漏洞 ID (CVE)、CVSS 评分、漏洞描述和建议的修复版本。
-
安装与基本使用:
grype的安装方式与syft类似。安装
grype(Linux/macOS):# 使用 Homebrew (macOS/Linux) brew install grype # 或者使用 Go 安装 (可能需要手动配置PATH) go install github.com/anchore/grype/cmd/grype@latest # 或者从 GitHub Release 下载二进制文件并添加到 PATH # 访问 https://github.com/anchore/grype/releases 下载适合您系统的版本验证安装:
grype version # 例如输出: grype v0.70.0示例:扫描
syft生成的 SBOM
我们使用之前为my-go-app生成的my-go-app-spdx.json文件。grype sbom:my-go-app-spdx.jsonsbom:前缀告诉grype输入是一个 SBOM 文件。grype将会下载并更新其漏洞数据库,然后对 SBOM 进行扫描。
输出将会是一个表格形式的报告,列出发现的所有漏洞。直接扫描 Go 项目 (背后的机制):
grype也可以直接扫描目录或容器镜像,而无需预先运行syft。在这种情况下,grype会在内部调用syft来生成一个临时的 SBOM,然后对其进行扫描。grype dir .这与
syft dir . -o syft-json | grype sbom:-(通过管道传输syft的syft-json输出到grype的标准输入) 的效果类似。直接使用grype dir .更方便,但理解其内部机制有助于在 CI/CD 中进行更精细的控制。 -
过滤与报告:
grype提供了强大的过滤和报告功能。-
按严重性过滤:
您可能只关心高危或严重漏洞。# 只显示严重 (Critical) 和高危 (High) 漏洞 grype sbom:my-go-app-spdx.json --severity Critical --severity Highgrype支持Critical,High,Medium,Low,Negligible,Unknown等严重性级别。 -
输出格式 (JSON, CycloneDX, SPDX):
除了默认的表格输出,grype也可以输出机器可读的格式,便于集成到其他安全工具或仪表板中。# 输出 JSON 格式报告 grype sbom:my-go-app-spdx.json -o json > my-go-app-vulnerabilities.json # 输出 CycloneDX 格式报告 (包含漏洞信息) grype sbom:my-go-app-spdx.json -o cyclonedx-json > my-go-app-vulnerabilities-cyclonedx.json # 输出 SPDX 格式报告 (包含漏洞信息) grype sbom:my-go-app-spdx.json -o spdx-json > my-go-app-vulnerabilities-spdx.json -
生成 SARIF 报告:
SARIF (Static Analysis Results Interchange Format) 是一种用于静态分析结果的通用格式,被许多安全工具和平台支持,包括 GitHub Code Scanning。grype sbom:my-go-app-spdx.json -o sarif > my-go-app-vulnerabilities.sarif这将生成一个 SARIF 文件,可以上传到 GitHub 或其他兼容 SARIF 的平台进行展示和管理。
-
-
配置
grype:自定义漏洞源、排除项:
grype支持通过配置文件进行更高级的配置。- 自定义漏洞源:可以配置
grype从私有漏洞数据库或特定的 OSV 仓库获取数据。 - 排除项:可以排除特定的 CVE ID,或排除特定组件的漏洞(例如,如果您知道某个组件的漏洞在您的特定使用场景下不会被触发)。
grype.yaml:# .grype.yaml ignore: - vulnerability: CVE-2022-XXXXX # 忽略某个特定的CVE reason: "False positive" - vulnerability: CVE-YYYY-YYYYY package: name: "github.com/some/package" # 忽略某个包的特定CVE version: "1.2.3" reason: "Mitigated by configuration" - package: name: "github.com/another/package" # 忽略某个包的所有漏洞 reason: "Internal package, not exposed"然后运行
grype并指定配置文件:grype sbom:my-go-app-spdx.json --config .grype.yaml
- 自定义漏洞源:可以配置
C. Go 语言原生漏洞检查工具 govulncheck
govulncheck 是 Go 团队推出的一款专门用于 Go 模块的漏洞检查工具。它与 grype 等通用工具形成互补,提供了 Go 语言特有的优势。
-
govulncheck的独特优势:基于调用图的精确性:govulncheck的核心优势在于它能够分析 Go 程序的调用图 (call graph)。- 这意味着它不仅会报告项目中存在的漏洞包,还会进一步检查您的代码是否实际调用了包含漏洞的函数。
- 这种“可到达性”分析大大减少了误报,使开发人员能够专注于真正影响其应用程序的漏洞。例如,如果一个库中有一个漏洞函数,但您的代码从未调用它,
govulncheck就不会将其标记为直接风险。 - 它利用 Go 官方维护的 Go Vulnerability Database (GoVulnDB),这个数据库包含了 Go 模块特有的漏洞信息。
-
安装与使用:
govulncheck是 Go 官方工具链的一部分,Go 1.18 及以上版本可以通过go install安装。go install golang.org/x/vuln/cmd/govulncheck@latest在
my-go-app目录下运行:govulncheck ./...或者直接扫描二进制文件:
go build -o my-go-app govulncheck ./my-go-appgovulncheck会输出发现的漏洞列表,并指示漏洞是否在您的代码中被实际调用。示例输出 (假设存在漏洞):
# govulncheck ./... Vulnerability #1: GO-2022-0001 github.com/gin-gonic/gin before v1.7.0 is vulnerable to ... Found in: github.com/gin-gonic/[email protected] Call stacks: ... main.main calls github.com/gin-gonic/gin.(*Engine).Run ...如果一个漏洞存在于依赖中,但没有实际的调用栈,
govulncheck也会报告,但会明确指出“Found in (not called)”,帮助您区分风险。 -
与 SBOM 工具的互补性:
govulncheck关注 Go 模块的已知漏洞和实际使用情况:它提供了 Go 项目特有的精确度,帮助开发人员聚焦于最相关的漏洞。grype/syft提供更全面的 SBOM 和漏洞信息:syft生成的 SBOM 不仅包含 Go 模块,还可能包含操作系统包、配置文件等其他组件。grype扫描的漏洞数据库更广泛,不仅限于 Go 官方维护的漏洞。grype的输出是标准化的 SBOM 格式,更利于与下游工具集成。
最佳实践是结合使用它们:
- 在 CI/CD 中,首先使用
syft生成一个全面的 SBOM。 - 然后使用
grype对这个 SBOM 进行通用漏洞扫描,以发现所有已知组件的漏洞。 - 对于 Go 项目,额外运行
govulncheck进行一次 Go 语言特有的精确性检查,以识别那些实际可达的 Go 模块漏洞。 - 这样可以获得最全面的覆盖和最精确的报告。
D. 漏洞处理与修复策略
发现漏洞后,下一步是进行处理。
-
升级依赖:
这是最常见和最推荐的修复方式。大多数漏洞都会有上游修复版本。go get github.com/gin-gonic/gin@latest go mod tidy升级后,重新生成 SBOM 并进行扫描,以确认漏洞已解决。
-
临时缓解措施:
如果无法立即升级(例如,升级会导致兼容性问题),可能需要采取临时缓解措施:- 禁用受影响的功能。
- 配置 WAF (Web Application Firewall) 或其他安全控制来阻止对漏洞的利用。
- 打补丁 (patch) 依赖库的源代码(不推荐,除非别无选择,且需谨慎管理)。
- 隔离受影响的服务。
这些措施通常是临时的,最终目标仍是升级。
-
接受风险 (附带文档说明):
在某些罕见情况下,如果漏洞的 CVSS 评分较低,或者您能明确证明漏洞在您的特定部署环境中无法被利用(例如,漏洞存在于您从未使用的代码路径中,或者有其他安全控制可以完全阻断攻击),您可以选择接受风险。
重要提示:这必须是一个经过深思熟虑的决定,并需要详细的文档说明,包括风险分析、缓解措施和批准人。在grype中可以使用ignore配置来标记这些已接受的漏洞。
VI. 将 SBOM 审计集成到 CI/CD 流水线
将 SBOM 生成和漏洞审计集成到 CI/CD (Continuous Integration/Continuous Delivery) 流水线是自动化软件供应链安全的关键步骤。这确保了每次代码提交或构建都会自动进行安全检查。
A. CI/CD 集成的必要性
- 持续安全:在开发生命周期的早期发现并修复问题,遵循“左移 (Shift Left)”原则。
- 自动化与一致性:消除手动操作的错误和遗漏,确保每次构建都遵循相同的安全标准。
- 及时反馈:快速将漏洞信息反馈给开发团队,加速修复周期。
- 合规性证明:每次构建都生成 SBOM 和扫描报告,为合规性审计提供证据。
- 阻止不安全部署:配置流水线在发现严重漏洞时阻止部署,防止不安全软件进入生产环境。
B. 典型 CI/CD 流程中的 SBOM 步骤
SBOM 生成和审计可以放置在 CI/CD 流水线的不同阶段:
-
构建前 (Pre-Build):
- 在编译或打包之前,分析
go.mod文件生成 SBOM。这确保了 SBOM 准确反映了依赖的原始状态。 - 对 SBOM 进行初步漏洞扫描。
- 在编译或打包之前,分析
-
构建后 (Post-Build):
- 如果应用程序被打包成容器镜像,可以在镜像构建完成后,对容器镜像进行扫描以生成 SBOM,并进行漏洞审计。这能捕获操作系统层面的依赖和漏洞。
- 或者,对编译后的二进制文件或部署包进行 SBOM 生成和漏洞扫描 (Go 项目推荐扫描源码目录)。
-
部署前 (Pre-Deployment):
- 在将应用程序部署到生产环境之前,再次进行 SBOM 审计,特别是对于长期运行的应用程序,以捕获在构建后新发现的漏洞。
C. GitHub Actions 示例
GitHub Actions 是一种流行的 CI/CD 平台,我们可以用它来自动化 SBOM 的生成和审计。
假设我们的 Go 项目在 GitHub 仓库中。
.github/workflows/sbom-audit.yml:
name: Go SBOM Generation and Vulnerability Audit
on:
push:
branches:
- main
pull_request:
branches:
- main
workflow_dispatch: # 允许手动触发
jobs:
build-and-audit:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v3
- name: Set up Go
uses: actions/setup-go@v4
with:
go-version: '1.21'
cache: true # 缓存 Go 模块以加速构建
- name: Install Go dependencies
run: go mod tidy
- name: Build Go application
run: go build -o my-go-app .
- name: Install Syft
uses: anchore/[email protected]
with:
version: 'latest' # 确保使用最新版 syft
- name: Generate SBOM (CycloneDX JSON)
id: generate_sbom
run: |
syft dir . -o cyclonedx-json > my-go-app-cyclonedx.json
echo "SBOM_PATH=$(pwd)/my-go-app-cyclonedx.json" >> $GITHUB_ENV
env:
# 确保 syft 能够识别 go 模块
SYFT_GO_MOD_ENABLED: "true"
- name: Upload SBOM as artifact
uses: actions/upload-artifact@v3
with:
name: sbom-cyclonedx
path: my-go-app-cyclonedx.json
- name: Install Grype
uses: anchore/[email protected]
with:
version: 'latest' # 确保使用最新版 grype
- name: Scan SBOM for vulnerabilities
id: scan_sbom
# 使用 syft 生成的 SBOM 进行扫描
# --fail-on 选项可以配置在检测到特定严重性漏洞时使构建失败
run: |
grype sbom:"${{ env.SBOM_PATH }}" -o cyclonedx-json > my-go-app-vulnerabilities-cyclonedx.json
# 如果需要 SARIF 格式用于 GitHub Code Scanning,可以额外生成
# grype sbom:"${{ env.SBOM_PATH }}" -o sarif > my-go-app-vulnerabilities.sarif
- name: Upload Vulnerability Report as artifact
uses: actions/upload-artifact@v3
with:
name: vulnerability-report-cyclonedx
path: my-go-app-vulnerabilities-cyclonedx.json
# path: my-go-app-vulnerabilities.sarif # 如果生成了 SARIF
- name: Run GoVulnCheck
run: |
govulncheck ./... || true # 允许 govulncheck 失败,但继续执行流水线,根据需要可以修改为严格模式
env:
# 设置 Go 的路径,govulncheck 依赖于此
GOVULNCHECK_DATABASE: https://vuln.go.dev/
GO111MODULE: on
- name: Check for critical vulnerabilities and fail build (example)
# 这是一个示例,您需要根据实际的漏洞报告来解析并决定是否失败
# 更健壮的方法是解析 grype 的 JSON 输出或 SARIF 报告
run: |
# 假设我们想检查是否有任何 critical 或 high 漏洞,如果有则失败
# 这是一个简化示例,实际生产中需要更复杂的脚本来解析 JSON 报告
VULN_COUNT=$(cat my-go-app-vulnerabilities-cyclonedx.json | jq '.vulnerabilities | length')
if [ "$VULN_COUNT" -gt 0 ]; then
echo "Found $VULN_COUNT vulnerabilities. Checking severity..."
# 进一步解析 JSON 报告,查找 Critical/High 漏洞
CRITICAL_HIGH_COUNT=$(cat my-go-app-vulnerabilities-cyclonedx.json | jq '[.vulnerabilities[] | select(.severity | IN("CRITICAL", "HIGH"))] | length')
if [ "$CRITICAL_HIGH_COUNT" -gt 0 ]; then
echo "::error::Found $CRITICAL_HIGH_COUNT CRITICAL/HIGH vulnerabilities. Failing build."
exit 1
else
echo "No CRITICAL/HIGH vulnerabilities found, but other severities exist. Build continues."
fi
else
echo "No vulnerabilities found."
fi
# 需要安装 jq 来解析 JSON
# uses: docker://alpine/git:latest # 或者在 setup-go 之后添加 apt install jq
# 如果您希望在发现漏洞时直接失败,可以使用 grype 的 --fail-on 选项
# - name: Scan SBOM for vulnerabilities with fail-on
# id: scan_sbom_fail_on
# run: grype sbom:"${{ env.SBOM_PATH }}" --fail-on Critical --fail-on High
# continue-on-error: false # 如果 grype 失败,整个 job 失败
这个 GitHub Actions 脚本的流程是:
- 拉取代码。
- 设置 Go 环境,安装依赖并构建应用程序。
- 安装
syft,并使用它生成my-go-app的 CycloneDX 格式 SBOM。 - 将 SBOM 作为构建产物 (artifact) 上传,方便后续下载和分析。
- 安装
grype,并使用 SBOM 进行漏洞扫描,生成 CycloneDX 格式的漏洞报告。 - 将漏洞报告作为构建产物上传。
- 运行
govulncheck进行 Go 语言特有的漏洞分析。 - 关键步骤:添加了一个条件检查,如果
grype报告中包含 Critical 或 High 严重性的漏洞,则使整个 GitHub Actions 任务失败。这有效地阻止了不安全的软件发布。
D. GitLab CI/CD 示例
GitLab CI/CD 也提供了类似的集成能力。
.gitlab-ci.yml:
stages:
- build
- sbom_audit
variables:
GO_VERSION: "1.21"
APP_NAME: "my-go-app"
SBOM_FILE_CYCLONEDX: "${APP_NAME}-cyclonedx.json"
VULN_REPORT_CYCLONEDX: "${APP_NAME}-vulnerabilities-cyclonedx.json"
build_job:
stage: build
image: golang:${GO_VERSION}-alpine
script:
- apk add --no-cache git # 安装 git 用于 go mod tidy
- go mod tidy
- go build -o ${APP_NAME} .
artifacts:
paths:
- ${APP_NAME}
- go.mod
- go.sum
expire_in: 1 week
sbom_audit_job:
stage: sbom_audit
image: docker.io/anchore/grype:latest # 使用包含 syft 和 grype 的镜像
dependencies:
- build_job # 依赖于构建阶段
script:
- echo "Generating SBOM using Syft..."
- syft dir . -o cyclonedx-json > ${SBOM_FILE_CYCLONEDX}
- echo "Scanning SBOM for vulnerabilities using Grype..."
# 使用 --fail-on 选项,在发现高危或严重漏洞时使 job 失败
- grype sbom:${SBOM_FILE_CYCLONEDX} --fail-on Critical --fail-on High -o cyclonedx-json > ${VULN_REPORT_CYCLONEDX}
# 运行 govulncheck
# - /usr/local/go/bin/go install golang.org/x/vuln/cmd/govulncheck@latest # 需要安装 go 环境才能运行
# - /go/bin/govulncheck ./... || true # 假设 go 安装在 /usr/local/go
artifacts:
paths:
- ${SBOM_FILE_CYCLONEDX}
- ${VULN_REPORT_CYCLONEDX}
expire_in: 1 week
allow_failure: false # 如果 grype 因漏洞而失败,则整个 job 失败
这个 GitLab CI 示例使用了 Anchore 提供的包含 syft 和 grype 的 Docker 镜像,简化了工具安装。allow_failure: false 结合 grype --fail-on 实现了在检测到关键漏洞时阻止流水线继续执行的功能。
E. Jenkins Pipeline 示例 (简要提及)
在 Jenkins Pipeline 中,您可以将 syft 和 grype 命令集成到 script 块中,或者使用 Docker 代理来运行这些工具。
pipeline {
agent {
docker {
image 'golang:1.21-alpine'
args '-v /var/run/docker.sock:/var/run/docker.sock' // 如果需要扫描容器镜像
}
}
environment {
APP_NAME = "my-go-app"
SBOM_FILE_CYCLONEDX = "${APP_NAME}-cyclonedx.json"
VULN_REPORT_CYCLONEDX = "${APP_NAME}-vulnerabilities-cyclonedx.json"
}
stages {
stage('Build') {
steps {
sh 'go mod tidy'
sh "go build -o ${APP_NAME} ."
}
}
stage('Generate SBOM and Audit') {
agent {
docker {
image 'anchore/grype:latest' // 使用 Anchore 的复合镜像
args '-v /var/run/docker.sock:/var/run/docker.sock'
}
}
steps {
script {
sh "syft dir . -o cyclonedx-json > ${SBOM_FILE_CYCLONEDX}"
// 使用 try-catch 块来捕获 grype 失败,并决定是否中断 pipeline
try {
sh "grype sbom:${SBOM_FILE_CYCLONEDX} --fail-on Critical --fail-on High -o cyclonedx-json > ${VULN_REPORT_CYCLONEDX}"
echo "No Critical/High vulnerabilities found, continuing."
} catch (e) {
echo "Found Critical/High vulnerabilities. Failing pipeline."
currentBuild.result = 'FAILURE'
error "Vulnerabilities found: ${e.message}"
}
// govulncheck 可以在 golang 镜像中运行
// sh "go install golang.org/x/vuln/cmd/govulncheck@latest"
// sh "govulncheck ./..."
}
archiveArtifacts artifacts: "${SBOM_FILE_CYCLONEDX}, ${VULN_REPORT_CYCLONEDX}"
}
}
}
}
F. 报告与通知:如何将结果反馈给开发团队
- CI/CD 仪表板:大多数 CI/CD 系统都会显示任务的成功或失败状态,以及日志输出。
- Artifacts:将 SBOM 和漏洞报告作为构建产物,方便开发人员下载查看。
- 安全扫描集成:将 SARIF 报告上传到 GitHub Code Scanning 或其他 SAST/DAST 平台,集中管理和展示安全问题。
- 通知:通过邮件、Slack、Microsoft Teams 等通知渠道,将关键漏洞警报发送给相关的开发团队或安全团队。
- 集中式安全平台:对于大型组织,可以集成像 Anchore Enterprise、Dependency-Track 等专业的供应链安全平台,它们可以摄入 SBOM 和漏洞报告,提供统一的视图、策略管理和风险评估。
VII. SBOM 最佳实践与未来展望
A. 最佳实践
-
版本控制 SBOM:与代码版本同步:
将生成的 SBOM 文件与您的应用程序代码一起进行版本控制(例如,提交到 Git 仓库)。这样,每个代码版本都有一个对应的 SBOM,便于追溯。 -
存储与分发 SBOM:安全、可访问:
- 将 SBOM 存储在安全且可审计的位置(例如,对象存储、制品库)。
- 确保 SBOM 在需要时可以被消费者或审计员访问。
- 考虑使用 OCI 注册表来存储 SBOM,就像存储容器镜像一样。
-
签名 SBOM:确保完整性与来源:
使用数字签名来证明 SBOM 的完整性和来源。这意味着 SBOM 在生成后未被篡改,并且确实由声称的实体生成。cosign等工具可以用于对 SBOM 文件进行签名。 -
涵盖所有组件:包括操作系统、运行时、工具链:
一个理想的 SBOM 不仅包含应用程序依赖,还应包含构建应用程序所用的所有环境组件:- 操作系统包 (如果应用程序运行在容器中)。
- 编程语言运行时 (Go 版本)。
- 编译器和构建工具 (如
make,go工具链)。 - 基础镜像中的所有组件。
syft在扫描容器镜像时可以很好地捕获这些信息。
-
持续更新与再生成:
软件依赖是动态变化的,新的漏洞每天都在被发现。因此,SBOM 应该定期重新生成和扫描。每次代码变更、依赖更新、新漏洞披露时,都应触发 SBOM 的更新和审计。 -
与许可证合规性的协同:
虽然本次讲座侧重安全,但 SBOM 中的许可证信息对于许可证合规性同样重要。在集成 SBOM 工具时,也可以考虑其对许可证检测的支持,实现安全与合规的双重管理。
B. 挑战与发展方向
-
SBOM 的自动化生成与更新精度:
虽然syft等工具已经非常强大,但在某些复杂场景下(如动态加载的库、混淆代码、非常规的构建系统),生成 100% 准确和完整的 SBOM 仍然是一个挑战。未来工具需要更高的智能性和更广泛的覆盖。 -
运行时 SBOM 与动态分析:
当前的 SBOM 主要反映的是软件在构建时的静态构成。然而,软件在运行时可能会动态加载组件、使用不同的配置或与外部服务交互。未来的趋势是探索如何生成“运行时 SBOM”或将其与动态分析技术结合,以提供更全面的运行时安全视图。 -
供应链攻击的复杂性:
攻击者也在不断进化,可能通过更隐蔽的方式渗透供应链。例如,利用包管理器中的命名冲突 (typosquatting)、依赖混淆 (dependency confusion) 等。SBOM 需要不断发展,以应对这些新型攻击。 -
跨组织 SBOM 共享与验证:
在一个复杂的供应链中,一个产品可能包含来自多个供应商的组件。如何安全、高效、可信地共享和验证跨组织生成的 SBOM 是一个重要的挑战。需要更强的标准化、签名机制和信任根。 -
SBOM 与 attestation (证明):
除了 SBOM 本身,软件的“证明”也越来越受到关注。证明是关于软件如何构建、测试、签名的元数据。例如,SLSA (Supply-chain Levels for Software Artifacts) 框架就是一个旨在提高软件供应链完整性的标准,它强调通过构建过程的透明度和不可篡改性来增强信任。SBOM 可以作为这些证明的重要组成部分。
VIII. 确保软件供应链安全,从 SBOM 开始
在软件日益成为社会基础设施核心的今天,软件供应链安全已不再是可选项,而是强制要求。Software Bill of Materials (SBOM) 作为一种基础性工具,为我们提供了前所未有的透明度和可追溯性,是构建安全软件供应链的基石。
通过本次讲座,我们深入了解了 SBOM 的概念、主流标准,并通过 syft、grype 和 govulncheck 等工具,演示了如何在 Go 项目中自动化生成 SBOM 并审计第三方依赖的安全风险。我们还探讨了如何将这些流程无缝集成到 CI/CD 流水线中,并讨论了 SBOM 的最佳实践和未来趋势。
请记住,SBOM 不是一劳永逸的解决方案,而是一个持续的实践。它需要您在整个软件开发生命周期中,从设计、开发、构建、测试到部署和运营,都保持对组件透明度和安全风险的关注。从今天开始,将 SBOM 引入您的 Go 项目,将是您迈向更安全、更可信赖软件之旅的重要一步。
感谢各位的参与!