name: sbom-management description: 软件物料清单管理,包括生成、格式、漏洞跟踪和供应链安全 allowed-tools: Read, Glob, Grep, Write, Edit, Task
SBOM 管理
软件物料清单创建、维护和供应链安全的全面指南。
何时使用此技能
- 为软件发布创建SBOM
- 响应客户SBOM请求
- 跟踪软件组件和依赖
- 实施供应链安全
- 满足法规要求(美国行政命令14028,欧盟CRA)
SBOM 基础
什么是SBOM?
软件物料清单是一个正式的、机器可读的软件组件和依赖、它们的关系以及相关元数据的清单。
您的应用程序
├── 依赖 A (v1.2.3) → 传递依赖 X
├── 依赖 B (v2.0.0) → 传递依赖 Y, Z
├── 依赖 C (v3.1.0)
└── 直接代码组件
NTIA 最低元素
根据NTIA SBOM指南的必需元素:
| 元素 | 描述 | 示例 |
|---|---|---|
| 供应商名称 | 创建/维护的实体 | “Microsoft” |
| 组件名称 | 组件的名称 | “System.Text.Json” |
| 版本 | 版本标识符 | “8.0.0” |
| 其他唯一标识符 | 额外ID | PURL, CPE |
| 依赖关系 | 上游/下游 | “依赖” |
| SBOM数据作者 | 谁创建了SBOM | “Contoso Inc” |
| 时间戳 | SBOM创建时间 | “2025-01-15T10:30:00Z” |
SBOM 格式
| 格式 | 优势 | 用例 |
|---|---|---|
| CycloneDX | 安全导向,支持VEX | 漏洞管理 |
| SPDX | 许可证导向,ISO标准 | 许可证合规 |
| SWID | 软件标识 | 资产管理 |
CycloneDX(推荐)
基本结构
{
"$schema": "http://cyclonedx.org/schema/bom-1.5.schema.json",
"bomFormat": "CycloneDX",
"specVersion": "1.5",
"version": 1,
"serialNumber": "urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79",
"metadata": {
"timestamp": "2025-01-15T10:30:00Z",
"tools": [
{
"vendor": "CycloneDX",
"name": "cyclonedx-dotnet",
"version": "3.0.0"
}
],
"component": {
"type": "application",
"name": "MyApplication",
"version": "1.0.0"
}
},
"components": [
{
"type": "library",
"bom-ref": "pkg:nuget/Newtonsoft.Json@13.0.3",
"name": "Newtonsoft.Json",
"version": "13.0.3",
"purl": "pkg:nuget/Newtonsoft.Json@13.0.3",
"licenses": [
{
"license": {
"id": "MIT"
}
}
],
"hashes": [
{
"alg": "SHA-256",
"content": "a5c9a4e..."
}
]
}
],
"dependencies": [
{
"ref": "pkg:nuget/MyApplication@1.0.0",
"dependsOn": [
"pkg:nuget/Newtonsoft.Json@13.0.3"
]
}
]
}
组件类型
应用程序 - 独立应用程序
框架 - 软件框架
库 - 软件库
容器 - 容器镜像
操作系统
设备 - 硬件设备
固件 - 设备固件
文件 - 任意文件
机器学习模型
数据 - 数据资产
.NET SBOM 生成
使用 CycloneDX 工具
# 安装工具
dotnet tool install --global CycloneDX
# 为解决方案生成SBOM
dotnet CycloneDX MyApp.sln -o sbom.json -j
# 包括开发依赖
dotnet CycloneDX MyApp.sln -o sbom.json -j --include-dev
# 递归为所有项目
dotnet CycloneDX . -o sbom.json -j -r
与构建集成
<!-- 添加到 Directory.Build.props -->
<PropertyGroup>
<GenerateSBOM>true</GenerateSBOM>
<SBOMFormat>CycloneDX</SBOMFormat>
</PropertyGroup>
<!-- MSBuild 目标 -->
<Target Name="GenerateSBOM" AfterTargets="Build" Condition="'$(GenerateSBOM)'=='true'">
<Exec Command="dotnet CycloneDX $(MSBuildProjectFullPath) -o $(OutputPath)sbom.json -j" />
</Target>
程序化生成
using CycloneDX.Models;
public class SbomGenerator
{
public Bom GenerateSbom(Project project, IEnumerable<PackageReference> packages)
{
var bom = new Bom
{
Version = 1,
SerialNumber = $"urn:uuid:{Guid.NewGuid()}",
Metadata = new Metadata
{
Timestamp = DateTime.UtcNow,
Component = new Component
{
Type = Component.Classification.Application,
Name = project.Name,
Version = project.Version
}
},
Components = new List<Component>()
};
foreach (var pkg in packages)
{
bom.Components.Add(new Component
{
Type = Component.Classification.Library,
BomRef = $"pkg:nuget/{pkg.Id}@{pkg.Version}",
Name = pkg.Id,
Version = pkg.Version,
Purl = $"pkg:nuget/{pkg.Id}@{pkg.Version}",
Licenses = pkg.Licenses?.Select(l => new LicenseChoice
{
License = new License { Id = l }
}).ToList()
});
}
return bom;
}
}
漏洞管理
VEX(漏洞可利用性交换)
VEX文档说明漏洞是否适用于您的产品:
{
"bomFormat": "CycloneDX",
"specVersion": "1.5",
"vulnerabilities": [
{
"id": "CVE-2023-12345",
"source": {
"name": "NVD",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2023-12345"
},
"ratings": [
{
"severity": "high",
"score": 7.5,
"method": "CVSSv3"
}
],
"analysis": {
"state": "not_affected",
"justification": "code_not_reachable",
"detail": "易受攻击的代码路径未在我们的实现中使用"
},
"affects": [
{
"ref": "pkg:nuget/SomePackage@1.0.0"
}
]
}
]
}
VEX 状态
| 状态 | 含义 |
|---|---|
exploitable |
漏洞可利用 |
in_triage |
正在调查 |
not_affected |
不受影响 |
resolved |
当前版本已修复 |
漏洞跟踪服务
public class VulnerabilityTracker
{
private readonly IVulnerabilityDatabase _vulnDb;
private readonly ISbomRepository _sbomRepo;
public async Task<VulnerabilityReport> ScanSbom(
string sbomPath,
CancellationToken ct)
{
var sbom = await _sbomRepo.Load(sbomPath, ct);
var report = new VulnerabilityReport
{
SbomSerialNumber = sbom.SerialNumber,
ScanTimestamp = DateTimeOffset.UtcNow
};
foreach (var component in sbom.Components)
{
var vulns = await _vulnDb.GetVulnerabilities(
component.Purl,
ct);
foreach (var vuln in vulns)
{
report.Vulnerabilities.Add(new VulnerabilityFinding
{
ComponentRef = component.BomRef,
ComponentName = component.Name,
ComponentVersion = component.Version,
CveId = vuln.Id,
Severity = vuln.Severity,
CvssScore = vuln.CvssScore,
Description = vuln.Description,
FixedInVersion = vuln.FixedInVersion,
VexStatus = DetermineVexStatus(component, vuln)
});
}
}
return report;
}
private VexStatus DetermineVexStatus(Component component, Vulnerability vuln)
{
// 检查是否存在现有的VEX确定
// 否则标记为 in_triage
return VexStatus.InTriage;
}
}
供应链安全
SLSA(软件工件供应链级别)
| 级别 | 要求 |
|---|---|
| SLSA 1 | 构建过程文档化,生成来源证明 |
| SLSA 2 | 版本控制,托管构建服务 |
| SLSA 3 | 强化构建,验证来源证明 |
| SLSA 4 | 双人审核,密封构建 |
包验证
public class PackageIntegrityVerifier
{
public async Task<VerificationResult> VerifyPackage(
PackageReference package,
CancellationToken ct)
{
var result = new VerificationResult { Package = package };
// 检查包签名
var signature = await GetPackageSignature(package, ct);
if (signature != null)
{
result.IsSigned = true;
result.SignatureValid = await VerifySignature(signature, ct);
result.SignerCertificate = signature.Certificate;
}
// 根据已知良好来源验证哈希
var packageHash = await ComputePackageHash(package, ct);
var expectedHash = await GetExpectedHash(package, ct);
result.HashMatch = packageHash == expectedHash;
// 检查已知漏洞
result.Vulnerabilities = await ScanForVulnerabilities(package, ct);
// 检查包年龄和维护状态
result.LastUpdated = await GetLastUpdateDate(package, ct);
result.IsDeprecated = await CheckDeprecationStatus(package, ct);
return result;
}
}
依赖锁定
<!-- 启用包锁文件以实现可重复构建 -->
<PropertyGroup>
<RestorePackagesWithLockFile>true</RestorePackagesWithLockFile>
<RestoreLockedMode Condition="'$(CI)' == 'true'">true</RestoreLockedMode>
</PropertyGroup>
CI/CD 集成
GitHub Actions SBOM 生成
name: 生成 SBOM
on:
release:
types: [published]
jobs:
sbom:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
- name: 设置 .NET
uses: actions/setup-dotnet@v4
with:
dotnet-version: '10.0.x'
- name: 安装 CycloneDX
run: dotnet tool install --global CycloneDX
- name: 生成 SBOM
run: |
dotnet CycloneDX MySolution.sln \
-o sbom.json \
-j \
--set-version ${{ github.event.release.tag_name }}
- name: 签名 SBOM
run: |
# 使用 cosign 或类似工具签名
cosign sign-blob --key ${{ secrets.SIGNING_KEY }} sbom.json
- name: 上传 SBOM 到发布
uses: actions/upload-release-asset@v1
with:
upload_url: ${{ github.event.release.upload_url }}
asset_path: ./sbom.json
asset_name: sbom.json
asset_content_type: application/json
- name: 扫描漏洞
run: |
grype sbom:sbom.json --fail-on high
SBOM 证明
- name: 生成 SBOM 证明
uses: actions/attest-sbom@v1
with:
subject-path: './bin/MyApp.dll'
sbom-path: './sbom.json'
SBOM 分发
发布位置
| 渠道 | 格式 | 受众 |
|---|---|---|
| 发布资产 | JSON/XML | 开发人员、安全团队 |
| API 端点 | JSON | 自动化系统 |
| 文档 | 人类可读 | 审计员、客户 |
| 容器标签 | 参考 | 容器运行时 |
容器集成
# 在容器中包含 SBOM
LABEL org.opencontainers.image.sbom="sbom.json"
COPY sbom.json /app/sbom.json
# 或在构建时生成
FROM mcr.microsoft.com/dotnet/sdk:10.0 AS build
RUN dotnet tool install --global CycloneDX
RUN dotnet CycloneDX /src/MyApp.csproj -o /app/sbom.json -j
法规要求
美国行政命令 14028
对美国政府销售的软件的要求:
- 所有软件必须提供SBOM
- 必须包括所有组件
- 机器可读格式(SPDX、CycloneDX)
- VEX 用于漏洞状态
- 定期更新
欧盟网络弹性法案
即将实施的要求:
- 所有包含数字元素的产品提供SBOM
- 漏洞处理程序
- 产品生命周期内的安全更新
- 报告被积极利用的漏洞
SBOM 检查清单
生成
- [ ] 包括所有直接依赖
- [ ] 解析传递依赖
- [ ] 准确记录版本
- [ ] 识别许可证
- [ ] 计算哈希
- [ ] 生成PURL
质量
- [ ] 存在NTIA最低元素
- [ ] 机器可读格式
- [ ] 符合架构
- [ ] 准确的依赖图
- [ ] 与实际部署的软件匹配
分发
- [ ] 包含在发布资产中
- [ ] 可通过API获取(如适用)
- [ ] 签名/证明
- [ ] VEX文档可用
- [ ] 客户访问方法文档化
交叉引用
- 许可证合规:
license-compliance用于许可证义务 - 安全:
security-frameworks用于供应链安全 - AI治理:
ai-governance用于ML模型SBOM