2026-04-22 · architecture / opensource
【开源许可与版权工程】开源许可证实操手册:从选型到发布
面向工程团队的开源许可证完整操作手册:许可证选型决策树、LICENSE/NOTICE/SPDX 文件写法、第三方依赖声明、CI 自动化检查、发布物合规标注,以及六套真实可复制的项目结构模板。




























十年前,一家公司发布一个 Java
应用,合规团队会问:“你们用了什么第三方库?”开发会打开
pom.xml,数一数 direct
dependencies,大概是二十几个,回一份 Excel 就算交差。
今天你再问同样的问题,答案是:我们也不知道。
一个普通的 Spring Boot 微服务,直接依赖十几个,间接依赖(transitive dependency)往往超过 400 个,这些间接依赖跨越至少七八种开源许可证,每周有若干个新的 CVE 披露,每天都有版本更新。没有人能靠人力维护这张清单。
软件成分分析(Software Composition Analysis,SCA) 和 软件物料清单(Software Bill of Materials,SBOM) 就是为了回答”你到底用了什么”这个问题而生的工程体系。它已经从 2015 年前后小众合规厂商的产品,演进成 2021 年美国总统行政令(Executive Order 14028)明文要求、2024 年欧盟《网络弹性法案》(Cyber Resilience Act,CRA)立法背书的基础设施。
如果你还没读过本系列前面的许可证知识,建议先看:
本文假设你已经理解 MIT、Apache-2.0、GPL、AGPL、SSPL 的基本差异,聚焦在”怎么用工具把这些许可证和漏洞信息自动化地管起来”。
2014 年的 Heartbleed、2015 年的 Shellshock、2017 年的 Equifax 数据泄露(起因是未升级的 Apache Struts CVE-2017-5638)、2020 年 SolarWinds 供应链攻击、2021 年 Log4Shell(CVE-2021-44228)——这一连串事件的共同规律是:受害企业并不知道自己用了什么版本的什么组件。
Log4Shell 爆发的那一周,安全团队第一件事不是打补丁,而是”先找一下我们哪里用了 Log4j”。很多公司花了两到三周才把自己家里的 Log4j 实例全部枚举清楚。原因是 Log4j 经常被另一个库间接引入,而那个库又被另一个库间接引入,在 fat-JAR、容器镜像、嵌入式 agent 中层层嵌套。
这件事直接催生了 2021 年 5 月拜登政府的行政令 EO 14028(Improving the Nation’s Cybersecurity),其中第 4(e) 条款明确要求联邦政府采购的软件必须提供 SBOM。美国商务部国家电信和信息管理局(NTIA)随后发布了《SBOM 最小元素》(The Minimum Elements For a Software Bill of Materials,2021 年 7 月),定义了 SBOM 必须包含的七项数据字段。
欧盟紧随其后。2024 年 10 月通过、2027 年底全面生效的《网络弹性法案》(CRA)对”带数字元素的产品”施加了强制安全义务,其中附件一明确要求制造商”识别并记录产品中包含的组件与漏洞”,行业普遍理解为必须提供 SBOM。
中国方面,等保 2.0(GB/T 22239-2019)在应用安全通用要求里含蓄地要求”对应用系统中使用的开发框架、第三方软件进行管理”;工信部 2022 年发布的《网络产品安全漏洞管理规定》要求厂商对自身及第三方组件漏洞承担披露义务;2023 年后陆续出现的关键信息基础设施(关基)采购指南明确提出”供方应随产品交付软件成分清单”。
换言之,SBOM 在国内外都已经从”加分项”变成”准入门槛”。
除了合规压力,工程侧本身也有刚需。过去十年开源依赖图谱的爆炸式增长有几个数据可以参考:
node_modules
目录下解压后的文件数通常在 20 万到 100 万级别。go.sum 达到 300–500
行已属常态。在这种规模下,人工维护依赖清单早已失效。即使你愿意给每个直接依赖标注许可证,传递依赖的数量也会以指数级扩展。比较出名的统计是 Tidelift 2021 年报告:一个中等规模应用的开源组件中,超过 80% 是传递依赖,开发者主动选择的直接依赖往往只是冰山一角。
对版权律师而言,SBOM 是开源合规取证的唯一可行路径;对 CISO 而言,SBOM 是 0-day 响应速度的决定性资产;对 DevOps 团队而言,SBOM 是”升不升版本”的决策依据;对采购与审计而言,SBOM 是合同附件。一份 SBOM 同时服务这四类角色,这也是它能迅速制度化的根本原因。
SCA 这个词有时会被理解成”扫一下代码生成一份 Excel”。但工业级 SCA 系统通常有四个层次。
这一层回答”项目里有哪些组件”。
最幼稚的做法是解析包管理器的锁文件——pom.xml、package-lock.json、Pipfile.lock、go.sum、Cargo.lock、composer.lock
等。这种方式快、准,但只覆盖”你声明的依赖”,不覆盖:
third_party/)。curl 一个库)。工业级工具必须同时支持三条路径:
Black Duck 的 Knowledge Base、FOSSA 的 Revere 引擎、Syft 的 cataloger 插件都属于第 2、3 层。
这一层回答”这个组件是什么许可证”。
SPDX license list(截至 2025 年收录约 660 个许可证 ID)是产业共识的词汇表。识别手段:
package.json 有 license
字段,Maven 有 <licenses>,Go module 的
go.mod 无此字段(这是 Go 生态的痛点)。LICENSE、LICENSE.txt、COPYING、COPYING.LESSER、NOTICE。package.json 写 MIT,但代码里带 GPL-2.0
的头文件——这通常意味着有人违规复制代码,必须人工复核。ScanCode 是这一层事实上的开源标杆,Black Duck、FOSSA、Mend 也都有自研的识别引擎。
一个经常被忽视的问题是许可证声明与源码不一致。举几类常见情形:
package.json 声明
MIT,但其中一个源文件顶部的注释写着”This file
is licensed under GPL-2.0”。这个文件很可能是早年从 Linux
内核复制粘贴过来的,当前仓库里就是一颗法律地雷。LICENSE 目录下同时放了
LICENSE.MIT、LICENSE.Apache、LICENSE.GPL,但没有
LICENSE 总声明。这种 “multi-licensed”
情况要求使用方主动选择一个许可证——默认使用等于同时接受三份合约,在实务中通常选择最宽松的那个,但需保留选择证据。third_party/、vendor/、external/
这些目录。因此许可证识别层在企业环境里通常需要双轨:一条快速路径(读元数据)用于 CI 阻断,一条慢速路径(全文扫描)用于合规审阅。
这一层回答”这些组件有没有已知漏洞”。
主要数据源:
关联的关键是 PURL(Package URL,RFC
草案),形如
pkg:maven/org.apache.logging.log4j/log4j-core@2.14.1。一个稳定的
PURL 能唯一标识”哪个生态的哪个包的哪个版本”,SBOM
工具与漏洞库都围绕 PURL 对齐。
与 PURL 并列的还有 CPE(Common Platform
Enumeration),形如
cpe:2.3:a:apache:log4j:2.14.1:*:*:*:*:*:*:*。CPE
是 NVD 早期使用的标识符,痛点是:NVD 分析员需要人工给每个
CVE 分配 CPE;同一个包经常有几个相近但不同的 CPE
字符串,匹配规则容易遗漏;CPE 与 PURL 之间没有官方 1:1
映射。2024 年 NVD 分析延迟恶化后,纯 CPE
匹配路线的误报和漏报问题更加突出,PURL-first
已经成为新系统的默认选择。
除数据源本身的覆盖差异外,关联还要处理版本范围语义。同一个
CVE 可能写成
< 2.17.0、>= 2.0, < 2.15.0、affected: 2.14.x,不同生态(Maven
的区间语法、npm semver、Debian 的
dpkg --compare-versions)语义不一致。工业级 SCA
往往要为每种生态写独立的版本比较器。这也是为什么 Trivy/Grype
这类扫描器会维护一张各生态的 canonical 版本比较实现。
这一层回答”发现了风险怎么办”。常见策略规则:
实现手段包括在 CI 中阻断流水线、在 PR 上留评论、在 Dependency-Track 中发告警、在制品库(Artifactory、Nexus)中设拦截规则。OPA(Open Policy Agent)的 Rego 语言和 CycloneDX 的 “License Expression” 字段可以把策略写成声明式代码。
策略层最常犯的错误是一刀切。同一个许可证(如 LGPL-2.1)在不同产品形态下的触发条件完全不同:作为 SaaS 后端使用基本无传染义务,静态链接进嵌入式固件分发就必须开源修改或提供可替换机制。一个成熟的策略引擎需要把”产品形态(分发/SaaS/内部工具)“作为输入维度,否则只能退化为”禁所有 Copyleft”这种一刀切,既杀错又挡不住真风险。关于这个话题展开见 Copyleft 工程边界。
SBOM 是 SCA 的输出契约。SCA 是过程,SBOM 是结果文档。目前主流有两套格式。
SPDX(Software Package Data Exchange)由 Linux 基金会于 2010 年发起,2021 年以 ISO/IEC 5962:2021 成为国际标准。它的定位是”许可证合规交换”,许可证表达能力最强。
SPDX 2.3(2022 年发布)支持 Tag-Value、RDF、JSON、YAML、Spreadsheet 多种序列化。核心概念:
Apache-2.0 OR MIT、(GPL-2.0-only WITH Classpath-exception-2.0)。SPDX 3.0(2024 年发布)做了较大结构重构,拆成 Core、Software、Security、Licensing、Build、AI、Dataset 等 profile,未来可以同时承载 SBOM、AI-BOM(AI 模型物料清单)、Dataset-BOM(数据集清单)。
一个极简的 SPDX 2.3 Tag-Value 片段示例:
SPDXVersion: SPDX-2.3
DataLicense: CC0-1.0
SPDXID: SPDXRef-DOCUMENT
DocumentName: my-service-1.4.2
DocumentNamespace: https://example.com/spdx/my-service-1.4.2-abc123
Creator: Tool: syft-1.12.0
Created: 2026-04-01T09:00:00Z
PackageName: log4j-core
SPDXID: SPDXRef-Package-log4j-core-2.17.1
PackageVersion: 2.17.1
PackageDownloadLocation: https://repo.maven.apache.org/maven2/org/apache/logging/log4j/log4j-core/2.17.1/log4j-core-2.17.1.jar
PackageLicenseConcluded: Apache-2.0
PackageLicenseDeclared: Apache-2.0
PackageCopyrightText: Copyright (c) Apache Software Foundation
ExternalRef: PACKAGE-MANAGER purl pkg:maven/org.apache.logging.log4j/log4j-core@2.17.1
Relationship: SPDXRef-Package-my-service DEPENDS_ON SPDXRef-Package-log4j-core-2.17.1
LicenseConcluded 与
LicenseDeclared
的区别很关键:Declared 是工具从 metadata
读到的声明,Concluded
是人工或扫描器综合各种证据得出的结论。两者不一致时,审阅员应以
Concluded 为准并留下理由。
CycloneDX 由 OWASP 于 2017 年发起,定位更偏”应用安全”。它的 schema 更简洁,对漏洞、VEX、服务、依赖图谱支持较早。
截至 2024 年 CycloneDX 1.6 支持:
CycloneDX 原生 JSON、XML、Protobuf,社区工具链(cdxgen、Dependency-Track)围绕它搭建。
对应的 CycloneDX 1.5 片段:
{
"bomFormat": "CycloneDX",
"specVersion": "1.5",
"serialNumber": "urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79",
"version": 1,
"metadata": {
"timestamp": "2026-04-01T09:00:00Z",
"tools": [{"vendor": "anchore", "name": "syft", "version": "1.12.0"}],
"component": {
"type": "application",
"bom-ref": "pkg:maven/com.example/my-service@1.4.2",
"name": "my-service",
"version": "1.4.2"
}
},
"components": [
{
"type": "library",
"bom-ref": "pkg:maven/org.apache.logging.log4j/log4j-core@2.17.1",
"group": "org.apache.logging.log4j",
"name": "log4j-core",
"version": "2.17.1",
"purl": "pkg:maven/org.apache.logging.log4j/log4j-core@2.17.1",
"licenses": [{"license": {"id": "Apache-2.0"}}]
}
],
"dependencies": [
{
"ref": "pkg:maven/com.example/my-service@1.4.2",
"dependsOn": ["pkg:maven/org.apache.logging.log4j/log4j-core@2.17.1"]
}
]
}CycloneDX 的 bom-ref 是 BOM
内部的引用锚点,通常直接复用
PURL,这让图谱构建变得极简。
| 维度 | SPDX | CycloneDX |
|---|---|---|
| 发起方 | Linux 基金会 | OWASP |
| 国际标准 | ISO/IEC 5962:2021 | ECMA-424(2024) |
| 主要定位 | 许可证合规交换 | 应用安全与漏洞 |
| 许可证表达 | 最完整(SPDX Expression 是业界事实标准) | 引用 SPDX ID |
| 漏洞/VEX | 3.0 新增 Security profile | 原生一等公民 |
| 序列化 | Tag-Value、JSON、YAML、RDF、XLSX | JSON、XML、Protobuf |
| 文件粒度 | 支持 File、Snippet | 默认 Component 级 |
| 工具生态 | FOSSology、ORT、tern、spdx-tools | cdxgen、Dependency-Track、CycloneDX CLI |
| 与 PURL | 2.3 起支持 | 1.0 起原生 |
| AI/数据 | 3.0 Profile | 1.5+ ML-BOM |
实践建议:
值得单独说明的是 VEX(Vulnerability Exploitability eXchange)。VEX 不是 SBOM 的替代品,而是补丁——当 SBOM 告诉你”我用了 Log4j 2.14.0”,VEX 回答”这个 Log4j 在我的产品里的 JNDI 查找功能被禁用,CVE-2021-44228 不可利用”。CycloneDX 1.4 起把 VEX 纳入一等公民,CISA 也发布了独立的 VEX 规范(Common Security Advisory Framework / CSAF VEX)。在给下游客户交付 SBOM 时,SBOM + VEX 成对交付才能避免客户被一堆”其实不受影响的 CVE”淹没。
商业 SCA 市场格局在 2020 年后发生了明显分化:一部分以开发者体验为卖点(Snyk、FOSSA),一部分仍固守”法律合规 + 审计报告”的老护城河(Black Duck、Sonatype),一部分挤在中间(Mend、Veracode SCA、Checkmarx SCA)。Gartner 的 AST(Application Security Testing)魔力象限里 SCA 近年基本稳定在这几家。下面逐一拆解。
以色列起家,2015 年成立,2022 年估值一度达 76 亿美元(后有回调)。产品线覆盖 SCA(Snyk Open Source)、SAST(Snyk Code)、容器(Snyk Container)、IaC(Snyk IaC)。
特点:
2015 年旧金山成立。相对 Snyk 更偏合规。
特点:
Black Duck Software 成立于 2002 年,是整个 SCA 行业的奠基者,2017 年被 Synopsys 以 5.65 亿美元收购。2024 年 Synopsys 将软件完整性业务(含 Black Duck、Coverity、Seeker)分拆成独立公司,仍沿用 Black Duck 品牌。
特点:
.jar 或容器镜像,反推出里面的组件。以色列 WhiteSource 于 2011 年成立,2022 年改名 Mend.io。
特点:
Sonatype 是 Maven Central 的运营方,2008 年成立,做 Nexus Repository(制品库)起家,Nexus IQ 是其 SCA 产品。
特点:
一个用于快速横向对比的表格:
| 工具 | 定位 | 漏洞数据源 | 许可证识别 | 二进制分析 | 典型年费(中型团队) |
|---|---|---|---|---|---|
| Snyk | 开发者优先 | 自研 Intel + NVD + GHSA | 中 | 否 | 5–20 万美元 |
| FOSSA | 合规优先 | 自研 + NVD | 强 | 有限 | 3–15 万美元 |
| Black Duck | 合规 + 审计 | BDSA(自研) | 强 | 强 | 10–50 万美元 |
| Mend | 修复自动化 | 自研 + NVD | 中 | 有限 | 5–20 万美元 |
| Sonatype IQ | 制品库阻断 | Sonatype Data Research | 中 | 有限 | 10–40 万美元 |
上述数字基于公开招投标与行业报告估算,不同规模、模块、席位差异极大,以实际报价为准。
Anchore 公司 2020 年开源 Syft(SBOM 生成)与 Grype(漏洞扫描),是目前最活跃的开源 SBOM 工具链。
Syft 的能力:
一个典型工作流:
# 安装(Linux / macOS)
curl -sSfL https://raw.githubusercontent.com/anchore/syft/main/install.sh | sh -s -- -b /usr/local/bin
# 对容器镜像生成 SBOM(CycloneDX JSON)
syft docker.io/library/nginx:1.25.3 -o cyclonedx-json > nginx-1.25.3.cdx.json
# 对本地目录生成 SPDX
syft dir:. -o spdx-json > my-app.spdx.json
# 对二进制文件做成分分析
syft /usr/local/bin/kubectl -o table
# 指定 cataloger(例如只看 Java 与 OS 包)
syft my-app.jar --catalogers java-cataloger,rpm-db-catalogerGrype 消费 Syft 输出:
# 直接扫描
grype docker.io/library/nginx:1.25.3
# 从 Syft SBOM 读入,离线扫描(SBOM-first 工作流)
syft -o json docker.io/library/nginx:1.25.3 | grype
# 仅报告 high/critical 且阻断 CI
grype sbom:nginx-1.25.3.cdx.json --fail-on high --only-fixedGrype 使用 Anchore 维护的漏洞数据库(聚合 NVD、GHSA、Alpine secdb、Debian OVAL、Red Hat OVAL、Amazon ALAS、Ubuntu USN、Wolfi、Chainguard 等)。
Syft 默认不下载源码,它只读包管理器元数据和文件指纹,因此速度极快——扫一个几百 MB 的容器镜像通常 10 秒内完成。这也是它与 ORT/ScanCode 的根本定位差异:Syft 回答”里面有什么”,ORT/ScanCode 回答”每一行代码是什么许可证”。二者配合而不是互相替代。
另一个实践要点是 Syft 的 --source-name 和
--source-version
参数:默认情况下它会用扫描目标的目录名或镜像名,若想让输出的
SBOM 在 Dependency-Track
里稳定对应同一个项目,最好显式传递。例如:
syft dir:. \
--source-name my-service \
--source-version $(git describe --tags --always) \
-o cyclonedx-json > sbom.cdx.jsonORT 由 HERE Technologies 发起,2017 年开源,现已捐给 OpenChain。它的定位是企业级合规工作流,而不是单点扫描工具。ORT 由若干 subcommand 组成:
典型命令:
# 1. 分析依赖(产出 analyzer-result.yml)
ort analyze -i ./my-project -o ./ort-output
# 2. 下载源码
ort download -i ./ort-output/analyzer-result.yml -o ./ort-output/downloads
# 3. 扫描许可证
ort scan -i ./ort-output/analyzer-result.yml -o ./ort-output
# 4. 查漏洞
ort advise -i ./ort-output/scan-result.yml -o ./ort-output \
--advisors OSV,VulnerableCode
# 5. 执行策略
ort evaluate -i ./ort-output/scan-result.yml -o ./ort-output \
--rules-resource /rules/osadl-matrix.rules.kts
# 6. 生成报告
ort report -i ./ort-output/evaluation-result.yml -o ./ort-output/reports \
--report-formats SpdxDocument,CycloneDx,WebApp,NoticeTemplateORT 的”策略 + 报告模板”设计非常适合大型企业,西门子、博世、华为、宝马均有公开案例使用 ORT。
ORT 的另一特色是
curations(人工修订)。开源生态里许可证元数据错漏很多——某个包声明是
MIT,实际源码里带了 GPL 代码;某个包根本没写 LICENSE
字段。面对这种情况,ORT 允许在 curations.yml
里写”对这个 PURL,concluded license 为 xxx,理由为
yyy”,把人工判断沉淀下来,下次扫描自动复用。这是企业级合规流程中”一次审阅,永久生效”的关键机制。ORT
官方还维护了一个公共的 ort-config
仓库,沉淀了社区共识的 curations,可以直接引用。
nexB 公司发起,2015 年开源,是许可证识别事实上的开源标杆。ORT、FOSSology 都会在内部调用 ScanCode。
pip install scancode-toolkit
scancode --license --copyright --package --info --json-pp result.json ./my-projectScanCode 的许可证规则库(scancode-licensedb)手工维护了几千条正则与文本模板,准确率在开源工具里第一。ScanCode.io(配套的 SaaS/自托管 Web 界面)让审阅者可以在 UI 里对扫描结果做 triage。
Linux 基金会项目,2008 年由惠普开源,定位是人工审阅平台。
FOSSology 在中国电信、中兴、华为内部有多年使用记录。它更像 Bugzilla 的 OSS 合规版,不是 CI 工具。
OWASP 旗舰项目,2013 年起由 Steve Springett 维护。定位是SBOM 聚合与持续监控平台。
工作模型:
它解决的核心痛点是时间维度的成分分析:扫一次只能告诉你此刻风险,Dependency-Track 告诉你”一周前上线那个版本是否受今天新披露的 CVE 影响”。
部署一般是 Docker Compose 起三个容器(apiserver、frontend、postgres),数分钟即可。
Dependency-Track 的几个高频用法:
exploitable、in_triage、resolved、not_affected(附豁免理由),生成对外交付用的
VEX 文档。CycloneDX 官方的 SBOM 生成器,印度工程师 Prabhu Subramanian 主力维护,由 OWASP Foundation 托管。
相比 Syft,cdxgen 的差异:
package.json。npm install -g @cyclonedx/cdxgen
# 自动探测项目类型
cdxgen -o bom.json .
# 指定类型(多项目共存时)
cdxgen -t java -o java-bom.json ./backend
cdxgen -t js -o js-bom.json ./frontend
# 容器镜像
cdxgen -t docker -o image.bom.json myorg/myapp:1.0
# 深度模式(解析 vendored / 二进制)
cdxgen --deep -t go -o go-deep.bom.json .SCA 落到 CI 上,本质要回答三个问题:什么时候扫、扫出来怎么办、产物放在哪。常见的模式有四类:
成熟的 SCA 体系通常是前扫后监控的组合:PR 时做增量扫描(快)、主干 release 时做全量扫描(慢但完整)、Dependency-Track 做持续监控(时间覆盖)。
GitHub 内置两件事:
GET /repos/{owner}/{repo}/dependency-graph/sbom。.github/dependabot.yml。对于企业 / 军工敏感代码不能上 GitHub SaaS 的场景,GitHub Enterprise Server 的 “Advanced Security” 许可里也提供 Dependabot、Secret Scanning、Code Scanning 三件套。
Dependabot 典型配置示例:
# .github/dependabot.yml
version: 2
updates:
- package-ecosystem: "gomod"
directory: "/"
schedule:
interval: "weekly"
open-pull-requests-limit: 5
groups:
minor-and-patch:
update-types: ["minor", "patch"]
ignore:
- dependency-name: "github.com/internal/legacy-sdk"
- package-ecosystem: "npm"
directory: "/web"
schedule:
interval: "daily"
versioning-strategy: increase-if-necessary
- package-ecosystem: "docker"
directory: "/"
schedule:
interval: "weekly"
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: "monthly"groups 是 2023 年新增的能力,能把一堆 patch
升级打包成一个 PR,显著减少 review
疲劳。对于更激进的全自动化,可以考虑 Renovate(Mend
开源维护),它支持 monorepo 按 package 级别分组、交叉关联
CVE、在 PR 里嵌入 release note 摘要。
Gitee(开源中国旗下)企业版在 2023 年后上线了”依赖扫描”,数据源包括 CNVD、NVD,对 Maven、npm、pip、Go 模块做依赖分析;“许可证识别”模块使用 ScanCode 规则库的本地化版本。Gitee 也接入了 OpenAtom 开源基金会的合规检查模板。
此外 GitCode、CodeArts(华为云)也都在 2024 年陆续推出了自研 SCA 能力,基本都是 ScanCode + 国产漏洞库的组合。
腾讯工蜂(git.code.tencent.com)、阿里云云效(codeup)也提供类似的内置 SCA 能力。对于主要在国内 DevOps 平台上开发的团队,优先用平台内置功能,省去自搭一套 Syft + Dependency-Track 的运维开销。代价是:这些平台的 SBOM 导出能力通常不完整,很难满足对外交付的 NTIA 最小元素要求,仍需在发版环节额外生成一份独立 SBOM。
以下是一个典型的”每次 push 生成 SBOM、附件到 Release、并上传到 Dependency-Track”的工作流:
# .github/workflows/sbom.yml
name: Generate SBOM
on:
push:
branches: [main]
tags: ['v*']
pull_request:
workflow_dispatch:
permissions:
contents: write # 用于上传到 Release
jobs:
sbom:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Set up Syft
uses: anchore/sbom-action/download-syft@v0
- name: Generate CycloneDX SBOM
run: |
syft dir:. \
-o cyclonedx-json=sbom.cdx.json \
-o spdx-json=sbom.spdx.json
- name: Grype scan (fail on high)
uses: anchore/scan-action@v3
with:
sbom: sbom.cdx.json
fail-build: true
severity-cutoff: high
- name: Upload SBOM artifacts
uses: actions/upload-artifact@v4
with:
name: sbom
path: |
sbom.cdx.json
sbom.spdx.json
- name: Upload to Dependency-Track
if: github.ref == 'refs/heads/main'
env:
DT_URL: ${{ secrets.DEPENDENCY_TRACK_URL }}
DT_API_KEY: ${{ secrets.DEPENDENCY_TRACK_API_KEY }}
PROJECT_UUID: ${{ secrets.DT_PROJECT_UUID }}
run: |
curl -sS -X POST "$DT_URL/api/v1/bom" \
-H "X-Api-Key: $DT_API_KEY" \
-H "Content-Type: multipart/form-data" \
-F "project=$PROJECT_UUID" \
-F "bom=@sbom.cdx.json"
- name: Attach SBOM to Release
if: startsWith(github.ref, 'refs/tags/')
uses: softprops/action-gh-release@v2
with:
files: |
sbom.cdx.json
sbom.spdx.json几个要点:
--fail-on 是最直接的策略网关。对容器镜像,把 syft dir:. 替换为
syft <image>:<tag> 即可。配合
cosign attach sbom 或
cosign attest --predicate sbom.cdx.json 可以把
SBOM 签名后附到 OCI
Registry,形成可验证的软件供应链证明(in-toto
attestation)。
把 SBOM 附到镜像的完整命令组合:
# 1. 构建镜像
docker buildx build -t registry.example.com/app:1.4.2 --push .
# 2. 生成 SBOM
syft registry.example.com/app:1.4.2 -o cyclonedx-json > sbom.cdx.json
# 3. 签名镜像
cosign sign registry.example.com/app:1.4.2 --key cosign.key
# 4. 把 SBOM 作为 attestation 附到镜像
cosign attest \
--predicate sbom.cdx.json \
--type cyclonedx \
--key cosign.key \
registry.example.com/app:1.4.2
# 5. 下游验证
cosign verify-attestation \
--key cosign.pub \
--type cyclonedx \
registry.example.com/app:1.4.2 \
| jq -r '.payload' | base64 -d | jq '.predicate'这种做法让 SBOM 永远跟随镜像走,而不是散落在 Release 资产或某个邮件附件里。符合 SLSA(Supply-chain Levels for Software Artifacts)level 3 的供应链成熟度模型。
2021 年 5 月 12 日签署,行政令序号 14028。第 4 节专门讲”增强软件供应链安全”。相关落地文件:
对中国企业出海美国的影响:向美国联邦、州政府、军方供货必须提供 SBOM;商业 SaaS 的大型美国客户(金融、医疗)也逐步把 SBOM 写进供应商合同。
与 EO 14028 配套的还有几个具体法规节点:
2022 年 9 月草案、2024 年 10 月正式通过(Regulation (EU) 2024/2847),自公布后 36 个月全面适用(2027 年底),报告义务于 21 个月后生效(2026 年 9 月)。
核心义务:
业内普遍解读:CRA 附件一第 2(1) 条的”识别 & 记录”等同于要求 SBOM。ENISA 也公开表态支持 SPDX/CycloneDX。
CRA 对开源项目作者的处理是一个专门博弈点:商业性质的开源(open-source software stewards)承担有限义务,纯个人业余开源不在范围内。对中国开源维护者的实际影响较小,但对”把开源 fork 后商业化销往欧盟”的公司,必须把 SBOM、漏洞响应、CE 合格声明全部走完。
CRA 另一条容易被忽视的高压线是主动利用披露 24 小时义务——在企业内部这意味着安全响应团队必须有能够 24 小时在岗的流程与人员,并且能够快速从 SBOM 反向定位到受影响产品版本、客户清单,才能在 24 小时内完成通知。SBOM 没有做持久化、没有版本化的公司,这条义务几乎不可能满足。
EU CRA 的落地时间线值得记忆:
| 时间 | 里程碑 |
|---|---|
| 2024-10-23 | 法案正式通过 |
| 2024-12-11 | 在 Official Journal 发布 |
| 2025-06-11 | 第 14 条报告义务指南出台窗口(委员会实施法案) |
| 2026-09-11 | 漏洞报告义务生效 |
| 2027-12-11 | 全面适用(所有主要义务) |
国内厂商对欧盟出口前应预留至少 12–18 个月准备期来搭 SBOM 能力与漏洞响应流程。
GB/T 22239-2019(信息安全技术 网络安全等级保护基本要求,俗称等保 2.0)本身没有”SBOM”字样,但相关条款已经等价要求:
此外:
实务操作上,国内企业的 SBOM 字段通常沿用 SPDX/CycloneDX,但增加一列”国产替代建议”或”国密合规状态”以满足本地化要求。
另外值得留意的三份国内标准/草案:
从合规触发点上说,一家公司若同时满足以下条件中的两条及以上,就值得把 SBOM 列为刚性工程目标:
落地的第一天不要去谈”全公司统一 SCA 平台”,先让 Syft 在 一个项目 的 CI 里跑起来,输出 CycloneDX JSON,上传为 Artifact。这一步成本极低(半天工作量),价值极高:从此团队至少能回答”我用了什么”。
注意事项:
repo/branch/commit
归档),这决定了后面”追溯历史漏洞”能不能做成。部署 Dependency-Track(或者直接用 SaaS,如 OWASP 自托管版本),把 SBOM 推上去,让它订阅 NVD/GHSA/OSV。
这一步会暴露第一个现实:历史技术债远大于新增风险。几乎所有项目第一次扫描都会发现几十个 high/critical。此时不要 panic——按”可利用性 × 修复成本”做优先级,先处理”有公开 exploit 且一条命令能升的”,把中长期不能升的组件挂 VEX 标注并上报给安全团队备案。
Dependency-Track 的最小部署(Docker Compose):
# docker-compose.yml
version: "3.8"
services:
dtrack-apiserver:
image: dependencytrack/apiserver:4.11.0
environment:
- ALPINE_DATABASE_MODE=external
- ALPINE_DATABASE_URL=jdbc:postgresql://db:5432/dtrack
- ALPINE_DATABASE_USERNAME=dtrack
- ALPINE_DATABASE_PASSWORD=changeme
deploy:
resources:
limits:
memory: 8G
volumes:
- dtrack-data:/data
depends_on: [db]
ports: ["8081:8080"]
dtrack-frontend:
image: dependencytrack/frontend:4.11.0
environment:
- API_BASE_URL=http://localhost:8081
ports: ["8080:8080"]
db:
image: postgres:15
environment:
- POSTGRES_DB=dtrack
- POSTGRES_USER=dtrack
- POSTGRES_PASSWORD=changeme
volumes:
- pgdata:/var/lib/postgresql/data
volumes:
dtrack-data:
pgdata:首次启动后到管理界面开启 NVD、GitHub Advisories、OSV 三个 analyzer 数据源,等待首轮镜像同步(NVD 完整镜像约 200 MB,OSV 约 500 MB),之后 API Key 即可用于从 CI 上传 SBOM。
等漏洞治理走上正轨后,再上许可证。典型策略:
| 许可证类别 | 合并到 main | 发布到公网 | SaaS 自用 |
|---|---|---|---|
| 公共领域 / CC0 | ✔ | ✔ | ✔ |
| MIT / BSD / Apache-2.0 | ✔ | ✔ | ✔ |
| MPL-2.0 / LGPL(动态链接) | ✔ | ✔(附义务) | ✔ |
| LGPL 静态链接 | 需审批 | 需审批 | ✔ |
| GPL-2.0 / GPL-3.0 | 需审批 | 仅随 GPL 产品 | ✔ |
| AGPL-3.0 | ❌ 原则禁 | ❌ | 需审批 |
| SSPL / BSL / Commons Clause | ❌ | ❌ | ❌ |
| 未知 / 无声明 | ❌ | ❌ | ❌ |
策略用 ORT Evaluator 的 Kotlin DSL 或 Dependency-Track 的 Policy Engine 落地,结合 OPA Rego 还能把”我们的产品是 SaaS 还是分发品”当成参数传入。
一个最小的 OPA Rego 策略示例:
package sbom.license
# 默认黑名单
forbidden_licenses := {
"AGPL-3.0-only", "AGPL-3.0-or-later",
"SSPL-1.0",
"Commons-Clause",
"BUSL-1.1",
}
# 产品类型参数(通过 input.product_type 传入)
# "distributed"(分发)| "saas"(自用)| "internal"(内部工具)
deny[msg] {
some component
component := input.components[_]
license := component.licenses[_].license.id
forbidden_licenses[license]
input.product_type == "distributed"
msg := sprintf("分发产品禁止使用 %s 许可证(组件:%s@%s)",
[license, component.name, component.version])
}
deny[msg] {
some component
component := input.components[_]
license := component.licenses[_].license.id
license == "GPL-3.0-only"
input.product_type == "distributed"
not component.properties[_].name == "license_approval"
msg := sprintf("GPL-3.0 组件 %s 需走白名单审批",
[component.name])
}
在 CI 中调用:
opa eval \
--data policy.rego \
--input sbom.cdx.json \
--format pretty \
'data.sbom.license.deny'有 deny 输出就阻断构建。Rego 的优点是策略即代码——策略本身可以进版本库、走 PR review、写单测。
product/version/{spdx,cdx}.json 命名。cosign attach sbom)。一些开源项目(如
Kubernetes、Istio)已经这么做。配套还需要建立几条最低限度的运营 SLA:
| 事件 | 响应 SLA |
|---|---|
| Critical CVE(CVSS ≥ 9.0)且已有公开 exploit | 8 小时内确认影响范围 + 48 小时内热修 |
| High CVE(7.0 ≤ CVSS < 9.0) | 72 小时内确认 + 7 天内修复或 VEX 豁免 |
| Medium / Low | 30 天内随例行版本合并修复 |
| 许可证高风险引入(AGPL/SSPL) | PR 阻断 + 24 小时内人工复核 |
| 新 CVE 影响过往 Release(回溯) | 7 天内发布客户通告 |
SLA 写下来之后,SCA 工具才真正开始发挥作用;没有 SLA 的 SBOM 只是一份没人看的 JSON。
实际落地一年后你大概率会踩到的坑:
SBOM
不是一次性产物。常见误解是”发版前扫一下就行”。现实是:依赖锁文件每次
npm install
都会变,容器基础镜像每次重建都会变,CVE 每天都在新增。SBOM
必须按构建生成、按版本归档、按时间监控,任何一环缺失都失去价值。
Go 二进制的模块信息缺失。Go 1.18+ 用
-buildvcs 嵌入了模块信息,但 1.17 及以下、以及
-trimpath 构建的二进制,syft
读不到依赖。解决办法是构建时强制保留
buildinfo,或扫描源码而不是二进制。
Python
动态依赖看不到。requirements.txt
能抓到显式依赖,但 setup.py 动态 import、conda
环境、notebook magic 安装的包都抓不到。建议以
pip freeze
的输出(运行时真实安装结果)为准。
vendored 代码被漏扫。某些团队把
third_party/zlib/
复制进仓库但没有任何元数据。此时只有 ScanCode
等基于文件指纹的工具才认得出,单靠 Syft 不够。
Fat-JAR 内层依赖。Spring Boot
的可执行 JAR 里嵌套了几百个小 JAR,Syft
默认会递归解开,但某些 Shade
插件重打包后类名被重写,反解失败。治理思路:禁 shade
重写,或在 Maven 阶段先扫
dependency:list。
License 冲突误报。同一个包在 NPM 写 MIT、源码头写 ISC、NOTICE 写 Apache-2.0——这不一定是违规,很多项目历史上就是这么”多许可证并存”。要手工建立”已审白名单”而不是每个 PR 都报红。
容器基础镜像的 CVE 风暴。扫一个官方 Ubuntu 22.04 基础镜像能轻松扫出 200+ CVE,大部分不可利用。策略要把基础镜像 CVE 与应用层 CVE 分轨治理,基础镜像层面以”及时更新 base image”代替”逐条修复”。
漏洞数据库滞后与误报。NVD 在 2024 年经历了严重的分析积压,大量 CVE 超过 3 个月仍无 CPE 映射,导致 Grype/Trivy 误报或漏报。推荐多源交叉:OSV + GHSA + 厂商原生库。
SBOM 本身成为敏感资产。一份完整 SBOM 等于告诉攻击者”我用了哪个 0-day 影响的库”。对外发布的 SBOM 与对内使用的 SBOM 应区分:对外脱敏(如不含内网路径、构建机器名),对内保真。
AI 模型与数据集不在经典 SBOM 范围。用 HuggingFace 上一个 Apache-2.0 权重训练了自己的模型,这个模型在你产品里是”组件”吗?SPDX 3.0、CycloneDX 1.5 的 AI-BOM/ML-BOM 正在补这个缺口,但工具链成熟度还不高。
多仓库去重。一家公司有上千个微服务,每个服务都引入 Jackson——漏洞管理应按”组件 × 版本 × 受影响服务”维度汇总,而不是每服务各自一张表。Dependency-Track 的 “Portfolio” 视图就是解决这个的。
依赖混淆攻击(dependency
confusion)。攻击者在公共 registry
上抢注你的内部包名,同版本号抢先发布,你的构建会误从外网拉取恶意包。防御手段:内部包统一使用
scope(如 @mycorp/xxx)或独立 registry 且禁止
fallback 到公共源。
恶意
typo-squatting。loadsh 冒充
lodash、colros 冒充
colors,这类包往往在首次安装时植入挖矿脚本。SCA
工具需要订阅恶意包情报(如 Sonatype OSS Index、Checkmarx
SCS、PyUp Safety),不是所有漏洞库都覆盖。
CI 产物外泄。SBOM 里含内部 npm
registry URL、内部包名、commit hash,这些本身是敏感情报。在
GitHub Actions 里用 upload-artifact
时,如果仓库是 public,Artifact
也可能被外部访问(取决于仓库配置)。
跨团队多语言一致性。前端用 Syft、后端用 ORT、运维用 Trivy——三份 SBOM 格式近似但字段值略有差异,聚合到 Dependency-Track 后产生”重复组件但不同 PURL”的脏数据。治理办法是统一工具链,或在聚合层做 PURL 归一化。
签名密钥轮换。cosign 签名的 SBOM 在密钥轮换后验证失败,需要保留历史公钥或使用 Fulcio 的短期证书配合 Rekor 透明日志。SLSA L3+ 的标准做法是结合 OIDC 与 Fulcio 实现 “keyless” 签名。
| 场景 | 推荐组合 |
|---|---|
| 个人项目 / 小团队 | Syft + Grype(本地跑) + GitHub Dependabot |
| 创业公司 A 轮前 | Syft + Grype + Dependency-Track(自托管) |
| 中型企业(百人研发) | 上面基础上 + ORT(合规报告)+ Renovate(升级机器人) |
| 大型企业(千人以上) | 商业 SCA(FOSSA/Black Duck/Snyk 三选一)+ 内部 Dependency-Track + 自研策略 |
| 金融、电信、国央企 | Black Duck 或 Nexus IQ 作底座(审计报告齐全) + 国产化 SCA(补 CNVD 数据源) |
| 军工、关基 | 完全离线:本地 ScanCode + 本地 VulnerableCode + 本地漏洞库同步 |
一个经验法则:工具只是 30%,流程与人占 70%。再贵的 Black Duck 也挡不住开发绕过 CI 直推制品;再好用的 Syft 也救不了一家没人读 SBOM 的公司。能跑得下去的标志是:有一个 OSPO 或安全团队每周 review 一次 Dependency-Track 告警、每季度 review 一次许可证策略、每年复审一次 SBOM 发布政策。
再给一个选型决策树,帮助快速定位:
关于 OSPO 如何搭建,见 企业开源办公室(OSPO)与开源 PMO 建设。
以下信息仅基于公开演讲、博客、白皮书,不代表内部实际架构。
华为:2020 年前后在内部上线基于 ORT 和 FOSSology 的开源合规平台”EulerMakerSec”(名称未公开)。华为是 ORT 的主要企业贡献者之一,公开提交了若干 Gradle/Maven 解析器改进。鸿蒙/欧拉项目的每个版本都随产品发布 SPDX SBOM。
字节跳动:字节的开源办公室 2022 年前后在 OpenAtom 会议上介绍过内部 SCA 体系,核心组件包括:基于 ScanCode 的许可证扫描、自研漏洞库(聚合 NVD/GHSA/OSV/CNVD)、与内部制品库 Bits 深度集成。对外的火山引擎云产品在 2024 年起陆续支持为客户生成 CycloneDX SBOM。
蚂蚁集团:在 2023 年 KubeCon China 演讲中介绍了基于 CycloneDX + Dependency-Track 的内部方案,结合自研的 “AntSec SBOM” 把 SBOM 签名(cosign)+ in-toto provenance 写入了 OceanBase/SOFAStack 等对外发布产品。蚂蚁也是 CycloneDX 标准的企业贡献者之一。
腾讯:腾讯代码安全团队公开过基于 Syft + Grype 的容器镜像扫描流水线,覆盖所有上 TKE(Tencent Kubernetes Engine)的业务镜像;在 OSPO 层面主要用商业工具做合规兜底(具体厂商未官宣)。
阿里巴巴:Dragonwell JDK、OceanBase、PolarDB 等对外产品在 2024 年后发布 SBOM(SPDX/CycloneDX 并存);云效 DevOps 平台内建了依赖扫描与许可证检查模块。
小米 / vivo / OPPO:Android/鸿蒙 衍生系统出海面临 Google GMS 和欧盟 CRA 双重合规压力,均已在 ROM 发布流程里加入 SBOM 生成步骤,供渠道商与监管核查。
这几家的共同规律:内部早用开源自研 + 外部合规交付用 SPDX/CycloneDX 标准。
另一个值得关注的趋势是国产 SCA 厂商的崛起。2023 年后几家安全厂商陆续推出本地化 SCA 产品:
国产厂商普遍的优势是 CNVD/CNNVD 数据同步及时、支持国产化操作系统(麒麟、统信、欧拉)的包格式解析、对国产 CPU 架构(鲲鹏、飞腾、龙芯、兆芯)二进制的识别。劣势在国际开源生态(Rust、Swift、现代前端工具链)覆盖尚在追赶。对于”信创 + 国际化并存”的企业,常见策略是商业双栈——一家国产 + 一家国际,在内部聚合层合并去重。
最后是一个成本观察:人力成本通常高于工具成本。一家 500 人研发规模的企业,搭建并维护 SCA/SBOM 体系的人力投入普遍在 3–5 FTE(full-time equivalent),包括安全工程师、OSPO 合规、DevOps 集成、法务审阅各占其中一部分。而工具年费按座位通常在 20 万到 200 万人民币区间,二者加起来只是整体研发成本的千分之几,却能避免一起 Equifax、一次 GPL 诉讼、一批客户流失——投产比极高。
如果你的产品要出海到美国 / 欧盟,请顺带阅读 出海合规:许可证、出口管制与数据合规。
本文为工程参考,不构成法律意见。涉及具体法律风险请咨询专业法律顾问。
标准与规范
法规
工具官方文档
商业厂商公开资料
行业报告与实践
上一篇:数字天堂、不乱买、罗盒:中国 GPL 诉讼第一案系列 | 下一篇:企业开源办公室(OSPO)与开源 PMO 建设
把当前热点继续串成多页阅读,而不是停在单篇消费。
2026-04-22 · architecture / opensource
面向工程团队的开源许可证完整操作手册:许可证选型决策树、LICENSE/NOTICE/SPDX 文件写法、第三方依赖声明、CI 自动化检查、发布物合规标注,以及六套真实可复制的项目结构模板。
2026-04-22 · architecture / opensource
面向做闭源/商业产品的团队:逐一拆解 MIT、LGPL、GPL、AGPL、SSPL、BSL 在 SaaS、私有化部署、移动 App、嵌入式固件等形态下的许可边界,给出三级名单模板、CI 扫描配置、SBOM 存证方案与出海补充要求。
2026-04-22 · architecture / opensource
面向中国工程团队的开源许可、版权与合规系列。从 GPL、AGPL、Apache、木兰协议到中国真实案例、SCA/SBOM 工具链与出海合规,讲清楚开源在工程落地中的坑与方法。
2026-04-22 · architecture / opensource
2018 年 8 月,红芯浏览器在完成 2.5 亿元融资后被发现基于 Chromium 换皮。本文从工程角度复盘这一事件:Chromium BSD-3 协议本身允许什么、不允许什么,如何通过文件指纹识别 Chromium 魔改,以及深度 Deepin、统信 UOS、麒麟 Kylin、中科曙光等国产系统的开源合规现状。
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。